Разделение регистрационного кода с объектов С#
В настоящее время у меня есть настраиваемый статический класс журналирования в С#, который можно вызвать со следующим кодом:
EventLogger.Log(EventLogger.EventType.Application, string.Format("AddData request from {0}", ipAddress));
Когда это называется, он просто записывает в определенный файл журнала, указанный в файле конфигурации.
Однако, поскольку мне приходится регистрировать много и много событий, мой код начинает усложняться, потому что все сообщения протоколирования.
Существует ли установленный способ более или менее отдельного кода регистрации из объектов и методов в классе С#, поэтому код не становится неуправляемым?
Спасибо всем за вашу помощь, потому что в последнее время я борется с этим.
Ответы
Ответ 1
Мне нравятся функции AOP, которые предлагает PostSharp. На мой взгляд, Loggin - это аспект любого программного обеспечения. Ведение журнала не является основным значением, которое приложение должно предоставить.
Итак, в моем случае PostSharp всегда был в порядке. Spring.NET также имеет модуль AOP, который можно использовать для достижения этого.
Ответ 2
Наиболее часто используемый метод, который я видел, использует AOP в той или иной форме.
PostSharp - это один продукт, который выполняет преобразование IL в виде AOP, хотя не единственный способ сделать AOP в .NET.
Ответ 3
Решением этого является использование Аспектно-ориентированное программирование, в котором вы можете отделить эти проблемы. Это довольно сложное/инвазивное изменение, поэтому я не уверен, насколько это возможно в вашей ситуации.
Ответ 4
Чтобы сделать код доступным для чтения, зарегистрируйте только то, что вам действительно нужно (информация/предупреждение/ошибка). Отправляйте сообщения об ошибках во время разработки, но удаляйте большинство, когда вы закончите. Для ведения журнала трассировки используйте
AOP для регистрации простых вещей, таких как ввод/выход метода (если вы считаете, что вам нужна такая гранулярность).
Пример:
public int SomeMethod(int arg)
{
Log.Trace("SomeClass.SomeMethod({0}), entering",arg); // A
if (arg < 0)
{
arg = -arg;
Log.Warn("Negative arg {0} was corrected", arg); // B
}
Log.Trace("SomeClass.SomeMethod({0}), returning.",arg); // C
return 2*arg;
}
В этом примере единственным необходимым оператором журнала является B. Операторы журнала A и C являются шаблонами, протоколируются, и вы можете оставить PostSharp для вставки вместо него.
Также: в вашем примере вы можете увидеть, что существует некоторая форма "Action X, вызванная Y", что говорит о том, что большая часть вашего кода может быть перенесена на более высокий уровень (например, Command/Filter).
Ваше распространение заявлений о регистрации может вам что-то сказать: что может использоваться некоторая форма шаблона проектирования, которая также может централизовать большую часть ведения журнала.
void DoSomething(Command command, User user)
{
Log.Info("Command {0} invoked by {1}", command, user);
command.Process(user);
}
Ответ 5
У меня был пользовательский встроенный регистратор, но недавно он был изменен на TracerX. Это обеспечивает простой способ управлять кодом с разной степенью серьезности. Регистраторы могут быть созданы с именами, тесно связанными с классом и т.д., Которые вы работаете с
Он имеет отдельный просмотрщик с множеством возможностей фильтрации, включая журнал, степень серьезности и т.д.
http://tracerx.codeplex.com/
Здесь есть статья: http://www.codeproject.com/KB/dotnet/TracerX.aspx
Ответ 6
Если ваша основная цель состоит в том, чтобы регистрировать точки входа/выхода из функции и случайную информацию между ними, у меня были хорошие результаты с помощью объекта Одноразовый, где конструктор отслеживает запись функции и Dispose() отслеживает выход. Это позволяет вызывающему коду просто обернуть каждый код метода внутри одного с помощью оператора. Также предлагаются методы для произвольных журналов между ними. Вот полный класс отслеживания событий С# ETW, а также оболочка ввода/вывода функций:
using System;
using System.Diagnostics;
using System.Diagnostics.Tracing;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace MyExample
{
// This class traces function entry/exit
// Constructor is used to automatically log function entry.
// Dispose is used to automatically log function exit.
// use "using(FnTraceWrap x = new FnTraceWrap()){ function code }" pattern for function entry/exit tracing
public class FnTraceWrap : IDisposable
{
string methodName;
string className;
private bool _disposed = false;
public FnTraceWrap()
{
StackFrame frame;
MethodBase method;
frame = new StackFrame(1);
method = frame.GetMethod();
this.methodName = method.Name;
this.className = method.DeclaringType.Name;
MyEventSourceClass.Log.TraceEnter(this.className, this.methodName);
}
public void TraceMessage(string format, params object[] args)
{
string message = String.Format(format, args);
MyEventSourceClass.Log.TraceMessage(message);
}
public void Dispose()
{
if (!this._disposed)
{
this._disposed = true;
MyEventSourceClass.Log.TraceExit(this.className, this.methodName);
}
}
}
[EventSource(Name = "MyEventSource")]
sealed class MyEventSourceClass : EventSource
{
// Global singleton instance
public static MyEventSourceClass Log = new MyEventSourceClass();
private MyEventSourceClass()
{
}
[Event(1, Opcode = EventOpcode.Info, Level = EventLevel.Informational)]
public void TraceMessage(string message)
{
WriteEvent(1, message);
}
[Event(2, Message = "{0}({1}) - {2}: {3}", Opcode = EventOpcode.Info, Level = EventLevel.Informational)]
public void TraceCodeLine([CallerFilePath] string filePath = "",
[CallerLineNumber] int line = 0,
[CallerMemberName] string memberName = "", string message = "")
{
WriteEvent(2, filePath, line, memberName, message);
}
// Function-level entry and exit tracing
[Event(3, Message = "Entering {0}.{1}", Opcode = EventOpcode.Start, Level = EventLevel.Informational)]
public void TraceEnter(string className, string methodName)
{
WriteEvent(3, className, methodName);
}
[Event(4, Message = "Exiting {0}.{1}", Opcode = EventOpcode.Stop, Level = EventLevel.Informational)]
public void TraceExit(string className, string methodName)
{
WriteEvent(4, className, methodName);
}
}
}
Используемый код будет выглядеть примерно так:
public void DoWork(string foo)
{
using (FnTraceWrap fnTrace = new FnTraceWrap())
{
fnTrace.TraceMessage("Doing work on {0}.", foo);
/*
code ...
*/
}
}
Ответ 7
Я думаю, что это хорошая возможность реализовать что-то похожее на фильтры в ASP.NET MVC. Это реализуется с помощью атрибутов и отражения. Вы отмечаете каждый метод, который хотите зарегистрировать определенным образом и наслаждайтесь. Я полагаю, что может быть лучший способ сделать это, может быть, с помощью шаблона Observer или что-то еще, но пока я думал об этом, я не мог придумать что-то лучше.
В основном такие проблемы называются сквозными проблемами и могут решаться с помощью АОП.
Я также думаю, что какая-то интересная схема наследования может применяться с логарифмическими сущностями в базе, но я бы пошел на фильтры