> ## Documentation Index
> Fetch the complete documentation index at: https://axiom.co/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Send logs from a .NET app

> This guide explains how to set up and configure logging in a .NET app, and how to send logs to Axiom.

## Prerequisites

* [Create an Axiom account](https://app.axiom.co/register).
* [Create a dataset in Axiom](/reference/datasets#create-dataset) where you send your data.
* [Create an API token in Axiom](/reference/tokens) with permissions to ingest data to the dataset you have created.

- [Install the .NET SDK](https://dotnet.microsoft.com/download).

## Option 1: Using HTTP Client

### Create a new .NET project

Create a new .NET project. In your terminal, go to the directory where you want to create your project. Run the following command to create a new console app named `AxiomLogs`.

```bash  theme={null}
dotnet new console -n AxiomLogs
```

### Install packages

Install the packages for your project. Use the `Microsoft.AspNet.WebApi.Client` package to make HTTP requests to the Axiom API. Run the following command to install the package:

```bash  theme={null}
dotnet add package Microsoft.AspNet.WebApi.Client
```

### Configure the Axiom logger

Create a class to handle logging to Axiom. Create a new file named `AxiomLogger.cs` in your project directory with the following content:

```csharp  theme={null}
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

public static class AxiomLogger
{
    public static async Task LogToAxiom(string message, string logLevel)
    {
        // Create an instance of HttpClient to make HTTP requests
        var client = new HttpClient();

        // Specify the Axiom dataset name and construct the API endpoint URL
        var datasetName = "DATASET_NAME";
        var axiomEdgeDomain = "AXIOM_DOMAIN";
        var axiomUri = $"https://{axiomEdgeDomain}/v1/ingest/{datasetName}";

        // Replace with your Axiom API token
        var apiToken = "API_TOKEN"; // Ensure your API token is correct

        // Create an array of log entries, including the timestamp, message, and log level
        var logEntries = new[]
        {
            new
            {
                timestamp = DateTime.UtcNow.ToString("o"),
                message = message,
                level = logLevel
            }
        };

        // Serialize the log entries to JSON format using System.Text.Json.JsonSerializer
        var content = new StringContent(System.Text.Json.JsonSerializer.Serialize(logEntries), Encoding.UTF8, "application/json");

        // Set the authorization header with the Axiom API token
        client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", apiToken);

        // Make a POST request to the Axiom API endpoint with the serialized log entries
        var response = await client.PostAsync(axiomUri, content);

        // Check the response status code
        if (!response.IsSuccessStatusCode)
        {
            // If the response isn’t successful, print the error details
            var responseBody = await response.Content.ReadAsStringAsync();
            Console.WriteLine($"Failed to send log: {response.StatusCode}\n{responseBody}");
        }
        else
        {
            // If the response is successful, print "Log sent successfully."
            Console.WriteLine("Log sent successfully.");
        }
    }
}
```

<Info>
  Replace `API_TOKEN` with the Axiom API token you have generated. For added security, store the API token in an environment variable.

  Replace `DATASET_NAME` with the name of the Axiom dataset where you send your data.

  Replace `AXIOM_DOMAIN` with the base domain of your edge deployment. For more information, see [Edge deployments](/reference/edge-deployments).
</Info>

### Configure the main program

Now that the Axiom logger is in place, update the main program so it can be used. Open the `Program.cs` file and replace its contents with the following code:

```csharp  theme={null}
using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        // Log the application startup event with an "INFO" log level
        await AxiomLogger.LogToAxiom("Application started", "INFO");

        // Call the SimulateOperations method to simulate various application operations
        await SimulateOperations();

        // Log the .NET runtime version information with an "INFO" log level
        await AxiomLogger.LogToAxiom($"CLR version: {Environment.Version}", "INFO");

        // Log the application shutdown event with an "INFO" log level
        await AxiomLogger.LogToAxiom("Application shutting down", "INFO");
    }

    static async Task SimulateOperations()
    {
        // Log the start of operations with a "DEBUG" log level
        await AxiomLogger.LogToAxiom("Starting operations", "DEBUG");

        // Log the database connection event with a "DEBUG" log level
        await AxiomLogger.LogToAxiom("Connecting to database", "DEBUG");
        await Task.Delay(500); // Simulated delay
        // Log the successful database connection with an "INFO" log level
        await AxiomLogger.LogToAxiom("Connected to database successfully", "INFO");

        // Log the user data retrieval event with a "DEBUG" log level
        await AxiomLogger.LogToAxiom("Retrieving user data", "DEBUG");
        await Task.Delay(1000);
        // Log the number of retrieved user records with an "INFO" log level
        await AxiomLogger.LogToAxiom("Retrieved 100 user records", "INFO");

        // Log the user preference update event with a "DEBUG" log level
        await AxiomLogger.LogToAxiom("Updating user preferences", "DEBUG");
        await Task.Delay(800);
        // Log the successful user preference update with an "INFO" log level
        await AxiomLogger.LogToAxiom("Updated user preferences successfully", "INFO");

        try
        {
            // Log the payment processing event with a "DEBUG" log level
            await AxiomLogger.LogToAxiom("Processing payments", "DEBUG");
            await Task.Delay(1500);
            // Intentionally throw an exception to demonstrate error logging
            throw new Exception("Payment gateway unavailable");
        }
        catch (Exception ex)
        {
            // Log the payment processing failure with an "ERROR" log level
            await AxiomLogger.LogToAxiom($"Payment processing failed: {ex.Message}", "ERROR");
        }

        // Log the email notification sending event with a "DEBUG" log level
        await AxiomLogger.LogToAxiom("Sending email notifications", "DEBUG");
        await Task.Delay(1200);
        // Log the number of sent email notifications with an "INFO" log level
        await AxiomLogger.LogToAxiom("Sent 50 email notifications", "INFO");

        // Log the high memory usage detection with a "WARN" log level
        await AxiomLogger.LogToAxiom("Detected high memory usage", "WARN");
        await Task.Delay(500);
        // Log the memory usage normalization with an "INFO" log level
        await AxiomLogger.LogToAxiom("Memory usage normalized", "INFO");

        // Log the completion of operations with a "DEBUG" log level
        await AxiomLogger.LogToAxiom("Operations completed", "DEBUG");
    }
}
```

This code simulates various app operations and logs messages at different levels (DEBUG, INFO, WARN, ERROR) to Axiom.

### Project file configuration

Ensure your `axiomlogs.csproj` file is configured with the package reference. The file should look like this:

```xml  theme={null}
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="6.0.0" />
  </ItemGroup>

</Project>
```

### Build and run the app

To build and run the app, go to the project directory in your terminal and run the following command:

```bash  theme={null}
dotnet build

dotnet run
```

This command builds the project and runs the app. You see the log messages being sent to Axiom, and the console displays `Log sent successfully.` for each log entry.

## Option 2: Using Serilog

### Install Serilog Packages

Add Serilog and the necessary extensions to your project. You need the `Serilog`, `Serilog.Sinks.Http`, `Serilog.Formatting.Elasticsearch` and `Serilog.Formatting.Json` packages.

```bash  theme={null}
dotnet add package Serilog
dotnet add package Serilog.Sinks.Console
dotnet add package Serilog.Sinks.Http
dotnet add package Serilog.Formatting.Elasticsearch
dotnet add package Microsoft.Extensions.Configuration
```

### Configure Serilog

In your `Program.cs` or a startup configuration file, set up Serilog to use the HTTP sink. Configure the sink to point to the Axiom ingestion API endpoint.

```csharp  theme={null}
using Serilog;
using Serilog.Formatting.Elasticsearch;
using Serilog.Sinks.Http;
using System.Net.Http;
using System.Net.Http.Headers;
using System.IO;
using Microsoft.Extensions.Configuration;

public class AxiomConfig
{
    public const string DatasetName = "DATASET_NAME";
    public const string ApiToken = "API_TOKEN";
    public const string ApiUrl = "https://AXIOM_DOMAIN/v1";
}

public class AxiomHttpClient : IHttpClient
{
    private readonly HttpClient _httpClient;

    public AxiomHttpClient()
    {
        _httpClient = new HttpClient();
        _httpClient.DefaultRequestHeaders.Authorization = 
            new AuthenticationHeaderValue("Bearer", AxiomConfig.ApiToken);
    }

    public void Configure(IConfiguration configuration)
    {
    }

    public async Task<HttpResponseMessage> PostAsync(string requestUri, Stream contentStream, CancellationToken cancellationToken = default)
    {
        var content = new StreamContent(contentStream);
        content.Headers.Add("Content-Type", "application/json");
        return await _httpClient.PostAsync(requestUri, content, cancellationToken).ConfigureAwait(false);
    }

    public void Dispose()
    {
        _httpClient?.Dispose();
    }
}

public class Program
{
    public static async Task Main(string[] args)
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .WriteTo.Console()
            .WriteTo.Http(
                requestUri: $"{AxiomConfig.ApiUrl}/ingest/{AxiomConfig.DatasetName}",
                queueLimitBytes: null,
                textFormatter: new ElasticsearchJsonFormatter(renderMessageTemplate: false, inlineFields: true),
                httpClient: new AxiomHttpClient()
            )
            .CreateLogger();

        try
        {
            Log.Information("Application started on .NET 8");
            await SimulateOperations();
            Log.Information($"Runtime version: {Environment.Version}");
            Log.Information("Application shutting down");
        }
        catch (Exception ex)
        {
            Log.Fatal(ex, "Application terminated unexpectedly");
        }
        finally
        {
            await Log.CloseAndFlushAsync();
        }
    }

    static async Task SimulateOperations()
    {
        Log.Debug("Starting operations");
        Log.Debug("Connecting to database");
        await Task.Delay(500);
        Log.Information("Connected to database successfully");
        
        Log.Debug("Retrieving user data");
        await Task.Delay(1000);
        Log.Information("Retrieved 100 user records");
        
        Log.Debug("Updating user preferences");
        await Task.Delay(800);
        Log.Information("Updated user preferences successfully");

        try
        {
            Log.Debug("Processing payments");
            await Task.Delay(1500);
            throw new Exception("Payment gateway unavailable");
        }
        catch (Exception ex)
        {
            Log.Error(ex, "Payment processing failed: {ErrorMessage}", ex.Message);
        }

        Log.Debug("Sending email notifications");
        await Task.Delay(1200);
        Log.Information("Sent 50 email notifications");
        
        Log.Warning("Detected high memory usage: {UsagePercentage}%", 85);
        await Task.Delay(500);
        Log.Information("Memory usage normalized");
        
        Log.Debug("Operations completed");
    }
}
```

<Info>
  Replace `API_TOKEN` with the Axiom API token you have generated. For added security, store the API token in an environment variable.

  Replace `DATASET_NAME` with the name of the Axiom dataset where you send your data.

  Replace `AXIOM_DOMAIN` with the base domain of your edge deployment. For more information, see [Edge deployments](/reference/edge-deployments).
</Info>

### Project file configuration

Ensure your `axiomlogs.csproj` file is configured with the package references. The file should look like this:

```xml  theme={null}
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <AssemblyName>SerilogApp</AssemblyName>
    <RootNamespace>SerilogApp</RootNamespace>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
    <PackageReference Include="Serilog" Version="3.1.1" />
    <PackageReference Include="Serilog.Formatting.Elasticsearch" Version="10.0.0" />
    <PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
    <PackageReference Include="Serilog.Sinks.Http" Version="9.0.0" />
  </ItemGroup>
</Project>
```

### Build and run the app

To build and run the app, go to the project directory in your terminal and run the following commands:

```bash  theme={null}
dotnet build
dotnet run
```

This command builds the project and runs the app. You see the log messages being sent to Axiom.

## Option 3: Using NLog

### Install NLog Packages

You need NLog and potentially an extension for HTTP targets.

```bash  theme={null}
dotnet add package NLog
dotnet add package NLog.Web.AspNetCore
dotnet add package NLog.Targets.Http
```

### Configure NLog

Set up NLog by creating an `NLog.config` file or configuring it programmatically. Here is an example configuration for `NLog` using an HTTP target:

```xml  theme={null}
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <extensions>
        <add assembly="NLog.Targets.Http" />
    </extensions>
    <targets>
        <target xsi:type="BufferingWrapper"
                name="allLogs"
                flushTimeout="5000">
            <target xsi:type="HTTP" 
                    name="axiom"
                    url="https://AXIOM_DOMAIN/v1/ingest/DATASET_NAME"
                    HttpHeaders="Authorization: Bearer API_TOKEN"
                    contentType="application/json">
                <layout xsi:type="JsonLayout" includeAllProperties="true">
                    <attribute name="timestamp" layout="${date:universalTime=true:format=o}" />
                    <attribute name="level" layout="${level:lowercase=true}" />
                    <attribute name="message" layout="${message}" />
                    <attribute name="exception" layout="${exception:format=toString}" 
                               encode="false" />
                </layout>
            </target>
        </target>
    </targets>
    <rules>
        <logger name="*" minlevel="Trace" writeTo="allLogs" />
    </rules>
</nlog>
```

<Info>
  Replace `API_TOKEN` with the Axiom API token you have generated. For added security, store the API token in an environment variable.

  Replace `DATASET_NAME` with the name of the Axiom dataset where you send your data.

  Replace `AXIOM_DOMAIN` with the base domain of your edge deployment. For more information, see [Edge deployments](/reference/edge-deployments).
</Info>

### Configure the main program

Update the main program to use `NLog`. In your `Program.cs` file:

```csharp  theme={null}
using NLog;
using NLog.Web;

var logger = NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();

class Program
{
    static async Task Main(string[] args)
    {
        logger.Info("Application started");
        await SimulateOperations();
        logger.Info($"CLR version: {Environment.Version}");
        logger.Info("Application shutting down");
    }

    static async Task SimulateOperations()
    {
        logger.Debug("Starting operations");
        logger.Debug("Connecting to database");
        await Task.Delay(500); // Simulated delay
        logger.Info("Connected to database successfully");
        logger.Debug("Retrieving user data");
        await Task.Delay(1000);
        logger.Info("Retrieved 100 user records");
        logger.Debug("Updating user preferences");
        await Task.Delay(800);
        logger.Info("Updated user preferences successfully");

        try
        {
            logger.Debug("Processing payments");
            await Task.Delay(1500);
            throw new Exception("Payment gateway unavailable");
        }
        catch (Exception ex)
        {
            logger.Error($"Payment processing failed: {ex.Message}");
        }

        logger.Debug("Sending email notifications");
        await Task.Delay(1200);
        logger.Info("Sent 50 email notifications");
        logger.Warn("Detected high memory usage");
        await Task.Delay(500);
        logger.Info("Memory usage normalized");
        logger.Debug("Operations completed");
    }
}
```

### Project file configuration

Ensure your `axiomlogs.csproj` file is configured with the package references. The file should look like this:

```xml  theme={null}
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="NLog" Version="4.7.12" />
    <PackageReference Include="NLog.Web.AspNetCore" Version="4.9.3" />
    <PackageReference Include="NLog.Targets.Http" Version="1.0.4" />
  </ItemGroup>

</Project>
```

### Build and run the app

To build and run the app, go to the project directory in your terminal and run the following commands:

```bash  theme={null}
dotnet build
dotnet run
```

This command builds the project and runs the app. You should see the log messages being sent to Axiom.

## Best practices for logging

To make your logging more effective, consider the following best practices:

* Include relevant information such as user IDs, request details, and system state in your log messages to provide context when investigating issues.
* Use different log levels (DEBUG, INFO, WARN, ERROR) to categorize the severity and importance of log messages. This allows you to filter and analyze logs more effectively
* Use structured logging formats like JSON to make it easier to parse and analyze log data

## Conclusion

This guide covers the steps to send logs from a C# .NET app to Axiom. By following these instructions and adhering to logging best practices, you can effectively monitor your app, diagnose issues, and gain valuable insights into its behavior.


Built with [Mintlify](https://mintlify.com).