Dela via


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 det när problem uppstår. Loggning är en av de viktigaste sakerna du kan lägga till i Service Fabric-programmet. 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 Händelseaggregering i Azure Service Fabric 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å namn eller värden för de angivna händelseegenskaperna. Genom att strukturera instrumentationsutdata blir det enklare 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. En start- eller stopphändelse för en metod skulle till exempel återanvändas 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 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 rapportering av 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.

  1. 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 Logga in ASP.NET Core.

  2. Lägg till ett användningsdirektiv för Microsoft.Extensions.Logging i tjänstfilen.

  3. Definiera en privat variabel i din tjänstklass.

    private ILogger _logger = null;
    
  4. Lägg till den här koden i konstruktorn för din tjänstklass:

    _logger = new LoggerFactory().CreateLogger<Stateless>();
    
  5. Börja instrumentera koden i dina metoder. Här är 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 infrastruktur:

  1. Lägg till paketen Serilog, Serilog.Extensions.Logging, Serilog.Sinks.Literate och Serilog.Sinks.Observable NuGet i projektet.

  2. Skapa en LoggerConfiguration och loggningsinstansen.

    Log.Logger = new LoggerConfiguration().WriteTo.LiterateConsole().CreateLogger();
    
  3. Lägg till ett Serilog.ILogger argument i tjänstkonstruktorn och skicka den nyligen skapade loggern.

    ServiceRuntime.RegisterServiceAsync("StatelessType", context => new Stateless(context, Log.Logger)).GetAwaiter().GetResult();
    
  4. 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>();
    }
    
  5. Instrumentera koden på samma sätt som om du använde ASP.NET Core utan Serilog.

    Anteckning

    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 statiska Log.Loggervisar den sista skrivaren av egenskapsberikarna värden för alla instanser som körs. Det här är en anledning till att variabeln _logger är en privat medlemsvariabel för tjänstklassen. Dessutom måste du göra den _logger tillgänglig för gemensam kod, som kan användas i olika tjänster.

Nästa steg