using System; using System.Collections.Generic; using System.Text; using Tapeti.Config; using ISerilogLogger = Serilog.ILogger; // ReSharper disable UnusedMember.Global namespace Tapeti.Serilog { /// /// Implements the Tapeti ILogger interface for Serilog output. /// public class TapetiSeriLogger: IBindingLogger { /// /// Implements the Tapeti ILogger interface for Serilog output. This version /// includes the message body and information if available when an error occurs. /// public class WithMessageLogging : TapetiSeriLogger { /// public WithMessageLogging(ISerilogLogger seriLogger) : base(seriLogger) { } internal override bool IncludeMessageInfo() => true; } private readonly ISerilogLogger seriLogger; /// /// Create a Tapeti ILogger implementation to output to the specified Serilog.ILogger interface /// /// The Serilog.ILogger implementation to output Tapeti log message to public TapetiSeriLogger(ISerilogLogger seriLogger) { this.seriLogger = seriLogger; } /// public void Connect(IConnectContext connectContext) { seriLogger .ForContext("isReconnect", connectContext.IsReconnect) .Information("Tapeti: trying to connect to {host}:{port}/{virtualHost}", connectContext.ConnectionParams.HostName, connectContext.ConnectionParams.Port, connectContext.ConnectionParams.VirtualHost); } /// public void ConnectFailed(IConnectFailedContext connectContext) { seriLogger.Error(connectContext.Exception, "Tapeti: could not connect to {host}:{port}/{virtualHost}", connectContext.ConnectionParams.HostName, connectContext.ConnectionParams.Port, connectContext.ConnectionParams.VirtualHost); } /// public void ConnectSuccess(IConnectSuccessContext connectContext) { seriLogger .ForContext("isReconnect", connectContext.IsReconnect) .Information("Tapeti: successfully connected to {host}:{port}/{virtualHost} on local port {localPort}", connectContext.ConnectionParams.HostName, connectContext.ConnectionParams.Port, connectContext.ConnectionParams.VirtualHost, connectContext.LocalPort); } /// public void Disconnect(IDisconnectContext disconnectContext) { seriLogger .Information("Tapeti: connection closed, reply text = {replyText}, reply code = {replyCode}", disconnectContext.ReplyText, disconnectContext.ReplyCode); } /// public void ConsumeException(Exception exception, IMessageContext messageContext, ConsumeResult consumeResult) { var message = new StringBuilder("Tapeti: exception in message handler"); var messageParams = new List(); var contextLogger = seriLogger .ForContext("consumeResult", consumeResult) .ForContext("exchange", messageContext.Exchange) .ForContext("queue", messageContext.Queue) .ForContext("routingKey", messageContext.RoutingKey); if (messageContext.TryGet(out var controllerPayload)) { contextLogger = contextLogger .ForContext("controller", controllerPayload.Binding.Controller.FullName) .ForContext("method", controllerPayload.Binding.Method.Name); message.Append(" {controller}.{method}"); messageParams.Add(controllerPayload.Binding.Controller.FullName); messageParams.Add(controllerPayload.Binding.Method.Name); } if (IncludeMessageInfo()) { message.Append(" on exchange {exchange}, queue {queue}, routingKey {routingKey}, replyTo {replyTo}, correlationId {correlationId} with body {body}"); messageParams.Add(messageContext.Exchange); messageParams.Add(messageContext.Queue); messageParams.Add(messageContext.RoutingKey); messageParams.Add(messageContext.Properties.ReplyTo); messageParams.Add(messageContext.Properties.CorrelationId); messageParams.Add(messageContext.RawBody != null ? Encoding.UTF8.GetString(messageContext.RawBody) : null); } contextLogger.Error(exception, message.ToString(), messageParams.ToArray()); } /// public void QueueDeclare(string queueName, bool durable, bool passive) { if (passive) seriLogger.Information("Tapeti: verifying durable queue {queueName}", queueName); else seriLogger.Information("Tapeti: declaring {queueType} queue {queueName}", durable ? "durable" : "dynamic", queueName); } /// public void QueueExistsWarning(string queueName, IReadOnlyDictionary existingArguments, IReadOnlyDictionary arguments) { seriLogger.Warning("Tapeti: durable queue {queueName} exists with incompatible x-arguments ({existingArguments} vs. {arguments}) and will not be redeclared, queue will be consumed as-is", queueName, existingArguments, arguments); } /// public void QueueBind(string queueName, bool durable, string exchange, string routingKey) { seriLogger.Information("Tapeti: binding {queueName} to exchange {exchange} with routing key {routingKey}", queueName, exchange, routingKey); } /// public void QueueUnbind(string queueName, string exchange, string routingKey) { seriLogger.Information("Tapeti: removing binding for {queueName} to exchange {exchange} with routing key {routingKey}", queueName, exchange, routingKey); } /// public void ExchangeDeclare(string exchange) { seriLogger.Information("Tapeti: declaring exchange {exchange}", exchange); } /// public void QueueObsolete(string queueName, bool deleted, uint messageCount) { if (deleted) seriLogger.Information("Tapeti: obsolete queue {queue} has been deleted", queueName); else seriLogger.Information("Tapeti: obsolete queue {queue} has been unbound but not yet deleted, {messageCount} messages remaining", queueName, messageCount); } internal virtual bool IncludeMessageInfo() => false; } }