I have a fairly large program (C#) that needs its functionality expanded by adding an option to turn off logging. The program takes a directory location as an argument, where it stores the log. I want it to not log anything if args[0] is empty. Right now the program has lines like this nested all over it:
DiagnosticLog.WriteLine("\t\t----Verifying Plugins were installed correctly----");
My first idea was to just create and do a check for a global flag within that function and run that line if it wasn't set. That way I could avoid using the same if statement around each of these lines all over the code. Is there a more clever way of just "turning off" these lines during run-time?
You could implement a version of DiagnosticLog that doesn't actually log anything, and use it in stead of your logging version if you don't want to log. That's assuming you know whether or not you want to log when you create the instance of DiagnosticLog (which I gather from the way you ask, you do).
How about modifying your DiagnosticLog.WriteLine function to take a second parameter doActualLog (bool) which has as default value true? Make some very minor modifications to DiagnoticLog to take this value into account. You can then decide at instantiation of DiagnosticLog if you want actual logging to happen or not.
You could just add an enabled flag to DiagnosticLog that is true by default. If args[0] is empty, call DiagnosticLog.Disable() to set it to false. Then in WriteLine and any other logging functions, check enabled before doing the actual logging.
Why don't you just call a log function that checks to see if the arg is empty?
public void WriteLine(string log) {
if (!firstArgIsEmpty) {
// Print to file.
}
}
How about using a System.Diagnostics.TraceListener class in conjunction with a System.Diagnostics.TraceSwitch? The functionality you seem to be after is already baked in.
You could create a property
public bool Log { get; set; }
string logFilePath;
public string LogFilePath
{
get { return logFilePath; }
set
{
logFilePath = ValidateLogFilePath(value);
Log = logFilePath.Length > 0;
}
}
public void WriteLine(string line)
{
if (!Log)
return;
//...
}
If you make a boolean property to indicate whether logging is occuring, then you could also use it to skip other sections of code that are not necessary if logging is not occuring. This could be useful if you are building any long strings just for logging purposes.
if (DiagnosticLog.Log)
{
DiagnosticLog.WriteLine("The following plugins were not installed:\r\n\t" +
string.Join("\r\n\t", GetMissingPluginNames()));
}
Related
I'm currently writing a custom logging method for my Web API where users can purchase items. This log method will log all the steps the users takes while following a purchase process so support can later track the steps. There are multiple steps like:
Creating a order
Updating a order
Purchasing a item
Receiving status
etc..
This method will return one 'Event' object where all the necessary log information is combined, for example the LogLevel, Message, UserId and more, and write this to a database.
Before i can reach this point, i have to create the very useful log message. The message is based on these two enums (explanation is a bit simplified):
ActionName - At which step in my process is this log event called
ActionOrigin - Is the recorded log event from my front end or backend system...
It is also based on a object where the necessary log values, like order id for example, are provided.
The log class where the log event method is defined is a scoped injected class so i can log events every where critical in my code.
The first thing that came into my mind was creating a switch statement and create the messages based on the correct case. But this would combine 2 switch statements and quickly started to look like a mess.
I did some research and found the strategy pattern. I'm not completely sure if this can help me? Are there any other ideas or examples?
Whenever you are working on an object model and find yourself writing a ton of switch statements, it usually means you've put the class-specific logic in the wrong place. You should put it with the class itself, not the class that consumes it.
To put it another way, your logger should not know how to log each and every type of event. That would be a maintenance nightmare. Instead, it should know how to log a common object (e.g. a string), and each event should itself know how to create that common object, via a common method that the logger knows about. That is the only thing it needs to know.
Here is a simple example. In this case, the logger accepts any type of LoggableEvent and calls its Serialize() method to figure out how it gets added to the common log. The event itself is responsible for knowing how to serialize itself.
abstract class LoggableEventBase
{
public string ActionName { get; }
public string ActionOrigin { get; }
public LoggableEventBase(string actionName, string actionOrigin)
{
ActionName = actionName;
ActionOrigin = actionOrigin;
}
public virtual string Serialize()
{
return string.Format("{0} {1}", ActionName, ActionOrigin);
}
}
class CreateOrderEvent : LoggableEventBase
{
protected readonly List<Item> _items;
protected readonly int _orderId;
public CreateOrderEvent(string origin, int orderID, List<Item> items) : base("CreateOrder", origin)
{
_orderId = orderID;
_items = items;
}
public override string Serialize()
{
return base.Serialize() + string.Format(" {0} {1}", _orderId, string.Join(",", _items.Select(item => item.SKU)));
}
}
Now the actual logging logic is rather simple-- no switch statements or anything else that needs to know what the event is:
class Logger : ILogger
{
public void Log(LoggableEventBase eventToLog)
{
Write(eventToLog.Serialize());
}
protected virtual void Write(string message)
{
//Write the message to a log file
}
}
To add additional event types, you just need to define the new class (and override Serialize()). You never have to go back and modify the Logger class. This is more consistent with the Open-Closed Principle than your existing solution.
This is a design pattern question. You might want to read on different patterns used for the language/framework you are using. It seems like you are trying to avoid writing your logs in line. One way of doing it would be to define the format for your different messages in a constant and use string interpolation (or simple concatenation) to build the message with a log() method.
Example (I'll do my best to write proper C#, please edit any mistakes or inadequacies):
class Logger {
// If you want personalized messages for different actions or origins, define their template constants and create different methods for building them.
public const string ORDER_PROGRESS_MSG_TMPL = "Action:{0}, Origin:{1}, OrderId:{3}";
void log_order_progress(string actionName, sting actionOrigin, string orderId){
Console.WriteLine(
ORDER_PROGRESS_MSG_TMPL, actionName, actionOrigin, orderId
);
}
}
Order
class Order {
...
void create(int orederId){
Logger.log_order_progress(ActionEnum.CREATING, OriginEnum.BACK_END, orderId)
// Do some stuff here to create order
Logger.log_order_progress(ActionEnum.UPDATING, OriginEnum.BACK_END, orderId)
// etc
}
}
This is a way of doing it, you could modularize it more by having templates in their own class. Also you could create (or better: use an existing logging framework) to differentiate level of logging (debug, info, error) as #Sandeep Sharma described.
You can create multiple methods in your Logger class, each for specific scenario.
The methods can be :
info() = for logging some information.
debug() = for debugging.
error() = for logging an error event.
Let's say you want to log an event of purchasing an item , and when user does buy action, you can pass information to the logger.info() method.
If you encounter an error, or a certain action or condition was not fulfilled , you can pass data to the method error() , which will log error in your case.
For messages :
1. Action Name - You can pass the method name or route path that was called by action of an user.
2. Action Origin - Provide details like user name , full path , action type etc.
You can also maintain fields like 'timestamp' and some 'unique-identifier' for better logging of events.
I have a C# project. Is it possible to write code to the effect that "If an exception should occur while executing thus and such a task (and debugger is available), please break immediately, without unwinding the call stack."
Also, I just want to say, if this isn't possible, I'm fine with an answer to that effect.
You should take a look at the System.Diagnostics.Debugger class (https://msdn.microsoft.com/en-us/library/system.diagnostics.debugger(v=vs.110).aspx)
Using this class you can check to see if the debugger is attached and if it is you can break.
You could also wrap this in a static method on a utility class so you can use it easily
public static class DebuggerHelpers
{
[Conditional("DEBUG")]
public static void BreakIfDebugging()
{
if (System.Diagnostics.Debugger.IsAttached)
{
System.Diagnostics.Debugger.Break()
}
}
}
The Conditional attribute (https://msdn.microsoft.com/en-us/library/system.diagnostics.conditionalattribute(v=vs.110).aspx) will cause all calls to this method to be omitted when the DEBUG is not defined (AKA Release).
If you want to leave the point where the exception was thrown and yet retain the call stack, you can do it only through logging the StackTrace AFAIK.
public static class Logger
{
...
public static string CurrentStackDefaultLog()
{
// the true value is used to include source file info
var l_CurrentStack = new System.Diagnostics.StackTrace(true);
return l_CurrentStack.ToString();
}
...
}
A good link for implementing this code is given in https://www.codeproject.com/Articles/223611/How-to-log-the-current-call-stack-in-NET by Daniele Mazzeranghi
Based on the other answers, it seems the answer to my question is that it can't be done.
I had this situation not sure how to best handle this. Input would be appreciated. Imagine I Have such method:
void loaddata()
{
try
{
// EXTRA: I also want to skip below SaveSomething if there was exeption
// last time I called DecryptAndloadXMLdata. This may happen
// if user calls loaddata twice. This is exaclty similar situation
// as app quitting just it happens is user calls loaddata twice
// and during first call there was exception say with DecryptAndloadXMLdata
Savesomething(listOfObjects, xmlPath);//save old data first
xmlPath = newValue;
// some operations
xmlDoc = DecryptAndloadXMLdata(xmlPath);
// some other operations- populate List with data from above XML file
listOfObjects.Add(objectFromXML);
// Here also possibly modify contents of listOfObjects elements
}
catch(Exception ex)
{
xlmPath="";
}
}
Now the thing is when app is quiting I have such feature
to automatically save the List object populated in above
method to a file. Like:
void whenAppisQuitting()
{
Savesomething(listOfObjects, xmlPath);
}
But the problem is. Imagine xmlDoc = loadXMLdata(); throws in above method. What will happen is the List I mentioned won't be populated and when app is quitting empty elements (e.g. empty listOfObjects) will be written to xmlPath - thus damaging my original file because there was unrelated exception say due to encryption in loadXMLData method.
I hope I have made my issue clear. What is the way to deal with such situations? For example what I did you can see I set xmlPath to empty in catch - thus in case of any exception I considered data was not loaded successfully - hence now on application exit I can be calm because nothing will be written to file because its xmlPath ="". Is it reasonable way to solve this issue?
Getting bit confused because this kind of issues now raise error handling to different level - I need to account for all possible kind of failures?
What is the way to deal with such situations?
I would set a flag indicating there was an error when parsing. Setting the path to string.Empty can lead to confusion (IMO). Perhaps an empty string could be a possible value bring passed to your method.
catch(Exception ex)
{
// Log
IsParsingSuccessful = false;
}
And look upon that flag when you want to write:
void AppIsQuitting()
{
if (IsParsingSuccessful)
{
SaveSomething(listOfObjects, xmlPath);
}
}
As a general guidance, you probably should never overwrite files without explicit intent from the user.
As for your error handling, use a simple flag / boolean to indicate valid behavior. Only set that flag to true after everything is processed and only if that flag is true, save the contents to the file.
Does anyone know if it's possible to cancel output caching in code? What I mean is if I place output caching on a child action as follows can I then based on a condition cancel that caching from inside the child action?
[ChildActionOnly]
[OutputCache(Duration = 36000, VaryByParam="tagslug")]
public virtual ActionResult MostViewed(string tagslug, int count)
{
// Make an API call here. If not data returned do not cache the ChildAction as specified above
}
Skimming the framework source it looks like the only logic is don't-cache-on-exception:
// Only cache output if this wasn't an error
if (!wasException) {
ChildActionCacheInternal.Add(uniqueId, capturedText,
DateTimeOffset.UtcNow.AddSeconds(Duration));
}
I can't see a brilliant way to solve this: I think you'll have to make your own custom OutputCachingAttribute based on the original source from the ASP.NET MVC source from CodePlex, and then either add an extra check to that line for the output returned e.g.
if (!(wasException || capturedText.Contains("results:0"))) {
or similar, or find a way to pass that code a flag to this from your controller. The existing code uses an object to store a value on the session; you could copy this, e.g.
define a new static object key the same as _childActionFilterFinishCallbackKey e.g. _noCacheResultKey
add a public static method to the attribute that you can call e.g.
public static void FlagNoCache(HttpContext httpContext) {
httpContext.Items[_noCacheResultKey] = true;
}
extend ClearChildActionFilterFinishCallback to remove this from .Items[] as well as the callback
extend the above test to check this too e.g.
if (!(wasException
|| filterContext.HttpContext.Items.ContainsKey(_noCacheResultKey))) {
from your controller call MyOutputCacheAttribute.FlagNoCache(Context); as necessary.
It may also be possible to throw an exception from your code and then catch it in a different IExceptionFilter so that it doesn't get passed up beyond the OutputCacheAttribute but I don't know how sorry.
In my custom data flow component, I have overriden the OnOutputPathAttached method. I want outputs to be attached under certain conditions. ie:
public override void OnOutputPathAttached(int outputID)
{
if (/*condition*/)
{
//do some processing
base.OnOutputPathAttached(outputID);
}
else
{
System.Windows.Forms.MessageBox.Show("Error message");
//CODE TO STOP OUTPUT FROM BEING ATTACHED???
}
}
What should I put so that the output isn't attached? For now it shows the error message but still attaches the output.
I suspect that it's too late to stop the user from attaching a path by the time your OnOutputPathAttached method is called. (At least, that's how I'm reading the MSDN page on the AttachPathAndPropagateNotifications method.)
Your best bet seems to be to return VS_ISBROKEN from your Validate method, along with raising useful OnError events.