Lägga till loggning för ditt Service Fabric-program
Ditt program måste tillhandahålla tillräckligt med information för att felsöka den när problem uppstår. Loggning är en av de viktigaste sakerna du kan lägga till i ditt Service Fabric-program. När ett fel inträffar kan bra loggning ge dig ett sätt att undersöka fel. Genom att analysera loggmönster kan du hitta sätt att förbättra programmets prestanda eller design. Det här dokumentet visar några olika loggningsalternativ.
EventFlow
Med EventFlow-bibliotekssviten kan program definiera vilka diagnostikdata som ska samlas in och var de ska matas ut. Diagnostikdata kan vara allt från prestandaräknare till programspårningar. Den körs i samma process som programmet, så kommunikationskostnaderna minimeras. Mer information om EventFlow och Service Fabric finns i Azure Service Fabric Event Aggregation med EventFlow.
Använda strukturerade EventSource-händelser
Genom att definiera meddelandehändelser efter användningsfall kan du paketera data om händelsen i samband med händelsen. Du kan enklare söka och filtrera baserat på namnen eller värdena för de angivna händelseegenskaperna. Genom att strukturera instrumentationsutdata blir det lättare att läsa, men det krävs mer eftertanke och tid för att definiera en händelse för varje användningsfall.
Vissa händelsedefinitioner kan delas i hela programmet. Till exempel återanvänds en metodstart- eller stopphändelse för många tjänster i ett program. En domänspecifik tjänst, till exempel ett ordersystem, kan ha en CreateOrder-händelse som har en egen unik händelse. Den här metoden kan generera många händelser och potentiellt kräva samordning av identifierare mellan projektteam.
[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);
}
...
Använda EventSource allmänt
Eftersom det kan vara svårt att definiera specifika händelser definierar många några händelser med en gemensam uppsättning parametrar som vanligtvis matar ut sin information som en sträng. Mycket av den strukturerade aspekten går förlorad och det är svårare att söka efter och filtrera resultaten. I den här metoden definieras några händelser som vanligtvis motsvarar loggningsnivåerna. Följande kodfragment definierar ett felsöknings- och felmeddelande:
[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);
}
...
Att använda en hybrid av strukturerade och generiska instrumentation kan också fungera bra. Strukturerad instrumentering används för att rapportera fel och mått. Allmänna händelser kan användas för detaljerad loggning som används av tekniker för felsökning.
Microsoft.Extensions.Logging
ASP.NET Core-loggning (Microsoft.Extensions.Logging NuGet-paketet) är ett loggningsramverk som tillhandahåller ett standardloggnings-API för ditt program. Stöd för andra loggningsserverdelar kan anslutas till ASP.NET Core-loggning. Detta ger dig en mängd olika stöd för loggning i ditt program bearbetas, utan att behöva ändra mycket kod.
Lägg till NuGet-paketet Microsoft.Extensions.Logging i det projekt som du vill instrumentera. Lägg också till eventuella providerpaket. Mer information finns i Loggning i ASP.NET Core.
Lägg till ett användningsdirektiv för Microsoft.Extensions.Logging i tjänstfilen.
Definiera en privat variabel i tjänstklassen.
private ILogger _logger = null;
Lägg till den här koden i konstruktorn för din tjänstklass:
_logger = new LoggerFactory().CreateLogger<Stateless>();
Börja instrumentera koden i dina metoder. Här följer några exempel:
_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);
Använda andra loggningsprovidrar
Vissa tredjepartsleverantörer använder den metod som beskrivs i föregående avsnitt, inklusive Serilog, NLog och Loggr. Du kan ansluta var och en av dessa till ASP.NET Core-loggning, eller så kan du använda dem separat. Serilog har en funktion som berikar alla meddelanden som skickas från en loggare. Den här funktionen kan vara användbar för att mata ut tjänstnamn, typ och partitionsinformation. Gör följande för att använda den här funktionen i ASP.NET Core-infrastrukturen:
Lägg till paketen Serilog, Serilog.Extensions.Logging, Serilog.Sinks.Literate och Serilog.Sinks.Observable NuGet i projektet.
Skapa en
LoggerConfiguration
och loggningsinstansen.Log.Logger = new LoggerConfiguration().WriteTo.LiterateConsole().CreateLogger();
Lägg till ett
Serilog.ILogger
argument i tjänstkonstruktorn och skicka den nyligen skapade loggaren.ServiceRuntime.RegisterServiceAsync("StatelessType", context => new Stateless(context, Log.Logger)).GetAwaiter().GetResult();
I tjänstkonstruktorn skapar du egenskapsberikare för ServiceTypeName, ServiceName, PartitionId och 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>(); }
Instrumentera koden på samma sätt som om du använde ASP.NET Core utan Serilog.
Kommentar
Vi rekommenderar att du inte använder statiska
Log.Logger
med föregående exempel. Service Fabric kan vara värd för flera instanser av samma tjänsttyp i en enda process. Om du använder den statiskaLog.Logger
visar den sista skrivaren för egenskapsberikarna värden för alla instanser som körs. Det här är en orsak till att variabeln _logger är en privat medlemsvariabel för tjänstklassen. Du måste också göra den_logger
tillgänglig för gemensam kod, som kan användas mellan olika tjänster.
Nästa steg
- Läs mer om programövervakning i Service Fabric.
- Läs mer om loggning med EventFlow och Windows Azure Diagnostics.