.NET (Core / 5+)

.NET Configuration

Ship logs and traces from ASP.NET to Logit.io

Follow the steps below to send your observability data to Logit.io

Logs

Use Serilog to send .NET logs to your Logit.io Stack.

Install Integration

Please click on the Install Integration button to configure your stack for this source.

Install

If using Visual Studio, create a new application using the ASP.NET Core Web App (Model-View-Controller) template.

If using a terminal application e.g. Powershell run the following command (where 'SerilogTestApp' is the name of the application you want to create):

dotnet new mvc -n SerilogTestApp

You will need to use NuGet or the command line to install three Serilog packages: Serilog.AspNetCore, Serilog.Extensions.Hosting and Serilog.Sinks.Network to send logs using TCP/TLS or UDP.

In Powershell:

dotnet add package Serilog.AspNetCore
dotnet add package Serilog.Extensions.Hosting
dotnet add package Serilog.Sinks.Network

If you are using Visual Studio, navigate to Tools -> NuGet Package Manager -> Manage NuGet packages for solution, browse for the 3 packages mentioned above and install them in your new application.

Configuring Serilog

Add Serilog settings to your appsettings.json file:

"Serilog": {
"Using": [ "Serilog.Sinks.Network" ],
"MinimumLevel": "Debug",
"WriteTo": [
  {
  "Name": "TCPSink",
  "Args": { "uri": "tls://@logstash.host:@logstash.sslPort" }
  }
],
"Enrich": [ "FromLogContext" ]
}

Using Serilog

Inside Program.cs, add Serilog to the WebApplication build process. Below is the updated Program.cs code in full:

using Serilog;
 
var builder = WebApplication.CreateBuilder(args);
 
builder.Host.UseSerilog((hostContext, _, configuration) =>
{
    configuration.ReadFrom.Configuration(hostContext.Configuration);
});
 
// Add services to the container.
builder.Services.AddControllersWithViews();
 
var app = builder.Build();
 
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}
 
app.UseHttpsRedirection();
app.UseStaticFiles();
 
app.UseRouting();
 
app.UseAuthorization();
 
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");
 
app.Run();

You can now log from anywhere in your application. For example, the following code will send a warning log to your stack when the application hits the Index action of the Home controller:

using Microsoft.AspNetCore.Mvc;
using SerilogTestApp.Models;
using System.Diagnostics;
 
namespace SerilogTestApp.Controllers
{
    public class HomeController(ILogger<HomeController> logger) : Controller
    {
        public IActionResult Index()
        {
            logger.LogWarning("This is something you need to be warned about!");
            return View();
        }
 
        public IActionResult Privacy()
        {
            return View();
        }
 
        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public IActionResult Error()
        {
            return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
        }
    }
}

Launch Logs to View Data

Run the application and click on the button below to open the log management visualizer:

Launch Logs

You should now see the above log stored in your stack.

APM

Install Integration

Please click on the Install Integration button to configure your stack for this source.

Install

Create a new 'ASP.NET Core Empty' application and use the Nuget Package Manager or the command line to add the following OpenTelemetry packages to the application. Below is what the .csproj ItemGroup element will look like once installed.

<ItemGroup>
  <PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.10.0" />
  <PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.10.0" />
  <PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.10.0" />
  <PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.9.0" />
  <PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.10.0" />
</ItemGroup>

The package versions shown above were the latest at the time of writing but as the .NET Core / 5+ OpenTelemetry APIs are still in development they could have been updated in the meantime.

Configuring AppSettings

appsettings.json
"OpenTelemetry": {
"ServiceName": "Open Telemetry Tracing - Test App",
"OTLP_ENDPOINT_URL": "https://@opentelemetry.endpointAddress",
"Protocol": "https",
"Port": "@opentelemetry.httpsPort",
"Username": "@opentelemetry.username",
"Password": "@opentelemetry.password"
}

Using OpenTelemetry

Copy and Paste the code below into Program.cs. This code is based on the demonstration code used in the Microsoft article found here (opens in a new tab) which also contains additional useful information about using OpenTelemetry with .NET.

Program.cs
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using System.Diagnostics;
using System.Text;
using OpenTelemetry.Exporter;
 
var builder = WebApplication.CreateBuilder(args);
 
// Custom ActivitySource for the application
var greeterActivitySource = new ActivitySource("OtJa.Example");
 
var config = builder.Configuration;
var openTelemetryCongfig = config.GetSection("OpenTelemetry");
var serviceName = openTelemetryCongfig.GetValue<string>("ServiceName");
var tracingOtlpEndpoint = openTelemetryCongfig.GetValue<string>("OTLP_ENDPOINT_URL");
var tracingOtlpProtocol = openTelemetryCongfig.GetValue<string>("Protocol");
var tracingOtlpPort = openTelemetryCongfig.GetValue<string>("Port");
var tracingUsername = openTelemetryCongfig.GetValue<string>("Username");
var tracingPassword = openTelemetryCongfig.GetValue<string>("Password");
 
var otel = builder.Services.AddOpenTelemetry();
 
// Configure OpenTelemetry Resources with the service name
if (serviceName is null)
{
    serviceName = "Logit.NetTestApp";
}
 
otel.ConfigureResource(resource => resource
    .AddService(serviceName: serviceName));
 
// Add Tracing for ASP.NET Core and our custom ActivitySource and export to Jaeger
otel.WithTracing(tracing =>
{
    tracing.AddAspNetCoreInstrumentation();
    tracing.AddHttpClientInstrumentation();
    tracing.AddSource(greeterActivitySource.Name);
    if (tracingOtlpEndpoint != null)
    {
        tracing.AddOtlpExporter(otlpOptions =>
        {
            if (tracingOtlpPort is not null)
            {
                tracingOtlpEndpoint += ":" + tracingOtlpPort;
            }
            otlpOptions.Endpoint = new Uri(tracingOtlpEndpoint);
 
            otlpOptions.Protocol = tracingOtlpProtocol!.ToLower() == "grpc" ? OtlpExportProtocol.Grpc : OtlpExportProtocol.HttpProtobuf;
            string credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{tracingUsername}:{tracingPassword}"));
            otlpOptions.Headers = "Authorization = Basic " + credentials;
        });
    }
    else
    {
        tracing.AddConsoleExporter();
    }
});
 
builder.Services.AddHttpClient();
 
var app = builder.Build();
 
app.MapGet("/", SendGreeting);
app.MapGet("/NestedGreeting", SendNestedGreeting);
 
app.Run();
 
async Task<string> SendGreeting(ILogger<Program> logger)
{
    // Create a new Activity scoped to the method
    using var activity = greeterActivitySource.StartActivity("GreeterActivity");
 
    // Log a message
    logger.LogInformation("Sending greeting");
 
    // Add a tag to the Activity
    activity?.SetTag("greeting", "Hello World!");
 
    return "Hello World!";
}
 
async Task SendNestedGreeting(int nestlevel, ILogger<Program> logger, HttpContext context, IHttpClientFactory clientFactory)
{
    // Create a new Activity scoped to the method
    using var activity = greeterActivitySource.StartActivity("GreeterActivity");
 
    if (nestlevel <= 5)
    {
        // Log a message
        logger.LogInformation("Sending greeting, level {nestlevel}", nestlevel);
 
        // Add a tag to the Activity
        activity?.SetTag("nest-level", nestlevel);
 
        await context.Response.WriteAsync($"Nested Greeting, level: {nestlevel}\r\n");
 
        if (nestlevel > 0)
        {
            var request = context.Request;
            var url = new Uri($"{request.Scheme}://{request.Host}{request.Path}?nestlevel={nestlevel - 1}");
 
            // Makes an http call passing the activity information as http headers
            var nestedResult = await clientFactory.CreateClient().GetStringAsync(url);
            await context.Response.WriteAsync(nestedResult);
        }
    }
    else
    {
        // Log a message
        logger.LogError("Greeting nest level {nestlevel} too high", nestlevel);
        await context.Response.WriteAsync("Nest level too high, max is 5");
    }
}

Run the application and two traces will have been sent to your Stack.

Launch Logit.io to view your traces

Launch APM

How to diagnose no data in Stack

If you don't see data appearing in your stack after following this integration, take a look at the troubleshooting guide for steps to diagnose and resolve the problem or contact our support team and we'll be happy to assist.

If you need any help with migrating your .NET Core data to Logit.io we are here to help. Feel free to get in touch with our support team via Intercom and we will be happy to assist.