Skip to content

3.8 Diagnostics

Jesse Sweetland edited this page Feb 7, 2018 · 9 revisions

As messages are received and processed, Platibus emits DiagnosticEvents that provide visibility into the low level activity that takes place. Diagnostic events are raised via the IDiagnosticService. Implementers can consume these events by registering one or more IDiagnosticEventSink implementations with the IDiagnosticService.

Diagnostic event sinks can be registered declaratively in the nested <diagnostics> configuration element or by invoking the AddSink method of the diagnostic service instance exposed through the DiagnosticService property on the configuration object passed to a configuration hook.

Diagnostic Events

The base diagnostic events specifies the following fields:

Field Required Description
Source No The object that raised the event
Timestamp Yes The UTC timestamp indicating when the event was raised
Type Yes The type of diagnostic event
Detail No Specific details regarding this instance of the event
Exception No The exception that prompted the event to be raised
Message No The Platibus Message to which the event pertains
Endpoint No The name of the endpoint to which the event pertains
Queue No The name of the queue to which the event pertains
Topic No The name of the topic to which the event pertains

Diagnostic Event Types

All diagnostic events are associated with a diagnostic event types. These types are discrete and there are a finite number specified within the core Platibus libraries, but they are also extensible. The diagnostic event type specifically and unambiguously the event that occurred. They are intended to be machine readable to enable intelligent grouping and windowing of events within sinks (e.g. for monitoring or metrics gathering).

The complete list of supported diagnostic event types can be found in the following classes:

Diagnostic event types are also associated with a diagnostic event level, which determines the severity or urgency of the event.

Diagnostic Event Levels

The diagnostic event levels specified by Platibus mirror those of many logging frameworks.

Level Value Description
Trace -1 Routine low-level events used for monitoring or metrics gathering
Debug 0 Routine low-level events exposing intermediate state, branch logic, or other information useful for troubleshooting unexpected conditions or outcomes (default)
Info 1 Routine high-level events used to verify correct operation
Warn 2 Unexpected but recoverable conditions that may warrant attention
Error 3 Unexpected and unrecoverable conditions that may require review and intervention

Sink Providers

The following sections describe the diagnostic event sink providers shipped with the Platibus package.

Filtering Sink

All sinks can be wrapped in a filtering sink to limit the events that are passed through to sink.

Events can be filtered by diagnostic event level by specifying minLevel and/or maxLevel attributes in the declarative configuration for any sink:

   <diagnostics>
      <sinks>
          <add name="consoleSink" provider="Console" minLevel="Warn" maxLevel="Error" />
      </sinks>
   </diagnostics>

Programmatic configuration example:

public class ConfigurationHook : IConfigurationHook
{
    public void Configure(PlatibusConfiguration configuration)
    {
        var consoleSink = new ConsoleLoggingSink();
        var minLevel = DiagnosticEventLevel.Warn;
        var maxLevel = DiagnosticEventLevel.Error;
        var filter = new DiagnosticEventLevelSpecification(minLevel, maxLevel);
        var filteringSink = new FilteringSink(consoleSink, filter);
        configuration.DiagnosticService.AddSink(filteringSink);
    }
}

If programmatic configuration is used, then any implementation of IDiagnosticEventSpecification can be supplied as the second argument to FilteringSink.

Console Logging Sink

The ConsoleLoggingSink emits formatted messages to the console.

Declarative configuration example:

   <diagnostics>
      <sinks>
          <add name="consoleSink" provider="Console" />
      </sinks>
   </diagnostics>

Programmatic configuration example:

public class ConfigurationHook : IConfigurationHook
{
    public void Configure(PlatibusConfiguration configuration)
    {
        var consoleSink = new ConsoleLoggingSink();
        configuration.DiagnosticService.AddSink(consoleSink);
    }
}

Common Logging Sink

Platibus version 3 and prior uses Common Logging for all diagnostic output. The CommonLoggingSink has been provided to enable the use of existing logging configuration as much as possible.

Note: the log categories used by the CommonLoggingSink are based on the DiagnosticEventType and not the previously defined LoggingCategories. Adjustments to existing rules may be needed.

Declarative configuration example:

   <diagnostics>
      <sinks>
          <add name="commonLoggingSink" provider="CommonLogging" />
      </sinks>
   </diagnostics>

Programmatic configuration example:

public class ConfigurationHook : IConfigurationHook
{
    public void Configure(PlatibusConfiguration configuration)
    {
        var commonLoggingSink = new CommonLoggingSink();
        configuration.DiagnosticService.AddSink(commonLoggingSink);
    }
}

GELF Sinks

Platibus supports output of diagnostic events in Graylog Extended Logging Format (GELF) to UDP, TCP, or HTTP inputs in a Graylog server or compatible service.

UDP

The GelfUdpLoggingSink emits GELF formatted log events over UDP with optional compression.

Declarative configuration example:

   <diagnostics>
      <sinks>
          <add name="gelfUdpSink" provider="GelfUdp" 
               host="127.0.0.1" port="12201" compress="true" />
      </sinks>
   </diagnostics>

Programmatic configuration example:

public class ConfigurationHook : IConfigurationHook
{
    public void Configure(PlatibusConfiguration configuration)
    {
        var gelfUdpSink = new GelfUdpLoggingSink("127.0.0.1", "12201", true);
        configuration.DiagnosticService.AddSink(gelfUdpSink);
    }
}

TCP

The GelfTcpLoggingSink emits GELF formatted log events over a persistent TCP connection.

Declarative configuration example:

   <diagnostics>
      <sinks>
          <add name="gelfTcpSink" provider="GelfTcp" 
               host="127.0.0.1" port="12201" />
      </sinks>
   </diagnostics>

Programmatic configuration example:

public class ConfigurationHook : IConfigurationHook
{
    public void Configure(PlatibusConfiguration configuration)
    {
        var gelfTcpSink = new GelfTcpLoggingSink("127.0.0.1", "12201");
        configuration.DiagnosticService.AddSink(gelfTcpSink);
    }
}

HTTP

The GelfHttpLoggingSink POSTs GELF formatted log events to an HTTP REST endpoint. Authentication is supported but optional.

Declarative configuration example:

   <diagnostics>
      <sinks>
          <add name="gelfHttpSink" provider="GelfHttp" 
               uri="http://127.0.0.1:12201/gelf" username="user" password="pass" />
      </sinks>
   </diagnostics>

Programmatic configuration example:

public class ConfigurationHook : IConfigurationHook
{
    public void Configure(PlatibusConfiguration configuration)
    {
        var uri = new Uri("http://localhost:12201/gelf");
        var credentials = new BasicAuthCredentials("user", "pass");
        var gelfHttpSink = new GelfHttpLoggingSink(uri, credentials);
        configuration.DiagnosticService.AddSink(gelfHttpSink);
    }
}

InfluxDB Sink

The InfluxDBSink counts the number of instances of certain types of diagnostic events and periodically POSTs points to an InfluxDB database. Implementers must specify the URI of the InfluxDB server and the database to which points are written. The name of the measurement, sample rate, precision, and custom tags are configurable but optional.

Custom Tags

Implementers may specify a static dictionary of custom tags to include with each point. If custom tags are not specified, then the following tags will be included by default:

Key Value
host The hostname of the machine on which the application is running
app The name of the application approximated by the name of the entry or executing assembly
app_ver The version of the application approximated by the version number of the entry or executing assembly

Fields

Field values are represented as long integers that represent the number of occurrences between samples. The following fields are tracked:

Field Value
requests Total number of HTTP requests received
received Total number of messages received
acknowledgements Total number of messages acknowledged
acknowledgement_failures Total number of handling attempts in which messages were not acknowledged
expired Total number of expired messages
dead Total number of dead letters (maximum attempts exceeded)
sent Total number of messages sent
delivered Total number of sent messages that were successfully delivered
delivery_failures Total number of sent messages that could not be delivered
errors Total number of events with the Error level
warnings Total number of events with the Warning level

Declarative configuration example:

   <diagnostics>
      <sinks>
          <add name="influxDBSink" provider="InfluxDB"
               uri="http://127.0.0.1:8086" database="mydb"
               measurement="pb_stats" precision="s"
               username="user" password="pass"
               tags="host=myserver,app=MyApp,app_ver=1.2"
               sampleRate="00:00:05"/>
      </sinks>
   </diagnostics>

Programmatic configuration example:

public class ConfigurationHook : IConfigurationHook
{
    public void Configure(PlatibusConfiguration configuration)
    {
        var uri = new Uri("http://localhost:8086");
        var database = "mydb";
        var options = new InfluxDBOptions(uri, database)
        {
            Measurement = "pb_stats",
            Username = "user",
            Password = "pass",
            Precision = InfluxDBPrecision.Second,
            Tags = {
                {"host", Environment.MachineName},
                {"app", "MyApp"},
                {"app_ver", "1.2"}
            }
        };
        var sampleRate = TimeSpan.FromSeconds(5);
        var influxDbSink = new InfluxDBSink(options, sampleRate);
        configuration.DiagnosticService.AddSink(influxDbSink);
    }
}