2

I want to set up a debug flag such that would replace "Console".Writeline with "Log".WriteLine. I don't want to write

if (debug)
    Log.writeline("log");
else 
    Console.Writeline("log"); every time I want to log info.

Something like INFO.Writelline("log"); where INFO could be replaced by "Log" or "Console" depending a global variable set.
Would have used conditional Macro but C# does not support that. Please let me know if I am missing something.

Flat Eric
  • 7,971
  • 9
  • 36
  • 45
Ronak Agrawal
  • 1,006
  • 1
  • 19
  • 48
  • 1
    Would it be possible for you to create a static method that abstracts the branching logic that you could use. For example: _public static void DebugLog(string log) { if (debug) Log.writeline(log); else Console.WriteLine(log); }_ – Ideae Aug 13 '14 at 18:47
  • 1
    Why can't you use normal `Trace` functionality that let you do almost exactly that (in addition to be configurable at run time via config files)? – Alexei Levenkov Aug 13 '14 at 18:49
  • "Would have used conditional Macro but C# does not support that" -- What gives you that idea? C# predefined symbols may not be as powerful as C's macros, but a simple `#if` is possible. –  Aug 13 '14 at 18:51
  • Would running C++ preprocessor on our source first work for you (I'd not do it for any new code, but may be acceptable workaround while code is refactored...) – Alexei Levenkov Aug 13 '14 at 18:51
  • @hvd - can you give an example ( OP seem to be talking about multiple versions of `#define LOG(xxx) Log.WriteLine(xxx)` - not sure how one would do it in C# alone). – Alexei Levenkov Aug 13 '14 at 18:53
  • @AlexeiLevenkov It's a simple matter of putting the `#if` inside a function, and calling that function every time, as far as I can tell. But after re-reading, I see that I misunderstood part of the OP's question, and because of that, I can see that what I was trying to say wasn't clear at all. –  Aug 13 '14 at 18:56
  • @Ideae: Yeah, that can be done. Thanks. – Ronak Agrawal Aug 14 '14 at 06:44
  • 3
    @ALexei: Thanks for input.But that would involve additional argument of object. Need to pass only the message. – Ronak Agrawal Aug 14 '14 at 06:47
  • @hvd: Yeah,that's what I am using now. Thanks – Ronak Agrawal Aug 14 '14 at 06:48

4 Answers4

3

Have you tried something like this:

 #if (DEBUG)
      Log.writeline("log");
 #else
     Console.Writeline("log");
 #endif
  • Note that it is almost exactly what OP said as " I don't want to write `if (...)`. Still multiple lines of code per on trace line - not really solution. – Alexei Levenkov Aug 13 '14 at 18:55
3

Something like this?

#define MY_DEBUG //Note: this must be the first line in the file

public static class INFO
{
    public static void WriteLine(string message)
    {
         #if (MY_DEBUG)
             Log.writeline(message);
         #else
             Console.Writeline(message);
         #endif
    }
}

And you would just call

INFO.WriteLine("log message");
mclaassen
  • 5,018
  • 4
  • 30
  • 52
  • Does *exactly* what OP asked for, +1, including the equivalent "conditional macro" that wasn't known about. – Steve Aug 13 '14 at 19:10
3

Not directly answering your question. But you could add your own interface ILog and avoid if(debug) conditions everywhere..

public interface ILog
{
    void WriteLine(string message);
}

Then implement it like

public class LogImpl : ILog
{
    public void WriteLine(string message)
    {
        Log.WriteLine(...);
    }
}

public class DebugImpl : ILog
{
    public void WriteLine(string message)
    {
        Debug.WriteLine(...);
    }
}

Then for your convenience, you could have a static class which provides this instance.

public static class Logger
{
    public static ILog Instance = new DebugImpl();//Or LogImpl 
}

Then you could just say

Logger.Instance.WriteLine(...);

Advantage is you can switch between different implementations at runtime. Say Debug, Console, File, Database and so forth.

Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
  • How would you switch implementation at *runtime*? – Christian Phillips Aug 13 '14 at 19:11
  • @christiandev Isn't that simply `Logger.Instance = new OtherILogImpl()`? When you want to switch, just set it to new instance. – Sriram Sakthivel Aug 13 '14 at 19:12
  • I know it could be done at design time, but I'm not sure how this is achieved at runtime? – Christian Phillips Aug 13 '14 at 19:14
  • @christiandev I don't get it. What stops you from doing it runtime? At any point of time you can change the instance by `Logger.Instance = new ILogImpl();` It is just a field or property which you can set anytime. Then it will behave differently from that time onwards. – Sriram Sakthivel Aug 13 '14 at 19:18
  • I mean in the context that your application is running on a server for example; or are you suggesting when you run the application locally, then stop the application, change the *implementation*, restart the application? – Christian Phillips Aug 13 '14 at 19:24
  • @christiandev Yes, I mean without restarting the application. This code should make you understand what I mean `void Main() { Logger.Instance = new DebugImpl(); Logger.Instance.WriteLine("Written in Debug"); //Some more code Logger.Instance = new DatabaseImpl(); Logger.Instance.WriteLine("Written in Database"); }` Does that makes it clear for you ? – Sriram Sakthivel Aug 13 '14 at 19:28
  • Yes, the code makes perfect sense; but it still doesn't get the user away from having some code decide which to use depending on a condition. I thought you were suggesting that it could be switched at run time with a library like MEF for example, where a new implementation could be introduced on the fly... – Christian Phillips Aug 13 '14 at 19:48
2

You could use a library like Log4Net and set up different appenders, one for console and one for logging to file/sql server etc.

<log4net>
    <appender name="FileAppender" type="log4net.Appender.FileAppender">
        <file value="log-file-1.txt" />
        <appendToFile value="true" />
        <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%date %message%newline" />
        </layout>
    </appender>
    <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
    <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
    </layout>
</appender>

    <root>
        <level value="DEBUG" />
        <appender-ref ref="FileAppender" />
        <appender-ref ref="ConsoleAppender" />
    </root>
</log4net>

By doing this, you will see it logging to Console when running locally and it will also log to file when running in production, and this will be done from the same line...

log.info(...);
Christian Phillips
  • 18,399
  • 8
  • 53
  • 82