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 log event properties to eventhubdata #18

Open
wants to merge 3 commits into
base: dev
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
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using Microsoft.Azure.EventHubs;
using Serilog.Events;
using Serilog.Formatting;
using Serilog.Sinks.AzureEventHub.Extensions;
using Serilog.Sinks.PeriodicBatching;

namespace Serilog.Sinks.AzureEventHub
Expand Down Expand Up @@ -77,9 +78,10 @@ protected override Task EmitBatchAsync(IEnumerable<LogEvent> events)
body = Encoding.UTF8.GetBytes(render.ToString());
}
var eventHubData = new EventData(body);

eventHubData.Properties.Add("Type", "SerilogEvent");
eventHubData.Properties.Add("Level", logEvent.Level.ToString());
eventHubData.AddEventProperties(logEvent.Properties);

batchedEvents.Add(eventHubData);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
// Copyright 2014 Serilog Contributors
//
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.Azure.EventHubs;
using Serilog.Core;
using Serilog.Events;
using Serilog.Formatting;
using Serilog.Sinks.AzureEventHub.Extensions;

namespace Serilog.Sinks.AzureEventHub
{
Expand All @@ -36,8 +41,8 @@ public class AzureEventHubSink : ILogEventSink
/// <param name="eventHubClient">The EventHubClient to use in this sink.</param>
/// <param name="formatter">Provides formatting for outputting log data</param>
public AzureEventHubSink(
EventHubClient eventHubClient,
ITextFormatter formatter)
EventHubClient eventHubClient,
ITextFormatter formatter)
{
_eventHubClient = eventHubClient;
_formatter = formatter;
Expand All @@ -59,6 +64,8 @@ public void Emit(LogEvent logEvent)
eventHubData.Properties.Add("Type", "SerilogEvent");
eventHubData.Properties.Add("Level", logEvent.Level.ToString());

eventHubData.AddEventProperties(logEvent.Properties);

//Unfortunately no support for async in Serilog yet
//https://github.com/serilog/serilog/issues/134
_eventHubClient.SendAsync(eventHubData, Guid.NewGuid().ToString()).GetAwaiter().GetResult();
Expand Down
107 changes: 107 additions & 0 deletions src/Serilog.Sinks.AzureEventHub/Sinks/Extensions/EventDataExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
using Microsoft.Azure.EventHubs;
using Serilog.Events;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace Serilog.Sinks.AzureEventHub.Extensions
{
/// <summary>
/// Extensions for EventData Class
/// </summary>
public static class EventDataExtension
{
/// <summary>
/// Convert and Map LogEvent Properties to Azure Hub Event Data Properties
/// </summary>
/// <param name="logEvent"></param>
/// <param name="properties"></param>
public static void AddEventProperties(this EventData logEvent, IReadOnlyDictionary<string, LogEventPropertyValue> properties)
{
foreach (var item in properties)
{
var value = GetEventPropertyValue(item.Value);
if (value is IDictionary<string, object> dic)
{
FaltternDictionary(dic, logEvent, item.Key);
}
else
{
logEvent.Properties.Add(item.Key, value);
}
}

}

private static void FaltternDictionary(IDictionary<string, object> nestedDictionary, EventData logEvent, string parentPropertyName)
{
foreach (var item in nestedDictionary)
{
var propertyName = $"{parentPropertyName}.{item.Key}";
if (item.Value is IDictionary<string, object> dic)
{
FaltternDictionary(dic, logEvent, propertyName);
}
else
{
logEvent.Properties.Add(propertyName, item.Value);
}
}
}

private static object GetEventPropertyValue(LogEventPropertyValue data)
{
switch (data)
{
case ScalarValue value:
// Because it can't serialize enums
var isEnum = value.Value?.GetType().GetTypeInfo().IsEnum;
if (isEnum != null && (bool)isEnum)
return value.Value.ToString();
return value.Value;
case DictionaryValue dictValue:
{
var expObject = new ExpandoObject() as IDictionary<string, object>;
foreach (var item in dictValue.Elements)
{
if (item.Key.Value is string key)
expObject.Add(key, GetEventPropertyValue(item.Value));
}
return expObject;
}

case SequenceValue seq:
var sequenceItems = seq.Elements.Select(GetEventPropertyValue).ToArray();
return string.Join(", ", sequenceItems);

case StructureValue str:
try
{
if (str.TypeTag == null)
return str.Properties.ToDictionary(p => p.Name, p => GetEventPropertyValue(p.Value));

if (!str.TypeTag.StartsWith("DictionaryEntry") && !str.TypeTag.StartsWith("KeyValuePair"))
return str.Properties.ToDictionary(p => p.Name, p => GetEventPropertyValue(p.Value));

var key = GetEventPropertyValue(str.Properties[0].Value);
if (key == null)
return null;

var expObject = new ExpandoObject() as IDictionary<string, object>;
expObject.Add(key.ToString(), GetEventPropertyValue(str.Properties[1].Value));
return expObject;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
break;
}

return null;
}
}
}