Conference: dotnetdays 2020
Location: Iaşi, Romania
Abstract: Ever had production problems and found that you cannot debug to find the problem? Or that you need to find out where potential issues are coming from in your Azure cloud solution and you have no idea what is happening?
Your applications need to be instrumented with logging, tracing and metrics, so you can see what is going on where. In .NET Core logging and tracing are built into the framework. We will have a look at the differences between logging, tracing and instrumentation in general.
You will learn how to use .NET Core to implement logging and tracing with best practices, do semantic logging, work with logging factories, trace providers. Also, you will learn how to instrument using Application Insights and add W3C compliant tracing for correlation across cloud resources in a distributed application.
Finally, we will put everything together to see how your logs and traces can give a rich way to get insights into your applications and services running in the Azure cloud or container based solutions.
7. Choosing correct type of instrumentation
Log
• What
happened?
• Errors and
warnings and
state changes
• Important
state changes
worth
registering
• Always logged
Trace
• How did it
happen?
• Circumstantial
data for
following flow
• Available on
request
• Publish/
subscribe
model mostly
• High volume
Metric
• How much is
happening?
• Numerical
information of
events
• Suitable for
aggregation
and trends
Health
• How is it
doing?
• Information
indicating
health status
• Internally
determined by
component
Audit
• Who made it
happen?
• Data
regarding
actions
performed by
someone
• Always
• Security and
identity
related
• Proof for non-
repudiability
18. Scopes
Groups a set of logical operations
Requires setting options to include scope for provider
logging.AddConsole(options => options.IncludeScopes = true);
using (logger.BeginScope("Message attached to logs created in the using block"))
{
logger.LogInformation(LoggingEvents.NewHighScore, “New high score {score}", highScore);
var game = gameRepository.Find(gameId);
if (game == null)
{
logger.LogWarning(LoggingEvents.GameNotFound, "GetById({game}) not found", gameId);
return NotFound();
}
}
19. Logging guidance
Separation of concerns
Choose your log severity level carefully
Use event IDs when possible
Log messages are not for UI
When in doubt, be generous on logging
22. Diagnostics Trace
High volume noise to follow flow
Publish/subscribe
System.Diagnostics namespace
Trace and TraceSource entrypoints
Uses activities under the cover
24. Activities
Ambient contextual data
Activity.Current
Used for correlating events
Parent/Child relationship
var activity = new Activity("SearchEngine.Run");
activity.SetStartTime(DateTime.Now);
activity.Start();
activity.Track...();
25. Available trace listeners
Namespace Class .NET version
System.Diagnostics DefaultTraceListener Core 1.0+
TextWriterTraceListener Core 1.0+
EventLogTraceListener Core 3.0
ConsoleTraceListener Core 3.0
DelimitedListTraceListener Core 1.0+
XmlWriterTraceListener Core 3.0
EventSchemaTraceListener .NET FX 3.5+
System.Diagnostics.Eventing EventProviderTraceListener .NET FX 3.5+
System.Web IisTraceListener .NET FX 2.0+
WebPageTraceListener .NET FX 2.0+
Microsoft.VisualBasic.Logging FileLogTraceListener .NET FX 2.0+
From .NET Framework 2.0 to .NET Core 3.0
29. Health check publishers
Pushes out health
info periodically
Options
ASP.NET Core application
DefaultHealthCheckService
HealthCheckPublisher
HostedService
IEnumerable<IHealthCheckPublisher>
services.AddHealthChecks()
.AddApplicationInsightsPublisher()
.AddPrometheusGatewayPublisher(
"http://pushgateway:9091/metrics",
"pushgateway") IHealthCheckPublisher
30. Probing containers to check for availability and health
Readiness and liveness
Kubernetes node
Kubernetes node
Kubernetes nodes
Containers
Readiness
Liveliness
31. Implementing readiness and liveliness
1. Add health checks with tags
2. Register multiple endpoints
with filter using
Options predicate
/api/v1/…
/health
/health/ready
/health/lively
app.UseHealthChecks("/health/ready",
new HealthCheckOptions() {
Predicate = reg => reg.Tags.Contains("ready")
});
services.AddHealthChecks()
.AddCheck<CircuitBreakerHealthCheck>(
"circuitbreakers",
tags: new string[] { "ready" });
app.UseHealthChecks("/health/lively",
new HealthCheckOptions() {
Predicate = _ => true
});