Generazione di eventi e log a livello di applicazione e servizioApplication and service level event and log generation

Strumentazione del codice con eventi personalizzatiInstrumenting the code with custom events

La strumentazione del codice è la base di molti altri aspetti di monitoraggio dei servizi.Instrumenting the code is the basis for most other aspects of monitoring your services. La strumentazione è l'unico modo per rilevare eventuali problemi e individuare le correzioni necessarie.Instrumentation is the only way you can know that something is wrong, and to diagnose what needs to be fixed. Anche se è tecnicamente possibile connettere un debugger a un servizio di produzione, questa non è una procedura comune.Although technically it's possible to connect a debugger to a production service, it's not a common practice. I dati dettagliati di strumentazione sono quindi importanti.So, having detailed instrumentation data is important.

Alcuni prodotti instrumentano automaticamente il codice.Some products automatically instrument your code. Benché queste soluzioni siano efficaci, è quasi sempre necessaria una strumentazione manuale.Although these solutions can work well, manual instrumentation is almost always required. Alla fine, è necessario disporre di informazioni sufficienti per eseguire un debug accurato dell'applicazione.In the end, you must have enough information to forensically debug the application. Questo documento illustra diversi approcci alla strumentazione del codice e indicano quando è consigliabile scegliere un approccio rispetto a un altro.This document describes different approaches to instrumenting your code, and when to choose one approach over another.

EventSourceEventSource

Quando si crea una soluzione di Azure Service Fabric da un modello in Visual Studio, viene generata una classe derivata da EventSource (ServiceEventSource o ActorEventSource).When you create a Service Fabric solution from a template in Visual Studio, an EventSource-derived class (ServiceEventSource or ActorEventSource) is generated. Viene creato un modello in cui è possibile aggiungere eventi per l'applicazione o il servizio.A template is created, in which you can add events for your application or service. Il nome di EventSource deve essere univoco e deve essere rinominato dalla stringa del modello predefinito MyCompany-<soluzione>-<progetto>.The EventSource name must be unique, and should be renamed from the default template string MyCompany-<solution>-<project>. Se esistono più definizioni di EventSource con lo stesso nome, potranno verificarsi errori di runtime.Having multiple EventSource definitions that use the same name causes an issue at run time. Ogni evento definito deve avere un identificatore univoco.Each defined event must have a unique identifier. Se un identificatore non è univoco, si verificherà un errore di runtime.If an identifier is not unique, a runtime failure occurs. Alcune organizzazioni preassegnano intervalli di valori per gli identificatori, in modo da evitare conflitti tra team di sviluppo separati.Some organizations preassign ranges of values for identifiers to avoid conflicts between separate development teams. Per altre informazioni, vedere il blog di Vance o la documentazione di MSDN.For more information, see Vance's blog or the MSDN documentation.

Uso di eventi EventSource strutturatiUsing structured EventSource events

Ogni evento negli esempi di codice di questa sezione è definito per un caso specifico, ad esempio, quando viene registrato un tipo di servizio.Each of the events in the code examples in this section are defined for a specific case, for example, when a service type is registered. Quando si definiscono i messaggi in base al caso di utilizzo, è possibile creare pacchetti dei dati e con il testo dell'errore, quindi eseguire ricerche e applicare filtri con maggiore facilità in base ai nomi o ai valori delle proprietà specificate.When you define messages by use case, data can be packaged with the text of the error, and you can more easily search and filter based on the names or values of the specified properties. Strutturando l'output della strumentazione è possibile usarlo con più facilità, ma ciò richiede sforzi maggiori per definire un nuovo evento per ciascun caso d'uso.Structuring the instrumentation output makes it easier to consume, but requires more thought and time to define a new event for each use case. Alcune definizioni di evento possono essere condivise nell'intera applicazione.Some event definitions can be shared across the entire application. Un evento di avvio o arresto di un metodo, ad esempio, può essere riutilizzato in molti servizi in un'applicazione.For example, a method start or stop event would be reused across many services within an application. Un servizio specifico per un dominio, ad esempio un sistema di ordine, può avere un evento CreateOrder, che ha un proprio evento univoco.A domain-specific service, like an order system, might have a CreateOrder event, which has its own unique event. Questo approccio può generare un numero elevato di eventi e può potenzialmente richiedere il coordinamento degli identificatori tra i team di progetto.This approach might generate many events, and potentially require coordination of identifiers across project teams.

    [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);
        }

Uso generico di EventSourceUsing EventSource generically

Poiché può essere difficile definire eventi specifici, molti utenti ne definiscono pochi con un set di parametri in comune che generalmente genera le informazioni sotto forma di stringa.Because defining specific events can be difficult, many people define a few events with a common set of parameters that generally output their information as a string. Gran parte dell'aspetto strutturato viene persa, rendendo più difficili le ricerche e i filtri dei risultati.Much of the structured aspect is lost, and it's more difficult to search and filter the results. In questo approccio vengono definiti alcuni eventi, in genere corrispondenti ai livelli di registrazione.In this approach, a few events that usually correspond to the logging levels are defined. Il frammento seguente definisce un messaggio di debug e di errore:The following snippet defines a debug and error message:

    [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);
        }

Anche un ibrido di strumentazione strutturata e generica può essere una soluzione ideale.Using a hybrid of structured and generic instrumentation also can work well. La strumentazione strutturata viene usata per la segnalazione degli errori e per le metriche.Structured instrumentation is used for reporting errors and metrics. Gli eventi generici possono essere usati per la registrazione dettagliata utilizzata dai tecnici per la risoluzione dei problemi.Generic events can be used for the detailed logging that is consumed by engineers for troubleshooting.

Registrazione di ASP.NET CoreASP.NET Core logging

È importante pianificare con attenzione la strumentazione del codice.It's important to carefully plan how you will instrument your code. Il piano di strumentazione corretto può consentire di evitare la potenziale destabilizzazione della codebase e la conseguente necessità di ripetere la strumentazione del codice.The right instrumentation plan can help you avoid potentially destabilizing your code base, and then needing to reinstrument the code. Per ridurre il rischio, è possibile scegliere una libreria di strumentazione come Microsoft.Extensions.Logging, inclusa in Microsoft ASP.NET Core.To reduce risk, you can choose an instrumentation library like Microsoft.Extensions.Logging, which is part of Microsoft ASP.NET Core. ASP.NET Core ha un'interfaccia ILogger che può essere usata con il provider preferito, riducendo al minimo l'effetto sul codice esistente.ASP.NET Core has an ILogger interface that you can use with the provider of your choice, while minimizing the effect on existing code. È possibile usare il codice in ASP.NET Core in Windows e Linux e in .NET Framework completo, in modo da standardizzare la strumentazione del codice.You can use the code in ASP.NET Core on Windows and Linux, and in the full .NET Framework, so your instrumentation code is standardized. Ciò viene approfondito di seguito:This is further explored below:

Uso di Microsoft.Extensions.Logging in Service FabricUsing Microsoft.Extensions.Logging in Service Fabric

  1. Aggiungere il pacchetto Microsoft.Extensions.Logging NuGet al progetto da strumentare.Add the Microsoft.Extensions.Logging NuGet package to the project you want to instrument. Aggiungere anche eventuali pacchetti del provider. Per un pacchetto di terze parti, vedere l'esempio seguente.Also, add any provider packages (for a third-party package, see the following example). Per altre informazioni, vedere Logging in ASP.NET Core (Registrazione in ASP.NET Core).For more information, see Logging in ASP.NET Core.
  2. Aggiungere una direttiva using per Microsoft.Extensions.Logging al file del servizio.Add a using directive for Microsoft.Extensions.Logging to your service file.
  3. Definire una variabile privata all'interno della classe di servizio.Define a private variable within your service class.

    private ILogger _logger = null;
    
  4. Nel costruttore della classe del servizio aggiungere il codice seguente:In the constructor of your service class, add this code:

    _logger = new LoggerFactory().CreateLogger<Stateless>();
    
  5. Avviare la strumentazione del codice nei metodi.Start instrumenting your code in your methods. Ecco alcuni esempi:Here are a few samples:

    _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);
    

Uso di altri provider di registrazioneUsing other logging providers

Alcuni provider di terze parti usano l'approccio descritto nella sezione precedente, inclusi Serilog, NLog e Loggr.Some third-party providers use the approach described in the preceding section, including Serilog, NLog, and Loggr. È possibile inserirli tutti nella registrazione ASP.NET Core oppure usarli separatamente.You can plug each of these into ASP.NET Core logging, or you can use them separately. Serilog offre una funzionalità che arricchisce tutti i messaggi inviati da un logger.Serilog has a feature that enriches all messages sent from a logger. Questa funzionalità può essere utile per restituire il nome del servizio, il tipo e le informazioni sulla partizione.This feature can be useful to output the service name, type, and partition information. Per usare questa funzionalità nell'infrastruttura di ASP.NET Core, seguire questa procedura:To use this capability in the ASP.NET Core infrastructure, do these steps:

  1. Aggiungere i pacchetti NuGet Serilog, Serilog.Extensions.Logging e Serilog.Sinks.Observable al progetto.Add the Serilog, Serilog.Extensions.Logging, and Serilog.Sinks.Observable NuGet packages to the project. Per l'esempio successivo aggiungere anche Serilog.Sinks.Literate.For the next example, also add Serilog.Sinks.Literate. Un approccio migliore viene illustrato più avanti in questo articolo.A better approach is shown later in this article.
  2. In Serilog creare LoggerConfiguration e l'istanza del logger.In Serilog, create a LoggerConfiguration and the logger instance.

    Log.Logger = new LoggerConfiguration().WriteTo.LiterateConsole().CreateLogger();
    
  3. Aggiungere un argomento SeriLog.ILogger al costruttore del servizio e passare il logger appena creato.Add a Serilog.ILogger argument to the service constructor, and pass the newly created logger.

    ServiceRuntime.RegisterServiceAsync("StatelessType", context => new Stateless(context, Log.Logger)).GetAwaiter().GetResult();
    
  4. Nel costruttore del servizio aggiungere il codice seguente che crea il necessario per arricchire le proprietà ServiceTypeName, ServiceName, PartitionId e InstanceId del servizio.In the service constructor, add the following code, which creates the property enrichers for the ServiceTypeName, ServiceName, PartitionId, and InstanceId properties of the service. Aggiunge anche un enricher delle proprietà alla struttura di registrazione di ASP.NET Core, per consentire di usare Microsoft.Extensions.Logging.ILogger nel codice.It also adds a property enricher to the ASP.NET Core logging factory, so you can use Microsoft.Extensions.Logging.ILogger in your code.

    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. Instrumentare il codice come se si stesse usando ASP.NET Core senza Serilog.Instrument the code the same as if you were using ASP.NET Core without Serilog.

    Nota

    È consigliabile non usare Log.Logger statico con l'esempio precedente.We recommend that you don't use the static Log.Logger with the preceding example. Service Fabric può ospitare più istanze dello stesso tipo di servizio in un singolo processo.Service Fabric can host multiple instances of the same service type within a single process. Se si usa Log.Logger statico, l'ultimo writer degli enricher delle proprietà mostrerà i valori per tutte le istanze in esecuzione.If you use the static Log.Logger, the last writer of the property enrichers will show values for all instances that are running. Questo è un motivo per cui la variabile _logger è una variabile di membro privata della classe di servizio.This is one reason why the _logger variable is a private member variable of the service class. È anche necessario rendere disponibile _logger al codice comune, che potrebbe essere usato nei servizi.Also, you must make the _logger available to common code, which might be used across services.

Scelta di un provider di registrazioneChoosing a logging provider

Se l'applicazione si basa sulle prestazioni elevate, EventSource è in genere l'approccio ottimale.If your application relies on high performance, EventSource is usually a good approach. EventSource usa in genere un numero minore di risorse e offre prestazioni migliori rispetto alla registrazione di ASP.NET Core o di eventuali soluzioni di terze parti disponibili.EventSource generally uses fewer resources and performs better than ASP.NET Core logging or any of the available third-party solutions. Non è un problema per molti servizi, ma se il servizio è orientato alle prestazioni EventSource si rivela la scelta più indicata.This isn't an issue for many services, but if your service is performance-oriented, using EventSource might be a better choice. Tuttavia per ottenere questi vantaggi della registrazione strutturata, EventSource richiede un investimento maggiore da parte del team tecnico.However, to get these benefits of structured logging, EventSource requires a larger investment from your engineering team. Se possibile, effettuare un rapido prototipo di alcune opzioni di registrazione e quindi scegliere quello che meglio soddisfa le esigenze dell'utente.If possible, do a quick prototype of a few logging options, and then choose the one that best meets your needs.

Passaggi successiviNext steps

Dopo aver scelto il provider di accesso per instrumentare le applicazioni e i servizi, è necessario aggregare i log e gli eventi prima di inviarli a una piattaforma.Once you have chosen your logging provider to instrument your applications and services, your logs and events need to be aggregated before they can be sent to any analysis platform. Per meglio comprendere alcune delle opzioni consigliate leggere altre informazioni su EventFlow e WAD.Read about EventFlow and WAD to better understand some of the recommended options.