Unique logger inside Post 多个线程使用的 Sharp 属性
Unique logger inside Post Sharp attribute used by multiple threads
我已经实现了 Postsharp
属性,如下所示,下面是使用细节:
- 有
static Func<ILog> GetLogger
或static ThreadLocal<ILog> TestLogger
,它们是从主程序 的方法HelloTask
设置的
- 目标是为调用方法的每个线程创建一个单独的记录器
DoTask
我对设置 static Func
或 static ThreadLocal
非常谨慎,认为这会导致多线程问题(竞争条件或损坏),但是即使调用了 100 个任务,也可以在 Main 方法中看到它工作得很好,所以这是正确的方法吗,哪个更好,我认为 ThreadLocal 更可取
有没有更好的方法来达到同样的效果?
[Serializable]
public class LogExecutionTimeAttribute : OnMethodBoundaryAspect
{
[NonSerialized]
public static Func<ILog> GetLogger;
[NonSerialized]
public static ThreadLocal<ILog> TestLogger;
public LogExecutionTimeAttribute()
{
// Setting AspectPriority explicity avoids undeterministic behaviour
// when multiple aspects are applied, and avoids warning messages
this.AspectPriority = 1;
}
public override void OnEntry(MethodExecutionArgs args)
{
args.MethodExecutionTag = Stopwatch.StartNew();
base.OnEntry(args);
}
public override void OnExit(MethodExecutionArgs args)
{
Stopwatch sw = (Stopwatch)args.MethodExecutionTag;
sw.Stop();
var logger =
#if Func
GetLogger();
#else
TestLogger.Value;
#endif
logger.DebugFormat(
"{0}.{1} for Id={2} executed in {3} seconds.",
this.className,
this.methodName,
args.Arguments[0],
sw.ElapsedMilliseconds / 1000.0);
base.OnExit(args);
}
}
用法如下:
class Program
{
static void Main(string[] args)
{
var taskList = new List<Task>();
for (var counter = 0; counter < 100; counter++)
{
var localCounter = counter;
taskList.Add(Task.Factory.StartNew(() => HelloTask(localCounter + 1), TaskCreationOptions.LongRunning));
}
Task.WaitAll(taskList.ToArray());
}
[LogExecutionTime]
private static void DoTask(int id)
{
#if Func
LogExecutionTimeAttribute.GetLogger().Info(id);
#else
LogExecutionTimeAttribute.TestLogger.Value.Info(id);
#endif
}
private static void HelloTask(int id)
{
var log = new LogFileLogger(id.ToString()).LogInstance;
#if Func
LogExecutionTimeAttribute.GetLogger = () => log;
#else
LogExecutionTimeAttribute.TestLogger = new ThreadLocal<ILog>(() => log);
#endif
var sw = Stopwatch.StartNew();
for (var i = 0; i < 50; i++)
{
DoTask(i);
}
sw.Stop();
#if Func
LogExecutionTimeAttribute.GetLogger().Info("Time :: " + sw.ElapsedMilliseconds);
#else
LogExecutionTimeAttribute.TestLogger.Value.Info("Time :: " + sw.ElapsedMilliseconds);
#endif
}
}
如对 the similar question on Code Review site 的回复中所述:当每个线程都有不同的记录器实例时,您应该将其存储在线程静态或线程本地字段中以避免并发问题。
从设计的角度来看,最好也使方面独立于您创建记录器实例的方式。因此,例如,仅在应用程序启动时分配静态 GetLogger
一次,并将其留给方面消费者来决定是否应为每个线程、每个实例或每个应用程序创建记录器。
[Serializable]
public class LogExecutionTimeAttribute : OnMethodBoundaryAspect
{
public static Func<ILog> GetLogger;
// ...
}
public static class LoggerFactory
{
[ThreadStatic]
public static ILog Logger;
public static ILog GetLogger()
{
return Logger;
}
}
class Program
{
static void Main(string[] args)
{
// Configure factory only once.
LogExecutionTimeAttribute.GetLogger = LoggerFactory.GetLogger;
// ...
}
private static void HelloTask(int id)
{
var log = new LogFileLogger(id.ToString()).LogInstance;
LoggerFactory.Logger = log;
// ...
}
}
您可以从本文档页面的各个方面阅读更多关于使用依赖项的信息:http://doc.postsharp.net/consuming-dependencies
我已经实现了 Postsharp
属性,如下所示,下面是使用细节:
- 有
static Func<ILog> GetLogger
或static ThreadLocal<ILog> TestLogger
,它们是从主程序 的方法 - 目标是为调用方法的每个线程创建一个单独的记录器
DoTask
HelloTask
设置的
我对设置 static Func
或 static ThreadLocal
非常谨慎,认为这会导致多线程问题(竞争条件或损坏),但是即使调用了 100 个任务,也可以在 Main 方法中看到它工作得很好,所以这是正确的方法吗,哪个更好,我认为 ThreadLocal 更可取
有没有更好的方法来达到同样的效果?
[Serializable]
public class LogExecutionTimeAttribute : OnMethodBoundaryAspect
{
[NonSerialized]
public static Func<ILog> GetLogger;
[NonSerialized]
public static ThreadLocal<ILog> TestLogger;
public LogExecutionTimeAttribute()
{
// Setting AspectPriority explicity avoids undeterministic behaviour
// when multiple aspects are applied, and avoids warning messages
this.AspectPriority = 1;
}
public override void OnEntry(MethodExecutionArgs args)
{
args.MethodExecutionTag = Stopwatch.StartNew();
base.OnEntry(args);
}
public override void OnExit(MethodExecutionArgs args)
{
Stopwatch sw = (Stopwatch)args.MethodExecutionTag;
sw.Stop();
var logger =
#if Func
GetLogger();
#else
TestLogger.Value;
#endif
logger.DebugFormat(
"{0}.{1} for Id={2} executed in {3} seconds.",
this.className,
this.methodName,
args.Arguments[0],
sw.ElapsedMilliseconds / 1000.0);
base.OnExit(args);
}
}
用法如下:
class Program
{
static void Main(string[] args)
{
var taskList = new List<Task>();
for (var counter = 0; counter < 100; counter++)
{
var localCounter = counter;
taskList.Add(Task.Factory.StartNew(() => HelloTask(localCounter + 1), TaskCreationOptions.LongRunning));
}
Task.WaitAll(taskList.ToArray());
}
[LogExecutionTime]
private static void DoTask(int id)
{
#if Func
LogExecutionTimeAttribute.GetLogger().Info(id);
#else
LogExecutionTimeAttribute.TestLogger.Value.Info(id);
#endif
}
private static void HelloTask(int id)
{
var log = new LogFileLogger(id.ToString()).LogInstance;
#if Func
LogExecutionTimeAttribute.GetLogger = () => log;
#else
LogExecutionTimeAttribute.TestLogger = new ThreadLocal<ILog>(() => log);
#endif
var sw = Stopwatch.StartNew();
for (var i = 0; i < 50; i++)
{
DoTask(i);
}
sw.Stop();
#if Func
LogExecutionTimeAttribute.GetLogger().Info("Time :: " + sw.ElapsedMilliseconds);
#else
LogExecutionTimeAttribute.TestLogger.Value.Info("Time :: " + sw.ElapsedMilliseconds);
#endif
}
}
如对 the similar question on Code Review site 的回复中所述:当每个线程都有不同的记录器实例时,您应该将其存储在线程静态或线程本地字段中以避免并发问题。
从设计的角度来看,最好也使方面独立于您创建记录器实例的方式。因此,例如,仅在应用程序启动时分配静态 GetLogger
一次,并将其留给方面消费者来决定是否应为每个线程、每个实例或每个应用程序创建记录器。
[Serializable]
public class LogExecutionTimeAttribute : OnMethodBoundaryAspect
{
public static Func<ILog> GetLogger;
// ...
}
public static class LoggerFactory
{
[ThreadStatic]
public static ILog Logger;
public static ILog GetLogger()
{
return Logger;
}
}
class Program
{
static void Main(string[] args)
{
// Configure factory only once.
LogExecutionTimeAttribute.GetLogger = LoggerFactory.GetLogger;
// ...
}
private static void HelloTask(int id)
{
var log = new LogFileLogger(id.ToString()).LogInstance;
LoggerFactory.Logger = log;
// ...
}
}
您可以从本文档页面的各个方面阅读更多关于使用依赖项的信息:http://doc.postsharp.net/consuming-dependencies