Skip to content
This repository has been archived by the owner on Sep 26, 2023. It is now read-only.

Commit

Permalink
Merge pull request #5 from Authenticom/develop
Browse files Browse the repository at this point in the history
Split single attribute into two separate ones and modifications to subject/type reflection code
  • Loading branch information
sirkirby authored Sep 15, 2017
2 parents a1be803 + 56f77a4 commit 54f1cfb
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 55 deletions.
18 changes: 10 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

All log events are sent to a custom event grid topic as an HTTP Post. For more information on Event Grid, see https://docs.microsoft.com/en-us/azure/event-grid/

[![NuGet](https://img.shields.io/nuget/v/Serilog.Sinks.EventGrid.svg)](https://www.nuget.org/packages/Serilog.Sinks.EventGrid/) [![Build status](https://ci.appveyor.com/api/projects/status/uxmd0qanuk1eltrg/branch/master?svg=true)](https://ci.appveyor.com/project/Authenticom/serilog-sinks-eventgrid/branch/master)

## Targets

* [.NET Standard 2](https://github.com/dotnet/standard/blob/master/docs/versions.md) (netstandard2)
Expand Down Expand Up @@ -43,29 +45,29 @@ The type of every event sent by this logger configuration

**customSubjectPropertyName** (string)

Name of the property added to the Serilog log event that will contain the Subject of the event
Name of the property added to the Serilog log event that will contain the Subject of the event. By default, the property key it's looking for is `EventSubject`

```csharp
Log.ForContext("SubjectPropertyName", "my/custom/subject/id").Information("{@OtherData}", otherData)
```

**customTypePropertyName** (string)

Name of the property added to the Serilog log event that will contain the Type of the event
Name of the property added to the Serilog log event that will contain the Type of the event. By default, the property key it's looking for is `EventType`

```csharp
Log.ForContext("EventPropertyName", "myCustomType").Information("{@OtherData}", otherData)
```

### Custom Attributes

In to specifying the subject and type through configuration or properties, you can rely on reflection at runtime using the `[EventGridSink]` Attribute. You can decorate any method or class with the attribute specifying the subject, type, or both. The Serilog log event called within the context of a method or class decorated with the attribute, will use those values when submitting the event.
In to specifying the subject and type through configuration or properties, you can rely on reflection at runtime using the `[EventGridSubject]` and `[EventGridType]` Attributes. You can decorate any method or class with the attributes, using one or both on each. The Serilog log event called within the context of a method or class decorated with the attribute, will use those values when submitting the event.

```csharp
[EventGridSink("MyCustomType")]
[EventGridType("MyCustomType")]
public class MyLogicClass
{
[EventGridSink(null, "MyCustomSubject/DoSomething")]
[EventGridSubject("MyCustomSubject/DoSomething")]
public void DoSomething(UserContext user)
{
Log.Information("{@user}", user);
Expand All @@ -77,7 +79,7 @@ In the above example, the information log event would have a subject of `MyCusto

### When you don't specify a custom subject or type

The simplest way to use the sink, is to let it set the subject and type for you. If neither was supplied using the above methods, then the sink will use reflection to walk back up the stack trace and attempt to add a meaningful subject and type for your event. The subject is based on the calling apps assembly name, class name, and method name in the following format: `AssemblyName/ClassName/MethodName`. The type will combine the calling method name and any parameter names for that method in the following format: `MethodName.param1Name.param2Name`. This is the resulting event based on the example class:
The simplest way to use the sink, is to let it set the subject and type for you. If neither was supplied using the above methods, then the sink will use reflection to walk back up the stack trace and attempt to add a meaningful subject and type for your event. The subject is based on the calling apps method name and any parameter names for that method in the following format: `MethodName/param1/param2`. The type will simply use the assembly name and class name in the following format: `AssemblyName/ClassName`. This is the resulting event based on the example class:

```csharp
public class MyLogicClass
Expand All @@ -92,8 +94,8 @@ public class MyLogicClass
```json
[{
"id": "15065e6e-5c0e-4258-836a-8cfc6f7b0efd",
"eventType": "DoSomething.user",
"subject": "MyClassLib/MyLogicClass/DoSomething",
"eventType": "MyClassLib/MyLogicClass",
"subject": "DoSomething/user",
"eventTime": "2017-09-07T19:35:04.9853198Z",
"data": [
{
Expand Down
4 changes: 2 additions & 2 deletions src/Serilog.Sinks.EventGrid/Serilog.Sinks.EventGrid.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
<Product />
<Description>Send log events to custom topics in Azure Event Grid</Description>
<PackageLicenseUrl>http://www.apache.org/licenses/LICENSE-2.0</PackageLicenseUrl>
<PackageProjectUrl>http://serilog.net</PackageProjectUrl>
<PackageProjectUrl>https://github.com/authenticom/serilog-sinks-eventgrid</PackageProjectUrl>
<PackageIconUrl>http://serilog.net/images/serilog-sink-nuget.png</PackageIconUrl>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/Authenticom/serilog-sinks-eventgrid</RepositoryUrl>
<PackageTags>serilog events eventgrid</PackageTags>
<Copyright>Copyright © Serilog Contributors 2017</Copyright>
<Copyright>Copyright © Chris Kirby 2017</Copyright>
</PropertyGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net461'">
Expand Down
56 changes: 33 additions & 23 deletions src/Serilog.Sinks.EventGrid/Sinks/EventGrid/EventGridSink.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,41 +99,51 @@ void GetEventInfoFromAttribute(CustomEventRequest customEvent)
var methods = stackFrames.Where(f => f != null).Select(f => f.GetMethod()).ToArray();
// walk through serilog to reach the calling method
var callingMethod = methods.FirstOrDefault(m => !m?.DeclaringType?.FullName?.StartsWith("Serilog") ?? false) ?? methods.First();
EventGridSinkAttribute myCustomAttribute;

// first look for the first method in the stack with the attribute
var methodAttribute = methods.FirstOrDefault(m => m.GetCustomAttribute<EventGridSinkAttribute>() != null)?.GetCustomAttribute<EventGridSinkAttribute>();
if (methodAttribute != null)
myCustomAttribute = methodAttribute;
else
{
// then look for the first class with the attribute, there can be only one
var classAttribute = methods.FirstOrDefault(m => m.ReflectedType != null && m.ReflectedType.GetCustomAttribute<EventGridSinkAttribute>() != null)?.ReflectedType?.GetCustomAttribute<EventGridSinkAttribute>();
myCustomAttribute = classAttribute;
}
var subjectAttributeValue = GetCustomValueFromAttribute<EventGridSubjectAttribute>(methods);
var typeAttributeValue = GetCustomValueFromAttribute<EventGridTypeAttribute>(methods);

// assign the event info, failing back to generic defaults
customEvent.Subject = customEvent.Subject ?? myCustomAttribute?.CustomEventSubject ?? GetSubject();
customEvent.EventType = customEvent.EventType ?? myCustomAttribute?.CustomEvenType ?? _customEventType ?? GetType();
customEvent.Subject = customEvent.Subject ?? subjectAttributeValue ?? GetSubject();
customEvent.EventType = customEvent.EventType ?? typeAttributeValue ?? _customEventType ?? GetEventType() ?? "AppDomain/Class";

string GetSubject()
{
// try to find the method where the log event initiated from
var methodName = GetMethodWithParams() ?? "Method/default";
return $"{methodName}";
}

string GetMethodWithParams()
{
var parameterNames = callingMethod != null && callingMethod.GetParameters().Any()
? callingMethod.GetParameters().Select(x => x.Name).Aggregate((combined, next) => combined += string.IsNullOrEmpty(combined) ? next : $"/{next}")
: "default";
var methodWithParameters = $"{callingMethod.Name}/{parameterNames}";
return methodWithParameters;
}

string GetEventType()
{
var assemblyName = callingMethod?.ReflectedType?.Assembly.GetName().Name ?? "General";
var className = callingMethod?.ReflectedType?.Name ?? "Class";
var methodName = callingMethod.Name;
return $"{assemblyName}/{className}/{methodName}";

return $"{assemblyName}/{className}";
}
}

string GetType()
private string GetCustomValueFromAttribute<TAttribute>(MethodBase[] methods) where TAttribute : Attribute, IEventGridAttribute
{
TAttribute tAttribute;
// look for the first method in the stack with the type attribute
var methodAttribute = methods.FirstOrDefault(m => m.GetCustomAttribute<TAttribute>() != null)?.GetCustomAttribute<TAttribute>();
if (methodAttribute != null)
tAttribute = methodAttribute;
else
{
var parameterNames = callingMethod.GetParameters().Any()
? callingMethod.GetParameters().Select(x => x.Name).Aggregate((combined, next) => combined += $".{next}")
: ".none";
var methodWithParameters = $"{callingMethod.Name}.{parameterNames}";
return methodWithParameters;
// then look for the first class with the attribute, there can be only one
var classAttribute = methods.FirstOrDefault(m => m.ReflectedType != null && m.ReflectedType.GetCustomAttribute<TAttribute>() != null)?.ReflectedType?.GetCustomAttribute<TAttribute>();
tAttribute = classAttribute;
}
return tAttribute?.CustomValue;
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;

namespace Serilog.Sinks.EventGrid
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class EventGridSubjectAttribute : Attribute, IEventGridAttribute
{
public string CustomValue { get; }

public EventGridSubjectAttribute(string customValue)
{
CustomValue = customValue;
}

public EventGridSubjectAttribute() { }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;

namespace Serilog.Sinks.EventGrid
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class EventGridTypeAttribute : Attribute, IEventGridAttribute
{
public string CustomValue { get; }

public EventGridTypeAttribute(string customValue)
{
CustomValue = customValue;
}

public EventGridTypeAttribute() { }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Serilog.Sinks.EventGrid
{
public interface IEventGridAttribute
{
string CustomValue { get; }
}
}

0 comments on commit 54f1cfb

Please sign in to comment.