Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 73 additions & 63 deletions Libraries/src/Amazon.Lambda.Logging.AspNetCore/LambdaILogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,32 @@
using System.Collections.Generic;

namespace Microsoft.Extensions.Logging
{
internal class LambdaILogger : ILogger
{
// Private fields
private readonly string _categoryName;
private readonly LambdaLoggerOptions _options;


internal IExternalScopeProvider ScopeProvider { get; set; }

// Constructor
public LambdaILogger(string categoryName, LambdaLoggerOptions options)
{
_categoryName = categoryName;
_options = options;
}

// ILogger methods
public IDisposable BeginScope<TState>(TState state) => ScopeProvider?.Push(state) ?? new NoOpDisposable();

public bool IsEnabled(LogLevel logLevel)
{
return (
_options.Filter == null ||
_options.Filter(_categoryName, logLevel));
}
{
internal class LambdaILogger : ILogger
{
// Private fields
private readonly string _categoryName;
private readonly LambdaLoggerOptions _options;
internal IExternalScopeProvider ScopeProvider { get; set; }
// Constructor
public LambdaILogger(string categoryName, LambdaLoggerOptions options)
{
_categoryName = categoryName;
_options = options;
}
// ILogger methods
public IDisposable BeginScope<TState>(TState state) => ScopeProvider?.Push(state) ?? new NoOpDisposable();
public bool IsEnabled(LogLevel logLevel)
{
return (
_options.Filter == null ||
_options.Filter(_categoryName, logLevel));
}

/// <summary>
/// The Log method called by the ILogger framework to log message to logger's target. In the Lambda case the formatted logging will be
Expand All @@ -39,17 +39,17 @@ public bool IsEnabled(LogLevel logLevel)
/// <param name="state"></param>
/// <param name="exception"></param>
/// <param name="formatter"></param>
/// <exception cref="ArgumentNullException"></exception>
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (formatter == null)
{
throw new ArgumentNullException(nameof(formatter));
}

if (!IsEnabled(logLevel))
{
return;
/// <exception cref="ArgumentNullException"></exception>
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (formatter == null)
{
throw new ArgumentNullException(nameof(formatter));
}
if (!IsEnabled(logLevel))
{
return;
}

var lambdaLogLevel = ConvertLogLevel(logLevel);
Expand All @@ -75,6 +75,16 @@ public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Except
messageTemplate = formatter.Invoke(state, exception);
}

if (_options.IncludeCategory)
{
// Unlike the text format, the JSON format otherwise drops the
// category entirely, so IncludeCategory has no effect. Prepend a
// "{Category}" placeholder (which the JSON formatter turns into a
// queryable property) and supply the category value.
messageTemplate = "[{Category}] " + messageTemplate;
parameters.Insert(0, _categoryName);
}

Amazon.Lambda.Core.LambdaLogger.Log(lambdaLogLevel, exception, messageTemplate, parameters.ToArray());
}
else
Expand Down Expand Up @@ -133,26 +143,26 @@ private static Amazon.Lambda.Core.LogLevel ConvertLogLevel(LogLevel logLevel)
default:
return Amazon.Lambda.Core.LogLevel.Information;
}
}

private void GetScopeInformation(List<string> logMessageComponents)
{
var scopeProvider = ScopeProvider;

if (_options.IncludeScopes && scopeProvider != null)
{
var initialCount = logMessageComponents.Count;

scopeProvider.ForEachScope((scope, list) =>
{
list.Add(scope.ToString());
}, (logMessageComponents));

if (logMessageComponents.Count > initialCount)
{
logMessageComponents.Add("=>");
}
}
}
private void GetScopeInformation(List<string> logMessageComponents)
{
var scopeProvider = ScopeProvider;
if (_options.IncludeScopes && scopeProvider != null)
{
var initialCount = logMessageComponents.Count;
scopeProvider.ForEachScope((scope, list) =>
{
list.Add(scope.ToString());
}, (logMessageComponents));
if (logMessageComponents.Count > initialCount)
{
logMessageComponents.Add("=>");
}
}
}

private bool IsLambdaJsonFormatEnabled
Expand All @@ -164,12 +174,12 @@ private bool IsLambdaJsonFormatEnabled
}

// Private classes
private class NoOpDisposable : IDisposable
{
public void Dispose()
{
}
private class NoOpDisposable : IDisposable
{
public void Dispose()
{
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,76 @@ public void TestJSONParameterLogging()

}

[Fact]
public void TestJSONParameterLoggingIncludesCategoryWhenEnabled()
{
Environment.SetEnvironmentVariable("AWS_LAMBDA_LOG_FORMAT", "JSON");
try
{
using (var writer = new StringWriter())
{
ConnectLoggingActionToLogger(message => writer.Write(message));

var configuration = new ConfigurationBuilder()
.AddJsonFile(GetAppSettingsPath("appsettings.json"))
.Build();

var loggerOptions = new LambdaLoggerOptions(configuration);
loggerOptions.IncludeCategory = true;
var loggerFactory = new TestLoggerFactory()
.AddLambdaLogger(loggerOptions);

var logger = loggerFactory.CreateLogger("JSONLogging");

logger.LogError(new Exception("Too Cheap"), "User {name} fail to by {product} for {price}", "Gilmour", "Guitar", 55.55);

var text = writer.ToString();
// Category is prepended as a placeholder + argument, so it becomes
// a queryable JSON property instead of being dropped.
Assert.Contains("{Category}", text);
Assert.Contains("parameter count: 4", text);
}
}
finally
{
Environment.SetEnvironmentVariable("AWS_LAMBDA_LOG_FORMAT", null);
}
}

[Fact]
public void TestJSONParameterLoggingOmitsCategoryWhenDisabled()
{
Environment.SetEnvironmentVariable("AWS_LAMBDA_LOG_FORMAT", "JSON");
try
{
using (var writer = new StringWriter())
{
ConnectLoggingActionToLogger(message => writer.Write(message));

var configuration = new ConfigurationBuilder()
.AddJsonFile(GetAppSettingsPath("appsettings.json"))
.Build();

var loggerOptions = new LambdaLoggerOptions(configuration);
loggerOptions.IncludeCategory = false;
var loggerFactory = new TestLoggerFactory()
.AddLambdaLogger(loggerOptions);

var logger = loggerFactory.CreateLogger("JSONLogging");

logger.LogError(new Exception("Too Cheap"), "User {name} fail to by {product} for {price}", "Gilmour", "Guitar", 55.55);

var text = writer.ToString();
Assert.DoesNotContain("{Category}", text);
Assert.Contains("parameter count: 3", text);
}
}
finally
{
Environment.SetEnvironmentVariable("AWS_LAMBDA_LOG_FORMAT", null);
}
}

[Fact]
public void JsonLoggingWithNoOriginalFormat()
{
Expand Down