Skip to content

Commit

Permalink
refactor: Makes GoogleLoggerScope extendable.
Browse files Browse the repository at this point in the history
Moves GoogleLoggerScope to Diagnostics.Common.
In preparation for allowing LogEntry augmentation and making it easier to use Google logging from non ASP.NET Core apps.
Towards #5313, #5360, #5929 and #6367
  • Loading branch information
amanda-tarafa committed Jun 16, 2021
1 parent da8f2f7 commit c8e9a48
Show file tree
Hide file tree
Showing 8 changed files with 559 additions and 328 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ public async Task Logging_Scope()
{
var message = EntryData.GetMessage(nameof(MainController.Scope), testId);
Assert.Equal(message, results.Single().JsonPayload.Fields["message"].StringValue);
Assert.Contains("Scope => ", results.Single().JsonPayload.Fields["scope"].StringValue);
Assert.Contains("Scope", results.Single().JsonPayload.Fields["scope"].StringValue);
});
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
using Google.Cloud.Diagnostics.Common;
using Google.Cloud.Logging.V2;
using Google.Protobuf.WellKnownTypes;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Moq;
using System;
Expand Down Expand Up @@ -141,7 +140,7 @@ public void BeginScope()
{
Predicate<IEnumerable<LogEntry>> matcher = (l) =>
l.Single().JsonPayload.Fields["message"].StringValue == LogMessage &&
l.Single().JsonPayload.Fields["scope"].StringValue == "scope => ";
l.Single().JsonPayload.Fields["scope"].StringValue == "scope";
var mockConsumer = new Mock<IConsumer<LogEntry>>();
mockConsumer.Setup(c => c.Receive(Match.Create(matcher)));
var logger = GetLogger(mockConsumer.Object, logLevel: LogLevel.Information);
Expand All @@ -161,7 +160,7 @@ public void BeginScope_WithFormattedScope()
var parentScopes = json["parent_scopes"].ListValue.Values;
var parentScope0 = parentScopes[0].StructValue.Fields;
return json["message"].StringValue == LogMessage &&
json["scope"].StringValue == "scope 42, Baz => " &&
json["scope"].StringValue == "scope 42, Baz" &&
parentScopes.Count == 1 &&
parentScope0.Count == 3 &&
parentScope0["Foo"].StringValue == "42" &&
Expand Down Expand Up @@ -189,7 +188,7 @@ public void BeginScope_DigitOnlyFormatParametersHaveUnderscorePrefix()
var parentScopes = json["parent_scopes"].ListValue.Values;
var parentScope0 = parentScopes[0].StructValue.Fields;
return json["message"].StringValue == LogMessage &&
json["scope"].StringValue == "scope 42, Baz => " &&
json["scope"].StringValue == "scope 42, Baz" &&
parentScopes.Count == 1 &&
parentScope0.Count == 3 &&
parentScope0["_0"].StringValue == "42" &&
Expand Down Expand Up @@ -219,7 +218,7 @@ public void BeginScope_WithNestedFormattedScope()
var scope1 = parentScopes[1].StructValue.Fields;
return json["message"].StringValue == LogMessage &&
json["scope"].StringValue == "first 42 => second Baz => " &&
json["scope"].StringValue == "first 42 => second Baz" &&
parentScopes.Count == 2 &&
scope0.Count == 2 &&
scope0["{OriginalFormat}"].StringValue == "second {Bar}" &&
Expand Down Expand Up @@ -256,7 +255,7 @@ public void BeginScope_WithFormattedMessageAndScope()
var parentScopes = json["parent_scopes"].ListValue.Values;
var parentScope0 = parentScopes[0].StructValue.Fields;
return json["message"].StringValue == "a log message with stuff" &&
json["scope"].StringValue == "scope 42 => " &&
json["scope"].StringValue == "scope 42" &&
formatParams.Count == 2 &&
formatParams["things"].StringValue == logParam &&
formatParams["{OriginalFormat}"].StringValue == message &&
Expand All @@ -282,7 +281,7 @@ public void BeginScope_Nested()
{
Predicate<IEnumerable<LogEntry>> matcher = (l) =>
l.Single().JsonPayload.Fields["message"].StringValue == LogMessage &&
l.Single().JsonPayload.Fields["scope"].StringValue == "parent => child => ";
l.Single().JsonPayload.Fields["scope"].StringValue == "parent => child";
var mockConsumer = new Mock<IConsumer<LogEntry>>();
mockConsumer.Setup(c => c.Receive(Match.Create(matcher)));
var logger = GetLogger(mockConsumer.Object, LogLevel.Information);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,6 @@ namespace Google.Cloud.Diagnostics.AspNetCore
/// <summary>
/// <see cref="ILogger"/> for Google Cloud Logging.
/// </summary>
///
/// <example>
/// <code>
/// public void Configure(ILoggerFactory loggerFactory)
/// {
/// string projectId = "[Google Cloud Platform project ID]";
/// loggerFactory.AddGoogle(projectId);
/// ...
/// }
/// </code>
/// </example>
///
/// <remarks>
/// Logs to Google Cloud Logging.
/// Docs: https://cloud.google.com/logging/docs/
/// </remarks>
/// <seealso cref="GoogleLoggerFactoryExtensions"/>
public sealed class GoogleLogger : ILogger
{
private const string GcpConsoleLogsBaseUrl = "https://console.cloud.google.com/logs/viewer";
Expand Down Expand Up @@ -97,7 +80,7 @@ public sealed class GoogleLogger : ILogger
}

/// <inheritdoc />
public IDisposable BeginScope<TState>(TState state) => new GoogleLoggerScope(state);
public IDisposable BeginScope<TState>(TState state) => GoogleLoggerScope.BeginScope(state);

/// <inheritdoc />
public bool IsEnabled(LogLevel logLevel) => logLevel >= _loggerOptions.LogLevel;
Expand Down Expand Up @@ -130,6 +113,7 @@ public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Except
Labels = { CreateLabels() },
};

GoogleLoggerScope.Current?.ApplyFullScopeStack(entry);
SetTraceAndSpanIfAny(entry);

_consumer.Receive(new[] { entry });
Expand Down Expand Up @@ -194,32 +178,7 @@ private Struct CreateJsonPayload<TState>(EventId eventId, TState state, Exceptio
if (state is IEnumerable<KeyValuePair<string, object>> formatParams &&
ContainsFormatParameters(formatParams))
{
jsonStruct.Fields.Add("format_parameters", CreateStructValue(formatParams));
}

var currentLogScope = GoogleLoggerScope.Current;
if (currentLogScope != null)
{
jsonStruct.Fields.Add("scope", Value.ForString(currentLogScope.ToString()));
}

// Create a map of format parameters of all the parent scopes,
// starting from the most inner scope to the top-level scope.
var scopeParamsList = new List<Value>();
while (currentLogScope != null)
{
// Determine if the state of the scope are format params
if (currentLogScope.State is IEnumerable<KeyValuePair<string, object>> scopeFormatParams)
{
scopeParamsList.Add(CreateStructValue(scopeFormatParams));
}

currentLogScope = currentLogScope.Parent;
}

if (scopeParamsList.Count > 0)
{
jsonStruct.Fields.Add("parent_scopes", Value.ForList(scopeParamsList.ToArray()));
jsonStruct.Fields.Add("format_parameters", formatParams.ToStructValue());
}

return jsonStruct;
Expand Down Expand Up @@ -247,25 +206,6 @@ bool ContainsFormatParameters(IEnumerable<KeyValuePair<string, object>> fields)
return iterator.MoveNext();
}
}

Value CreateStructValue(IEnumerable<KeyValuePair<string, object>> fields)
{
Struct fieldsStruct = new Struct();
foreach (var pair in fields)
{
string key = pair.Key;
if (string.IsNullOrEmpty(key))
{
continue;
}
if (char.IsDigit(key[0]))
{
key = "_" + key;
}
fieldsStruct.Fields[key] = Value.ForString(pair.Value?.ToString() ?? "");
}
return Value.ForStruct(fieldsStruct);
}
}

private void SetTraceAndSpanIfAny(LogEntry entry)
Expand Down
Loading

0 comments on commit c8e9a48

Please sign in to comment.