> ## 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.
