Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add custom top-level properties #70

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ This library uses the [Google Cloud .NET](https://cloud.google.com/dotnet/docs)
| UseSourceContextAsLogName | The log name for a log entry will be set to the [SourceContext](https://github.com/serilog/serilog/wiki/Writing-Log-Events#source-contexts) property if available. Default is `true`. |
| UseLogCorrelation | Integrate logs with [Cloud Trace](https://cloud.google.com/trace) by setting `Trace`, `SpanId`, `TraceSampled` properties if available. Default is `true`. |
| GoogleCredentialJson | JSON string to override [Application Default Credentials](https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application) (contents of your credential file). |
| CustomTopLevelPropertyKeys | Optional names of properties that should be logged on the top-level, next to 'message'. |

### Log Level Mapping

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public void WillInitializeWithDefaultArgumentsCorrectly()
ServiceVersion = null,
UseSourceContextAsLogName = true,
UseLogCorrelation = true,
CustomTopLevelPropertyKeys = new string[0]
});
}

Expand All @@ -39,7 +40,8 @@ public void WillCorrectlyAssignAllConstructorArguments()
useLogCorrelation: false,
googleCredentialJson: "{}",
serviceName: "service-name",
serviceVersion: "1.0.1");
serviceVersion: "1.0.1",
customTopLevelPropertyKeys: new[] {"foo", "bar"});

options
.Should()
Expand All @@ -54,7 +56,8 @@ public void WillCorrectlyAssignAllConstructorArguments()
ServiceName = "service-name",
ServiceVersion = "1.0.1",
UseSourceContextAsLogName = false,
UseLogCorrelation = false
UseLogCorrelation = false,
CustomTopLevelPropertyKeys = new[] {"foo", "bar"}
});
}

Expand Down
16 changes: 15 additions & 1 deletion src/Serilog.Sinks.GoogleCloudLogging/GoogleCloudLoggingSink.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Google.Api;
Expand Down Expand Up @@ -96,9 +97,12 @@ private LogEntry CreateLogEntry(LogEvent evnt, StringWriter writer)
var jsonPayload = new Struct();
jsonPayload.Fields.Add("message", Value.ForString(_logFormatter.RenderEventMessage(evnt, writer)));

foreach (var customTopLevelProperty in GetCustomTopLevelProperties())
_logFormatter.WritePropertyAsJson(jsonPayload, customTopLevelProperty.Key, customTopLevelProperty.Value);

var propStruct = new Struct();
jsonPayload.Fields.Add("properties", Value.ForStruct(propStruct));
foreach (var property in evnt.Properties)
foreach (var property in GetOtherProperties())
{
_logFormatter.WritePropertyAsJson(propStruct, property.Key, property.Value);
HandleSpecialProperty(log, property.Key, property.Value);
Expand All @@ -110,6 +114,16 @@ private LogEntry CreateLogEntry(LogEvent evnt, StringWriter writer)
log.JsonPayload = jsonPayload;

return log;

IEnumerable<KeyValuePair<string, LogEventPropertyValue>> GetCustomTopLevelProperties()
{
return evnt.Properties.Where(p => _sinkOptions.CustomTopLevelPropertyKeys.Any(c => c.Equals(p.Key, StringComparison.OrdinalIgnoreCase)));
}

IEnumerable<KeyValuePair<string, LogEventPropertyValue>> GetOtherProperties()
{
return evnt.Properties.Where(p => !_sinkOptions.CustomTopLevelPropertyKeys.Any(c => c.Equals(p.Key, StringComparison.OrdinalIgnoreCase)));
}
}

private void HandleSpecialProperty(LogEntry log, string key, LogEventPropertyValue value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public static LoggerConfiguration GoogleCloudLogging(
string? googleCredentialJson = null,
string? serviceName = null,
string? serviceVersion = null,
string[]? customTopLevelPropertyKeys = null,
int? batchSizeLimit = null,
TimeSpan? period = null,
int? queueLimit = null,
Expand All @@ -87,7 +88,8 @@ public static LoggerConfiguration GoogleCloudLogging(
useLogCorrelation,
googleCredentialJson,
serviceName,
serviceVersion
serviceVersion,
customTopLevelPropertyKeys ?? new string[0]
);

return loggerConfiguration.GoogleCloudLogging(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;

namespace Serilog.Sinks.GoogleCloudLogging;

Expand Down Expand Up @@ -68,6 +69,11 @@ public class GoogleCloudLoggingSinkOptions
/// </remarks>
public string? ServiceVersion { get; set; }

/// <summary>
/// Optional names of properties that should be logged on the top-level, next to 'message'.
/// </summary>
public string[] CustomTopLevelPropertyKeys { get; set; } = new string[0];

/// <summary>
/// Options for Google Cloud Logging
/// </summary>
Expand Down Expand Up @@ -105,6 +111,9 @@ public class GoogleCloudLoggingSinkOptions
/// Attach service version to log entries (added as `serviceContext.version` metadata in `jsonPayload`).
/// Required for logged exceptions to be forwarded to StackDriver Error Reporting.
/// </param>
/// <param name="customTopLevelPropertyKeys">
/// Optional names of properties that should be logged on the top-level, next to 'message'.
/// </param>
public GoogleCloudLoggingSinkOptions(
string? projectId = null,
string? resourceType = null,
Expand All @@ -115,7 +124,8 @@ public GoogleCloudLoggingSinkOptions(
bool useLogCorrelation = true,
string? googleCredentialJson = null,
string? serviceName = null,
string? serviceVersion = null)
string? serviceVersion = null,
string[]? customTopLevelPropertyKeys = null)
{
ProjectId = projectId;
ResourceType = resourceType;
Expand All @@ -134,5 +144,6 @@ public GoogleCloudLoggingSinkOptions(
GoogleCredentialJson = googleCredentialJson;
ServiceName = serviceName;
ServiceVersion = serviceVersion;
CustomTopLevelPropertyKeys = customTopLevelPropertyKeys ?? new string[0];
}
}
7 changes: 7 additions & 0 deletions src/TestWeb/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
ResourceType = "gce_instance",
LogName = "someLogName",
UseSourceContextAsLogName = true,
CustomTopLevelPropertyKeys = ["customProperty1", "customProperty2"]
};

builder.Host.UseSerilog((ctx, lc) => lc.WriteTo.Console().WriteTo.GoogleCloudLogging(options).MinimumLevel.Is(LogEventLevel.Verbose));
Expand Down Expand Up @@ -76,6 +77,12 @@
{ "valueAsMaxDouble", double.MaxValue },
{ "valueAsMaxDecimal", decimal.MaxValue },
});

_logger.LogInformation(
"Test message with default: {@default} and custom properties: {@customProperty1}, {@customProperty2}",
"default-value",
"customProperty1-value",
"customProperty2-value");

try
{
Expand Down
3 changes: 2 additions & 1 deletion src/TestWeb/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
},
"resourceLabels": {
"someResourceLabel": "bar"
}
},
"customTopLevelPropertyKeys": ["customProperty1", "customProperty2"]
}
}
]
Expand Down