Skip to content

Instantly share code, notes, and snippets.

@LeeCampbell
Created October 2, 2012 08:20
Show Gist options
  • Save LeeCampbell/3817281 to your computer and use it in GitHub Desktop.
Save LeeCampbell/3817281 to your computer and use it in GitHub Desktop.
Logging implementation with Rx features
using System;
using System.Diagnostics;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Concurrency;
using Microsoft.Practices.Prism.Logging;
using log4net;
using log4net.Core;
//From ResSharper --> Options --> Code Inspection --> Code Annotations -->Copy default implementation to clipboard
//http://www.jetbrains.com/resharper/webhelp/Code_Analysis__External_Annotations.html
using JetBrains.Annotations;
namespace MyLib
{
public enum LogLevel
{
Verbose,
Trace,
Debug,
Warn,
Info,
Error,
Fatal
}
//TODO: Document interface. -LC
public interface ILogger
{
void Write(LogLevel level, string message, Exception exception);
IDisposable Scope(string name);
}
//Check if I can do some thing smarter with a Func<ILoggerFacade>
public interface ILoggerFactory
{
ILogger GetLogger();
}
public static class LoggerExtentions
{
[StringFormatMethod("message")]
public static void Fatal(this ILogger logger, Exception exception, string message, params object[] args)
{
var formattedMessage = string.Format(message, args);
logger.Write(LogLevel.Fatal, formattedMessage, exception);
}
[StringFormatMethod("message")]
public static void Fatal(this ILogger logger, string message, params object[] args)
{
logger.Fatal(null, message);
}
[StringFormatMethod("message")]
public static void Error(this ILogger logger, Exception exception, string message, params object[] args)
{
var formattedMessage = string.Format(message, args);
logger.Write(LogLevel.Error, formattedMessage, exception);
}
[StringFormatMethod("message")]
public static void Error(this ILogger logger, string message, params object[] args)
{
logger.Error(null, message, args);
}
[StringFormatMethod("message")]
public static void Info(this ILogger logger, Exception exception, string message, params object[] args)
{
var formattedMessage = string.Format(message, args);
logger.Write(LogLevel.Info, formattedMessage, exception);
}
[StringFormatMethod("message")]
public static void Info(this ILogger logger, string message, params object[] args)
{
logger.Info(null, message);
}
[StringFormatMethod("message")]
public static void Warn(this ILogger logger, Exception exception, string message, params object[] args)
{
var formattedMessage = string.Format(message, args);
logger.Write(LogLevel.Warn, formattedMessage, exception);
}
[StringFormatMethod("message")]
public static void Warn(this ILogger logger, string message, params object[] args)
{
logger.Warn(null, message);
}
[StringFormatMethod("message")]
public static void Debug(this ILogger logger, Exception exception, string message, params object[] args)
{
var formattedMessage = string.Format(message, args);
logger.Write(LogLevel.Debug, formattedMessage, exception);
}
[StringFormatMethod("message")]
public static void Debug(this ILogger logger, string message, params object[] args)
{
logger.Trace(null, message);
}
[StringFormatMethod("message")]
public static void Trace(this ILogger logger, Exception exception, string message, params object[] args)
{
var formattedMessage = string.Format(message, args);
logger.Write(LogLevel.Trace, formattedMessage, exception);
}
[StringFormatMethod("message")]
public static void Trace(this ILogger logger, string message, params object[] args)
{
logger.Trace(null, message);
}
[StringFormatMethod("message")]
public static void Verbose(this ILogger logger, Exception exception, string message, params object[] args)
{
var formattedMessage = string.Format(message, args);
logger.Write(LogLevel.Verbose, formattedMessage, exception);
}
[StringFormatMethod("message")]
public static void Verbose(this ILogger logger, string message, params object[] args)
{
logger.Verbose(null, message);
}
public static IObservable<T> Log<T>(this IObservable<T> source, ILogger logger, string name)
{
return Observable.Create<T>(
o =>
{
logger.Trace("{0}.Subscribe()", name);
var disposal = Disposable.Create(() => logger.Trace("{0}.Dispose()", name));
var subscription = source
.Do(
i => logger.Trace("{0}.OnNext({1})", name, i),
ex => logger.Trace("{0}.OnError({1})", name, ex),
() => logger.Trace("{0}.OnCompleted()", name)
)
.Subscribe(o);
return new CompositeDisposable(disposal, subscription);
});
}
public static IObservable<T> Concurrently<T>(this IObservable<T> source, ILogger logger, string name, IScheduler subscribeOn, IScheduler observeOn)
{
return source.Concurrently(logger, name, subscribeOn, observeOn, TimeSpan.FromMilliseconds(50));
}
public static IObservable<T> Concurrently<T>(this IObservable<T> source, ILogger logger, string name, IScheduler subscribeOn, IScheduler observeOn, TimeSpan tollerence)
{
return source
.SubscribeOn(subscribeOn)
.Timestamp(subscribeOn)
.ObserveOn(observeOn)
.Select(ts =>
{
var latency = observeOn.Now - ts.Timestamp;
if (latency > tollerence)
{
logger.Warn("{0} took {1} to be observed", name, latency);
}
return ts.Value;
});
}
}
public sealed class Log4NetLogger : ILogger, ILoggerFacade
{
private readonly ILog _log;
public Log4NetLogger(Type callingType)
{
_log = LogManager.GetLogger(callingType);
}
public void Write(LogLevel level, string message, Exception exception)
{
_log.Logger.Log(null, ToLog4Net(level), message, exception);
}
public IDisposable Scope(string name)
{
//TODO: Add a GUID correlation/context id?
//return log4net.GlobalContext.Stacks["NDC"].Push(name);
//return log4net.ThreadContext.Stacks["NDC"].Push(name);
return log4net.LogicalThreadContext.Stacks["NDC"].Push(name);
//return NDC.Push(name);
}
public void Log(string message, Category category, Priority _)
{
_log.Logger.Log(null, ToLog4Net(category), message, null);
}
private static Level ToLog4Net(Category category)
{
switch (category)
{
case Category.Debug:
return Level.Debug;
case Category.Exception:
return Level.Error;
case Category.Info:
return Level.Info;
case Category.Warn:
return Level.Warn;
default:
throw new ArgumentOutOfRangeException("category");
}
}
private static Level ToLog4Net(LogLevel level)
{
switch (level)
{
case LogLevel.Verbose:
return Level.Verbose;
case LogLevel.Trace:
return Level.Trace;
case LogLevel.Debug:
return Level.Debug;
case LogLevel.Warn:
return Level.Warn;
case LogLevel.Info:
return Level.Info;
case LogLevel.Error:
return Level.Error;
case LogLevel.Fatal:
return Level.Fatal;
default:
throw new ArgumentOutOfRangeException("level");
}
}
}
public class LoggerFactory : ILoggerFactory
{
public ILogger GetLogger()
{
var callersStackFrame = new StackFrame(1);
var callerMethod = callersStackFrame.GetMethod();
var callingType = callerMethod.ReflectedType;
return new Log4NetLogger(callingType);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment