Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Приложения должно содержать достаточно информации для экспертной отладки при возникновении проблем. Ведение журнала является одной из самых важных дополнительных функций в приложении Service Fabric. Если произойдет сбой, хорошие логи позволят вам расследовать его. Анализируя тенденции по записям журнала, вы можете найти пути к улучшению производительности или структуры приложения. Этот документ демонстрирует несколько методов ведения журнала.
EventFlow
Пакет библиотек EventFlow позволяет приложениям определять данные для сбора диагностики и целевые объекты для их вывода. Данные диагностики могут быть любыми, от счетчиков производительности до трассировок действий в приложении. Эти действия выполняются в том же процессе, что и само приложение, что позволяет снизить издержки на взаимодействие. Дополнительные сведения об использовании EventFlow и Service Fabric см. в статье Агрегация событий в Azure Service Fabric с EventFlow.
Использование структурированных событий EventSource
Определив события сообщений для разных вариантов использования, вы сможете собирать пакеты данных о событии в контексте этого события. Имена и значения свойств выбранного события упрощают поиск и фильтрацию данных. Структурирование вывода данных инструментирования упрощает чтение, но требует большего внимания и времени для определения события для каждого случая использования.
Некоторые определения событий могут быть общими для всего приложения. Например, запуск или остановка метода применяются многократно во многих службах в рамках приложения. Специализированная служба, например система обработки заказов, может использовать событие CreateOrder, включающее собственное уникальное событие. Такой подход будет порождать множество событий и может потребовать согласования идентификаторов между командами проектов.
[EventSource(Name = "MyCompany-VotingState-VotingStateService")]
internal sealed class ServiceEventSource : EventSource
{
public static readonly ServiceEventSource Current = new ServiceEventSource();
// The instance constructor is private to enforce singleton semantics.
private ServiceEventSource() : base() { }
...
// The ServiceTypeRegistered event contains a unique identifier, an event attribute that defined the event, and the code implementation of the event.
private const int ServiceTypeRegisteredEventId = 3;
[Event(ServiceTypeRegisteredEventId, Level = EventLevel.Informational, Message = "Service host process {0} registered service type {1}", Keywords = Keywords.ServiceInitialization)]
public void ServiceTypeRegistered(int hostProcessId, string serviceType)
{
WriteEvent(ServiceTypeRegisteredEventId, hostProcessId, serviceType);
}
// The ServiceHostInitializationFailed event contains a unique identifier, an event attribute that defined the event, and the code implementation of the event.
private const int ServiceHostInitializationFailedEventId = 4;
[Event(ServiceHostInitializationFailedEventId, Level = EventLevel.Error, Message = "Service host initialization failed", Keywords = Keywords.ServiceInitialization)]
public void ServiceHostInitializationFailed(string exception)
{
WriteEvent(ServiceHostInitializationFailedEventId, exception);
}
...
Универсальное использование EventSource
Так как определение конкретных событий может вызвать трудности, многие разработчики определяют несколько событий с общим набором параметров, информация о которых обычно выводится в строковом формате. При этом они теряют преимущества структурированности, что усложняет поиск и фильтрацию результатов. При таком подходе обычно определяется небольшое число событий, соответствующих уровням ведения журнала. В приведенном ниже фрагменте кода определяются отладочное сообщение и сообщение об ошибке.
[EventSource(Name = "MyCompany-VotingState-VotingStateService")]
internal sealed class ServiceEventSource : EventSource
{
public static readonly ServiceEventSource Current = new ServiceEventSource();
// The Instance constructor is private, to enforce singleton semantics.
private ServiceEventSource() : base() { }
...
private const int DebugEventId = 10;
[Event(DebugEventId, Level = EventLevel.Verbose, Message = "{0}")]
public void Debug(string msg)
{
WriteEvent(DebugEventId, msg);
}
private const int ErrorEventId = 11;
[Event(ErrorEventId, Level = EventLevel.Error, Message = "Error: {0} - {1}")]
public void Error(string error, string msg)
{
WriteEvent(ErrorEventId, error, msg);
}
...
Хорошие результаты может дать гибридный подход, сочетающий структурированное и универсальное инструментирование. Структурированное инструментирование используется для уведомления об ошибках и метриках. Универсальные события можно использовать для подробного логирования, используемого инженерами для устранения неполадок.
Microsoft.Extensions.Logging
Ведение журнала ASP.NET Core (пакет Microsoft.Extensions.Logging NuGet) — это платформа ведения журнала, которая предоставляет стандартный API для ведения журналов в приложениях. К системе ведения журнала ASP.NET Core можно подключить поддержку других серверных систем для ведения журнала. Этот метод предоставляет вам разнообразную поддержку для процессов аутентификации в приложении, практически не требуя изменений в коде.
Добавьте пакет NuGet Microsoft.Extensions.Logging в проект, который вы хотите инструментировать. Кроме того, добавьте все пакеты поставщиков. Дополнительные сведения см. в разделе Introduction to Logging in ASP.NET Core (Вводные сведения о ведении журналов в ASP.NET Core).
Добавьте в файл службы директиву using для Microsoft.Extensions.Logging.
Определите частную переменную в классе службы.
private ILogger _logger = null;
Добавьте в конструктор класса службы приведенный ниже код.
_logger = new LoggerFactory().CreateLogger<Stateless>();
Запустите инструментирование кода в методах. Вот несколько примеров.
_logger.LogDebug("Debug-level event from Microsoft.Logging"); _logger.LogInformation("Informational-level event from Microsoft.Logging"); // In this variant, we're adding structured properties RequestName and Duration, which have values MyRequest and the duration of the request. // Later in the article, we discuss why this step is useful. _logger.LogInformation("{RequestName} {Duration}", "MyRequest", requestDuration);
Использование других поставщиков ведения журнала
Некоторые сторонние поставщики, например Serilog, NLog и Loggr, используют подход, описанный в предыдущем разделе. Вы можете подключить любой из них к подсистеме ведения журналов ASP.NET Core или использовать их отдельно. Serilog обладает функцией, которая обогащает все сообщения, отправляемые из логгера. Эту функцию можно использовать для вывода информации об имени и типе службы, а также секционировании. Чтобы использовать эту возможность в инфраструктуре ASP.NET Core, сделайте следующее.
Добавьте в проект пакеты NuGet Serilog, Serilog.Extensions.Logging, Serilog.Sinks.Literate и Serilog.Sinks.Observable.
Создайте
LoggerConfiguration
и экземпляр логгера.Log.Logger = new LoggerConfiguration().WriteTo.LiterateConsole().CreateLogger();
Добавьте аргумент
Serilog.ILogger
в конструктор службы и передайте туда недавно созданное средство ведения журнала.ServiceRuntime.RegisterServiceAsync("StatelessType", context => new Stateless(context, Log.Logger)).GetAwaiter().GetResult();
Этот конструктор службы создаёт обогащающие свойства для ServiceTypeName, ServiceName, PartitionId и InstanceId.
public Stateless(StatelessServiceContext context, Serilog.ILogger serilog) : base(context) { PropertyEnricher[] properties = new PropertyEnricher[] { new PropertyEnricher("ServiceTypeName", context.ServiceTypeName), new PropertyEnricher("ServiceName", context.ServiceName), new PropertyEnricher("PartitionId", context.PartitionId), new PropertyEnricher("InstanceId", context.ReplicaOrInstanceId), }; serilog.ForContext(properties); _logger = new LoggerFactory().AddSerilog(serilog.ForContext(properties)).CreateLogger<Stateless>(); }
Инструментируйте код так же, как если бы вы использовали ASP.NET Core без Serilog.
Примечание.
Мы рекомендуем не использовать в предыдущем примере статический аргумент
Log.Logger
. Service Fabric позволяет разместить в одном процессе несколько экземпляров службы одного типа. Если вы примените статический аргументLog.Logger
, последний модуль записи дополнительных свойств будет содержать значения для всех запущенных экземпляров. Это одна из причин, по которой переменная _logger является частным членом класса службы. Кроме того, переменная_logger
должна быть доступна в общем коде, который может использоваться несколькими службами.
Дальнейшие действия
- Узнайте больше о мониторинге приложений в Service Fabric.
- Изучите методы журналирования с использованием EventFlow и Диагностики Windows Azure.