Created
October 2, 2012 08:20
-
-
Save LeeCampbell/3817281 to your computer and use it in GitHub Desktop.
Logging implementation with Rx features
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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