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

feat: Ambiguous method definition on LogMetric #424

Merged
merged 17 commits into from
Jul 14, 2022
Merged
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
2 changes: 1 addition & 1 deletion docs/preview/02-Guidance/use-with-dotnet-and-aspnetcore.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public class OrderController : ControllerBase
{"Customer", order.Customer.Name}
};

_logger.LogEvent("Order received", contextualInformation);
_logger.LogCustomEvent("Order received", contextualInformation);
}
}
```
Expand Down
2 changes: 1 addition & 1 deletion docs/preview/02-Guidance/use-with-dotnet-and-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ public class DockerHubMetricScraperFunction
{"Image ID", $"{repoName}/{imageName}"}
};

_logger.LogMetric("Image Pulls", pullCount, contextualInformation);
_logger.LogCustomMetric("Image Pulls", pullCount, contextualInformation);
}
}
```
Expand Down
6 changes: 3 additions & 3 deletions docs/preview/03-Features/making-telemetry-more-powerful.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ var telemetryContext = new Dictionary<string, object>
{"OrderId", "ABC"},
};

logger.LogEvent("Order Created", telemetryContext);
logger.LogCustomEvent("Order Created", telemetryContext);
// Output: "Events Order Created (Context: [Customer, Arcus], [OrderId, ABC])"
```

Expand All @@ -34,7 +34,7 @@ Let's use an example - When measuring a metric you get an understanding of the c
```csharp
using Microsoft.Extensions.Logging;

logger.LogMetric("Orders Received", 133);
logger.LogCustomMetric("Orders Received", 133);
// Log output: "Metric Orders Received: 133 (Context: )"
```

Expand All @@ -51,7 +51,7 @@ var telemetryContext = new Dictionary<string, object>
{ "Customer", "Contoso"},
};

logger.LogMetric("Orders Received", 133, telemetryContext);
logger.LogCustomMetric("Orders Received", 133, telemetryContext);
// Log output: "Metric Orders Received: 133 (Context: [Customer, Contoso])"
```

Expand Down
4 changes: 2 additions & 2 deletions docs/preview/03-Features/writing-different-telemetry-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ Here is how you can report an `Order Created` event:
```csharp
using Microsoft.Extensions.Logging;

logger.LogEvent("Order Created");
logger.LogCustomEvent("Order Created");
// Output: {"EventName": "Order Created", "Context": {}}
```

Expand All @@ -488,7 +488,7 @@ Here is how you can report an `Invoices Received` metric:
```csharp
using Microsoft.Extensions.Logging;

logger.LogMetric("Invoices Received", 133);
logger.LogCustomMetric("Invoices Received", 133);
// Output: {"MetricName": "Invoices Received", "MetricValue": 133, "Timestamp": "03/23/2020 09:32:02 +00:00", "Context: {[TelemetryType, Metric]}}
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public static void LogSecurityEvent(this ILogger logger, string name, Dictionary
context = context ?? new Dictionary<string, object>();
context["EventType"] = "Security";

LogEvent(logger, name, context);
LogCustomEvent(logger, name, context);
}

/// <summary>
Expand All @@ -40,6 +40,25 @@ public static void LogSecurityEvent(this ILogger logger, string name, Dictionary
/// <param name="context">Context that provides more insights on the event that occurred</param>
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="logger"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentException">Thrown when the <paramref name="name"/> is blank.</exception>
public static void LogCustomEvent(this ILogger logger, string name, Dictionary<string, object> context = null)
{
Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry");
Guard.NotNullOrWhitespace(name, nameof(name), "Requires a non-blank event name to track an custom event");

context = context ?? new Dictionary<string, object>();

logger.LogWarning(MessageFormats.EventFormat, new EventLogEntry(name, context));
}

/// <summary>
/// Logs a custom event
/// </summary>
/// <param name="logger">The logger to track the telemetry.</param>
/// <param name="name">Name of the event</param>
/// <param name="context">Context that provides more insights on the event that occurred</param>
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="logger"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentException">Thrown when the <paramref name="name"/> is blank.</exception>
[Obsolete("Use " + nameof(LogCustomEvent) + " instead")]
public static void LogEvent(this ILogger logger, string name, Dictionary<string, object> context = null)
{
Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,26 @@ public static partial class ILoggerExtensions
/// <param name="context">Context that provides more insights on the event that occurred</param>
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="logger"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentException">Thrown when the <paramref name="name"/> is blank.</exception>
public static void LogCustomMetric(this ILogger logger, string name, double value, Dictionary<string, object> context = null)
{
Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry");
Guard.NotNullOrWhitespace(name, nameof(name), "Requires a non-blank name to track a metric");

context = context ?? new Dictionary<string, object>();

LogCustomMetric(logger, name, value, DateTimeOffset.UtcNow, context);
}

/// <summary>
/// Logs a custom metric
/// </summary>
/// <param name="logger">The logger to track the metric.</param>
/// <param name="name">Name of the metric</param>
/// <param name="value">Value of the metric</param>
/// <param name="context">Context that provides more insights on the event that occurred</param>
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="logger"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentException">Thrown when the <paramref name="name"/> is blank.</exception>
[Obsolete("Use " + nameof(LogCustomMetric) + " instead")]
public static void LogMetric(this ILogger logger, string name, double value, Dictionary<string, object> context = null)
{
Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry");
Expand All @@ -42,6 +62,27 @@ public static void LogMetric(this ILogger logger, string name, double value, Dic
/// <param name="context">Context that provides more insights on the event that occurred</param>
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="logger"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentException">Thrown when the <paramref name="name"/> is blank.</exception>
public static void LogCustomMetric(this ILogger logger, string name, double value, DateTimeOffset timestamp, Dictionary<string, object> context = null)
{
Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry");
Guard.NotNullOrWhitespace(name, nameof(name), "Requires a non-blank name to track a metric");

context = context ?? new Dictionary<string, object>();

logger.LogWarning(MessageFormats.MetricFormat, new MetricLogEntry(name, value, timestamp, context));
}

/// <summary>
/// Logs a custom metric
/// </summary>
/// <param name="logger">The logger to track the metric.</param>
/// <param name="name">Name of the metric</param>
/// <param name="value">Value of the metric</param>
/// <param name="timestamp">Timestamp of the metric</param>
/// <param name="context">Context that provides more insights on the event that occurred</param>
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="logger"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentException">Thrown when the <paramref name="name"/> is blank.</exception>
[Obsolete("Use " + nameof(LogCustomMetric) + " instead")]
public static void LogMetric(this ILogger logger, string name, double value, DateTimeOffset timestamp, Dictionary<string, object> context = null)
{
Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,24 @@ await RetryAssertUntilTelemetryShouldBeAvailableAsync(async client =>
});
}

[Fact]
public async Task LogCustomEvent_SinksToApplicationInsights_ResultsInEventTelemetry()
{
// Arrange
string eventName = BogusGenerator.Finance.AccountName();
Dictionary<string, object> telemetryContext = CreateTestTelemetryContext();

// Act
Logger.LogCustomEvent(eventName, telemetryContext);
stijnmoreels marked this conversation as resolved.
Show resolved Hide resolved

// Assert
await RetryAssertUntilTelemetryShouldBeAvailableAsync(async client =>
{
EventsCustomEventResult[] results = await client.GetEventsAsync();
Assert.Contains(results, result => result.CustomEvent.Name == eventName);
});
}

[Fact]
public async Task LogEventWithComponentName_SinksToApplicationInsights_ResultsInTelemetryWithComponentName()
{
Expand Down Expand Up @@ -84,6 +102,29 @@ await RetryAssertUntilTelemetryShouldBeAvailableAsync(async client=>
});
}

[Fact]
public async Task LogCustomEventWithVersion_SinksToApplicationInsights_ResultsInTelemetryWithVersion()
{
// Arrange
var eventName = "Update version";
LoggerConfiguration.Enrich.WithVersion();

// Act
Logger.LogCustomEvent(eventName);

// Assert
await RetryAssertUntilTelemetryShouldBeAvailableAsync(async client =>
{
EventsCustomEventResult[] events = await client.GetEventsAsync();
Assert.Contains(events, ev =>
{
return ev.CustomEvent.Name == eventName
&& ev.CustomDimensions.TryGetValue(VersionEnricher.DefaultPropertyName, out string actualVersion)
&& !String.IsNullOrWhiteSpace(actualVersion);
});
});
}

[Fact]
public async Task LogEventWithCorrelationInfo_SinksToApplicationInsights_ResultsInTelemetryWithCorrelationInfo()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,28 @@ await RetryAssertUntilTelemetryShouldBeAvailableAsync(async client =>
Assert.NotEmpty(results);
});
}

[Fact]
public async Task LogCustomMetric_SinksToApplicationInsights_ResultsInMetricTelemetry()
{
// Arrange
string metricName = "threshold";
double metricValue = 0.25;
Dictionary<string, object> telemetryContext = CreateTestTelemetryContext();

// Act
Logger.LogCustomMetric(metricName, metricValue, telemetryContext);

// Assert
await RetryAssertUntilTelemetryShouldBeAvailableAsync(async client =>
{
var bodySchema = new MetricsPostBodySchema(
id: Guid.NewGuid().ToString(),
parameters: new MetricsPostBodySchemaParameters("customMetrics/" + metricName));

MetricsResultsItem[] results = await client.GetMetricsAsync(bodySchema);
Assert.NotEmpty(results);
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,33 @@ public void LogEvent_WithTelemetryTypeFilter_IgnoresLogEvent()
}
}

[Fact]
public void LogCustomEvent_WithTelemetryTypeFilter_IgnoresLogEvent()
{
// Arrange
string eventName = _bogusGenerator.Random.Word();
string propertyName = _bogusGenerator.Random.Word();
string propertyValue = _bogusGenerator.Random.Word();
var properties = new Dictionary<string, object> { [propertyName] = propertyValue };

var spySink = new InMemoryLogSink();
Logger serilogLogger = new LoggerConfiguration()
.Filter.With(TelemetryTypeFilter.On(TelemetryType.Events))
.WriteTo.Sink(spySink)
.CreateLogger();

using (var factory = new SerilogLoggerFactory(serilogLogger))
{
ILogger logger = factory.CreateLogger<TelemetryTypeFilterTests>();

// Act
logger.LogCustomEvent(eventName, properties);

// Assert
Assert.Empty(spySink.CurrentLogEmits);
}
}

[Theory]
[MemberData(nameof(TelemetryTypesWithoutEvent))]
public void LogEvent_WithTelemetryTypeFilterOnOtherType_DoesNotFilterOutEntry(TelemetryType telemetryType)
Expand Down Expand Up @@ -90,6 +117,39 @@ public void LogEvent_WithTelemetryTypeFilterOnOtherType_DoesNotFilterOutEntry(Te
}
}

[Theory]
[MemberData(nameof(TelemetryTypesWithoutEvent))]
public void LogCustomEvent_WithTelemetryTypeFilterOnOtherType_DoesNotFilterOutEntry(TelemetryType telemetryType)
{
// Arrange
string eventName = _bogusGenerator.Random.Word();
string propertyName = _bogusGenerator.Random.Word();
string propertyValue = _bogusGenerator.Random.Word();
var properties = new Dictionary<string, object> { [propertyName] = propertyValue };

var spySink = new InMemoryLogSink();
Logger serilogLogger = new LoggerConfiguration()
.Filter.With(TelemetryTypeFilter.On(telemetryType, isTrackingEnabled: false))
.WriteTo.Sink(spySink)
.CreateLogger();

using (var factory = new SerilogLoggerFactory(serilogLogger))
{
ILogger logger = factory.CreateLogger<TelemetryTypeFilterTests>();

// Act
logger.LogCustomEvent(eventName, properties);

// Assert
LogEvent logEvent = Assert.Single(spySink.CurrentLogEmits);
Assert.NotNull(logEvent);
string writtenMessage = logEvent.RenderMessage();
Assert.Contains(propertyName, writtenMessage);
Assert.Contains(propertyValue, writtenMessage);
Assert.Contains(TelemetryType.Events.ToString(), writtenMessage);
}
}

[Fact]
public void LogSecurityEvent_WithTelemetryTypeFilter_IgnoresLogEvent()
{
Expand Down Expand Up @@ -178,6 +238,34 @@ public void LogMetric_WithTelemetryTypeFilter_IgnoresMetric()
}
}

[Fact]
public void LogCustomMetric_WithTelemetryTypeFilter_IgnoresMetric()
{
// Arrange
string metricName = _bogusGenerator.Random.Word();
double metricValue = _bogusGenerator.Random.Double();
string propertyName = _bogusGenerator.Random.Word();
string propertyValue = _bogusGenerator.Random.Word();
var properties = new Dictionary<string, object> { [propertyName] = propertyValue };

var spySink = new InMemoryLogSink();
Logger serilogLogger = new LoggerConfiguration()
.Filter.With(TelemetryTypeFilter.On(TelemetryType.Metrics))
.WriteTo.Sink(spySink)
.CreateLogger();

using (var factory = new SerilogLoggerFactory(serilogLogger))
{
ILogger logger = factory.CreateLogger<TelemetryTypeFilterTests>();

// Act
logger.LogCustomMetric(metricName, metricValue, properties);

// Assert
Assert.Empty(spySink.CurrentLogEmits);
}
}

[Theory]
[MemberData(nameof(TelemetryTypesWithoutMetric))]
public void LogMetric_WithTelemetryTypeFilterOnDifferentTyp_DoesNotFilterOutEntry(TelemetryType telemetryType)
Expand Down Expand Up @@ -214,6 +302,42 @@ public void LogMetric_WithTelemetryTypeFilterOnDifferentTyp_DoesNotFilterOutEntr
}
}

[Theory]
[MemberData(nameof(TelemetryTypesWithoutMetric))]
public void LogCustomMetric_WithTelemetryTypeFilterOnDifferentTyp_DoesNotFilterOutEntry(TelemetryType telemetryType)
{
// Arrange
string metricName = _bogusGenerator.Random.Word();
double metricValue = _bogusGenerator.Random.Double();
string propertyName = _bogusGenerator.Random.Word();
string propertyValue = _bogusGenerator.Random.Word();
var properties = new Dictionary<string, object> { [propertyName] = propertyValue };

var spySink = new InMemoryLogSink();
Logger serilogLogger = new LoggerConfiguration()
.Filter.With(TelemetryTypeFilter.On(telemetryType))
.WriteTo.Sink(spySink)
.CreateLogger();

using (var factory = new SerilogLoggerFactory(serilogLogger))
{
ILogger logger = factory.CreateLogger<TelemetryTypeFilterTests>();

// Act
logger.LogCustomMetric(metricName, metricValue, properties);

// Assert
LogEvent logEvent = Assert.Single(spySink.CurrentLogEmits);
Assert.NotNull(logEvent);
string writtenMessage = logEvent.RenderMessage();
Assert.Contains(metricName, writtenMessage);
Assert.Contains(metricValue.ToString(CultureInfo.InvariantCulture), writtenMessage);
Assert.Contains(propertyName, writtenMessage);
Assert.Contains(propertyValue, writtenMessage);
Assert.Contains(TelemetryType.Metrics.ToString(), writtenMessage);
}
}

[Fact]
public void LogRequest_WithTelemetryTypeFilter_FilersInRequest()
{
Expand Down
Loading