---
title: C# Log Collection
description: Datadog, the leading service for cloud-scale monitoring.
breadcrumbs: Docs > Log Management > Log Collection and Integrations > C# Log Collection
---

# C# Log Collection

To send your C# logs to Datadog, use one of the following approaches:

- Log to a file and then tail that file with your Datadog Agent.
- Enable Agentless logging.
- Use the Serilog sink.

## File-tail logging with the Datadog Agent{% #file-tail-logging-with-the-datadog-agent %}

The recommended approach for C# log collection is to output your logs to a file and then [tail](https://docs.datadoghq.com/glossary/#tail) that file with your Datadog Agent. This enables the Datadog Agent to enrich the logs with additional metadata.

Datadog strongly encourages setting up your logging library to produce your logs in JSON format to avoid the need for [custom parsing rules](https://docs.datadoghq.com/logs/log_configuration/parsing).

File-tail logging supports the following frameworks:

- Serilog
- NLog
- log4net

### Configure your logger{% #configure-your-logger %}

{% tab title="Serilog" %}
Like many other libraries for .NET, Serilog provides diagnostic logging into files, the console, and elsewhere. It has a clean API and is portable between recent .NET platforms.

Unlike other logging libraries, Serilog is built with powerful structured event data in mind.

To install Serilog with NuGet, run the following command in the Package Manager Console:

```text
PM> Install-Package Serilog.Sinks.File
```

Then, add the following code to initialize the logger directly in your application:

```csharp
// Instantiate the logger
var log = new LoggerConfiguration()  // using Serilog;

    // using Serilog.Formatting.Json;
    .WriteTo.File(new JsonFormatter(renderMessage: true), "log.json")

    // using Serilog.Formatting.Compact;
    // .WriteTo.File(new RenderedCompactJsonFormatter(), "log.json")

    .CreateLogger();

// An example
var position = new { Latitude = 25, Longitude = 134 };
var elapsedMs = 34;

log.Information("Processed {@Position} in {Elapsed:000} ms.", position, elapsedMs);
```

In the `log.json` file, confirm the logger instantiated successfully:

- If using `JsonFormatter(renderMessage: true)`, look for the following event for confirmation:

```json
{
  "MessageTemplate": "Processed {@Position} in {Elapsed:000} ms.",
  "Level": "Information",
  "Timestamp": "2016-09-02T15:02:29.648Z",
  "Renderings": {"Elapsed": [{"Format": "000", "Rendering": "034"}]},
  "RenderedMessage":"Processed { Latitude: 25, Longitude: 134 } in 034 ms.",
  "Properties": {"Position": {"Latitude": 25, "Longitude": 134}, "Elapsed": 34}
}
```

- If using `RenderedCompactJsonFormatter()`, look for the following event for confirmation:

```json
{
  "@t": "2020-05-20T04:15:28.6898801Z",
  "@m": "Processed { Latitude: 25, Longitude: 134 } in 034 ms.",
  "@i": "d1eb2146",
  "Position": {"Latitude": 25, "Longitude": 134 },
  "Elapsed": 34
}
```

{% /tab %}

{% tab title="NLog" %}
NLog is a logging platform for .NET with rich log routing and management capabilities. It can help you produce and manage high-quality logs for your application regardless of its size or complexity.

To install NLog using NuGet, run the following command in the Package Manager Console:

```text
PM> Install-Package NLog
```

Once the library is in your classpath, attach the following layout to any target. Edit or add a `NLog.config` file to the project root path. Then copy/paste the following code in it (*Logs are written into the `application-logs.json` file*):

```xml
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <!--
  See https://github.com/nlog/nlog/wiki/Configuration-file
  for information on customizing logging rules and outputs.
   -->
  <targets async="true">
    <!-- Write logs as Json into a file -->
    <target name="json-file" xsi:type="File" fileName="application-logs.json">
      <layout xsi:type="JsonLayout">
        <attribute name="date" layout="${date:universalTime=true:format=o}" />
        <attribute name="level" layout="${level:upperCase=true}"/>
        <attribute name="message" layout="${message}" />
        <attribute name="exception" layout="${exception:format=ToString}" />
      </layout>
    </target>

  </targets>
  <rules>
    <!-- Log all events to the json-file target -->
    <logger name="*" writeTo="json-file" minlevel="Trace" />
  </rules>
</nlog>
```

To fire and log your first events, add this to your code:

```csharp
using NLog;

namespace Datadog
{
    class Program
    {
        // Initialize a logger
        private static Logger logger = LogManager.GetCurrentClassLogger();

        static void Main(string[] args)
        {
            // Log a simple debug message
            logger.Debug("This is my first step");

            // your code continues here ...
        }
    }
}
```

{% /tab %}

{% tab title="Log4Net" %}
Log4Net is a logging platform for .NET inspired from Log4j with rich log routing and management capabilities. It can help you produce and manage high-quality logs for your application regardless of its size or complexity.

To install Log4Net, run the following command in the Package Manager Console:

```text
PM> Install-Package log4net
PM> Install-Package log4net.Ext.Json
```

Once the library is installed, attach the following layout to any target. Edit the `App.config` of your project and add the following section:

```xml
<?xml version="1.0" encoding="utf-8"?>
<configuration>

  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configSections>

  <log4net>
    <root>
      <level value="DEBUG" />
      <appender-ref ref="JsonFileAppender" />
    </root>
    <appender name="JsonFileAppender" type="log4net.Appender.FileAppender">
      <threshold value="DEBUG"/>
      <file value="application-logs.json" />
      <encoding type="System.Text.UTF8Encoding" />
      <appendToFile value="true" />
      <layout type="log4net.Layout.SerializedLayout, log4net.Ext.Json">
        <decorator type="log4net.Layout.Decorators.StandardTypesDecorator, log4net.Ext.Json" />
        <default />
        <!--explicit default members-->
        <remove value="ndc" />
        <remove value="message" />
        <!--remove the default preformatted message member-->
        <member value="message:messageobject" />
        <!--add raw message-->
      </layout>
    </appender>
  </log4net>

  <!-- The rest of your configuration starts here ... -->
```

Instantiate your logger and start to fire your events:

```csharp
using log4net;

namespace Datadog
{
    class Program
    {
        // Get the current class logger
        private static ILog logger = LogManager.GetLogger(typeof(Program));

        static void Main(string[] args)
        {

           // Load the configure fom App.config
           XmlConfigurator.Configure();

           // Log a simple debug message
           logger.Debug("This is my first debug message");

           // your code continues here ...
        }
    }
}
```

If you have followed the instructions you should see in your file (for example `C:\Projects\Datadog\Logs\log.json`) the following event:

```json
{
  "level": "DEBUG",
  "message": "This is my debug message",
  "date": "2016-05-24 15:53:35.7175",
  "appname": "Datadog.vshost.exe",
  "logger": "Datadog.Program",
  "thread": "10"
}
```

If, despite the benefits of logging in JSON, you wish to log in raw string format, try updating the `log4net conversion pattern` to automatically parse your logs with the C# integration Pipeline as follows:

```text
<param name="ConversionPattern" value="%date{yyyy-MM-dd HH:mm:ss.SSS} %level [%thread] %logger %method:%line - %message%n" />
```

{% /tab %}

### Configure the Datadog Agent{% #configure-the-datadog-agent %}

Once [log collection is enabled](https://docs.datadoghq.com/agent/logs/?tab=tailfiles#activate-log-collection), set up [custom log collection](https://docs.datadoghq.com/agent/logs/?tab=tailfiles#custom-log-collection) to tail your log files and send them to Datadog.

1. Create a `csharp.d/` folder in the `conf.d/` [Agent configuration directory](https://docs.datadoghq.com/agent/configuration/agent-configuration-files/?tab=agentv6v7#agent-configuration-directory).

1. Create a `conf.yaml` file in `csharp.d/` with the following content:

   ```yaml
   init_config:
   
   instances:
   
   ##Log section
   logs:
   
     - type: file
       path: "<path_to_your_csharp_log>.log"
       service: <service_name>
       source: csharp
       sourcecategory: sourcecode
       # For multiline logs, if they start by the date with the format yyyy-mm-dd uncomment the following processing rule
       #log_processing_rules:
       #  - type: multi_line
       #    name: new_log_start_with_date
       #    pattern: \d{4}\-(0?[1-9]|1[012])\-(0?[1-9]|[12][0-9]|3[01])
   ```

1. Make sure the Agent user has read access permissions to the log file.

1. [Restart the Agent](https://docs.datadoghq.com/agent/configuration/agent-commands/?tab=agentv6v7#restart-the-agent).

1. Run the [Agent's status subcommand](https://docs.datadoghq.com/agent/configuration/agent-commands/?tab=agentv6v7#agent-status-and-information) and look for `csharp` under the `Checks` section to confirm logs are successfully submitted to Datadog.

If logs are in JSON format, Datadog automatically [parses the log messages](https://docs.datadoghq.com/logs/log_configuration/parsing/?tab=matchers) to extract log attributes. Use the [Log Explorer](https://docs.datadoghq.com/logs/explorer/#overview) to view and troubleshoot your logs.

### Connect your service across logs and traces{% #connect-your-service-across-logs-and-traces %}

If APM is enabled for this application, connect your logs and traces by automatically adding trace IDs, span IDs, `env`, `service`, and `version` to your logs by [following the APM .NET instructions](https://docs.datadoghq.com/tracing/other_telemetry/connect_logs_and_traces/dotnet/)

**Note**: If the APM tracer injects `service` into your logs, it overrides the value set in the agent configuration.

## Agentless logging with APM{% #agentless-logging-with-apm %}

It is possible to stream logs from your application to Datadog directly, without making any code changes, using the .NET APM automatic instrumentation library. This approach sends logs directly to Datadog, so it does not benefit from [features such as sensitive data scrubbing](https://docs.datadoghq.com/agent/logs/advanced_log_collection) which are provided by the Datadog Agent. For that reason, we recommend using file tail logging where possible, but it is useful in environments where this is not possible (when using [Azure App Service](https://docs.datadoghq.com/serverless/azure_app_services) for example). It is worth noting that you will still be able to rely on server-side scrubbing capabilities performed by [Sensitive Data Scanner](https://docs.datadoghq.com/security/sensitive_data_scanner/).

Agentless logging (also known as "direct log submission") supports the following frameworks:

- Serilog (v1.0+)
- NLog (v2.1+)
- log4net (v1.0+)
- Microsoft.Extensions.Logging (2.0+)

It does not require modifying your application code, or installing additional dependencies into your application.

{% alert level="danger" %}
**Note:** If you use log4net or NLog, an appender (log4net) or a logger (NLog) must be configured for Agentless logging to be enabled. In those cases, you can either add these extra dependencies, or use [agentless logging with the Serilog sink](https://docs.datadoghq.com/logs/log_collection/csharp/?tab=log4net#agentless-logging-with-serilog-sink) instead.
{% /alert %}

### Configure the APM library{% #configure-the-apm-library %}

Agentless logging is only available when using APM with automatic instrumentation. To get started, instrument your application as described in the following documents:

- [.NET Core/.NET 5+ applications](https://docs.datadoghq.com/tracing/trace_collection/dd_libraries/dotnet-core)
- [.NET Framework applications](https://docs.datadoghq.com/tracing/trace_collection/dd_libraries/dotnet-framework)

After installing, verify you are receiving traces correctly.

### Enable Agentless logging{% #enable-agentless-logging %}

To enable Agentless logging, set the following environment variables:

{% dl %}

{% dt %}
`DD_API_KEY`
{% /dt %}

{% dd %}
Your [Datadog API Key](https://app.datadoghq.com/organization-settings/api-keys) for sending your logs to Datadog.
{% /dd %}

{% dt %}
`DD_SITE`
{% /dt %}

{% dd %}
The name of [your Datadog site](https://docs.datadoghq.com/getting_started/site/). Choose from one of the following examples:**Example**: `datadoghq.com` (US1), `datadoghq.eu` (EU), `us3.datadoghq.com` (US3), `us5.datadoghq.com` (US5), `ddog-gov.com` (US1-FED)**Default**: `datadoghq.com` (US1)
{% /dd %}

{% dt %}
`DD_LOGS_INJECTION`
{% /dt %}

{% dd %}
Enables [connecting logs and traces](https://docs.datadoghq.com/tracing/other_telemetry/connect_logs_and_traces/dotnet/):**Default**: `true`Enabled by default from Tracer version 3.24.0.
{% /dd %}

{% dt %}
`DD_LOGS_DIRECT_SUBMISSION_INTEGRATIONS`
{% /dt %}

{% dd %}
Enables Agentless logging. Enable for your logging framework by setting to `Serilog`, `NLog`, `Log4Net`, or `ILogger` (for `Microsoft.Extensions.Logging`). If you are using multiple logging frameworks, use a semicolon separated list of variables.**Example**: `Serilog;Log4Net;NLog`
{% /dd %}

{% /dl %}

{% alert level="danger" %}
**Note:** If you are using a logging framework in conjunction with `Microsoft.Extensions.Logging`, you will generally need to use the framework name. For example, if you are using [Serilog.Extensions.Logging](https://github.com/serilog/serilog-extensions-logging), you should set `DD_LOGS_DIRECT_SUBMISSION_INTEGRATIONS=Serilog`.
{% /alert %}

Restart your application after setting these environment variables.

### Additional configuration{% #additional-configuration %}

You can further customize some aspects of Agentless log collection using the following environment variables:

{% dl %}

{% dt %}
`DD_LOGS_DIRECT_SUBMISSION_MINIMUM_LEVEL`
{% /dt %}

{% dd %}
Allows filtering logs by level *before* they're sent to Datadog. Set to one of the following values: `Verbose`, `Debug`, `Information`, `Warning`, `Error`, `Critical`. These correspond to the equivalent levels in the supported logging frameworks.**Default**: `Information`
{% /dd %}

{% dt %}
`DD_LOGS_DIRECT_SUBMISSION_HOST`
{% /dt %}

{% dd %}
Set the name of the host machine associated with logs. If not provided, the host name will attempt to be found automatically.**Default**: Determined automatically
{% /dd %}

{% dt %}
`DD_LOGS_DIRECT_SUBMISSION_TAGS`
{% /dt %}

{% dd %}
If specified, adds all of the specified tags to all generated spans. If not provided, will use `DD_TAGS` instead.**Example**: `layer:api, team:intake` Note that the delimiter is a comma and a whitespace: `,`.
{% /dd %}

{% /dl %}

The following configuration values should generally not be modified, but may be set if required.

{% dl %}

{% dt %}
`DD_LOGS_DIRECT_SUBMISSION_URL`
{% /dt %}

{% dd %}
Sets the URL where logs should be submitted. Uses the domain provided in `DD_SITE` by default.**Default**: `:443` (based on `DD_SITE`)
{% /dd %}

{% dt %}
`DD_LOGS_DIRECT_SUBMISSION_SOURCE`
{% /dt %}

{% dd %}
Sets the parsing rule for submitted logs. Should always be set to `csharp`, unless you have a [custom pipeline](https://docs.datadoghq.com/logs/log_configuration/pipelines/?tab=source).**Default**: `csharp`
{% /dd %}

{% dt %}
`DD_LOGS_DIRECT_SUBMISSION_MAX_BATCH_SIZE`
{% /dt %}

{% dd %}
Sets the maximum number of logs to send at one time. Takes into account the [limits in place for the API](https://docs.datadoghq.com/api/latest/logs/#send-logs).**Default**: `1000`
{% /dd %}

{% dt %}
`DD_LOGS_DIRECT_SUBMISSION_MAX_QUEUE_SIZE`
{% /dt %}

{% dd %}
Sets the maximum number of logs to hold in the internal queue at any one time before dropping log messages.**Default**: `100000`
{% /dd %}

{% dt %}
`DD_LOGS_DIRECT_SUBMISSION_BATCH_PERIOD_SECONDS`
{% /dt %}

{% dd %}
Sets the time to wait (in seconds) before checking for new logs to send.**Default**: `1`
{% /dd %}

{% /dl %}

If you are using the `Microsoft.Extensions.Logging` integration, you can filter the logs sent to Datadog using the standard capabilities built-into `ILogger`. Use the key `"Datadog"` to identify the direct-submission provider, and set the minimum log levels for each namespace. For example, adding the following to your `appSettings.json` would prevent sending any logs with a level below `Warning` to Datadog. Introduced in the .NET tracer library v2.20.0.

```json
{
  "Logging": {
    "Datadog": {
      "LogLevel": {
        "Microsoft.AspNetCore": "Warning"
      },
    }
  }
}
```

## Agentless logging with Serilog sink{% #agentless-logging-with-serilog-sink %}

{% alert level="info" %}
Since `0.2.0`, you can configure the Datadog sink by using an `appsettings.json` file with the [`Serilog.Setting.Configuration`](https://github.com/serilog/serilog-settings-configuration) package. For more information, see the [`Serilog.Sinks.Datadog.Logs`](https://github.com/DataDog/serilog-sinks-datadog-logs/tree/master?tab=readme-ov-file#serilogsinksdatadoglogs) package.
{% /alert %}

If it is not possible to use file-tail logging or APM Agentless logging, and you are using the `Serilog` framework, then you can use the Datadog [Serilog sink](https://www.nuget.org/packages/Serilog.Sinks.Datadog.Logs) to send logs directly to Datadog.

Install the [Datadog Serilog sink](https://www.nuget.org/packages/Serilog.Sinks.Datadog.Logs) into your application, which sends events and logs to Datadog. By default the sink forwards logs through HTTPS on port 443. Run the following command in the Package Manager Console:

```text
PM> Install-Package Serilog.Sinks.Datadog.Logs
```

Then, initialize the logger directly in your application. Ensure that you [add your `<API_KEY>`](https://app.datadoghq.com/organization-settings/api-keys).

```csharp
using (var log = new LoggerConfiguration()
    .WriteTo.DatadogLogs("<API_KEY>", configuration: new DatadogConfiguration(){ Url = "" })
    .CreateLogger())
{
    // Some code
}
```

New logs are now directly sent to Datadog.

## Further Reading{% #further-reading %}

- [How to collect, customize, and analyze C# logs](https://www.datadoghq.com/blog/c-logging-guide/)
- [Connecting .NET Logs and Traces](https://docs.datadoghq.com/tracing/other_telemetry/connect_logs_and_traces/dotnet/)
- [Learn how to process your logs](https://docs.datadoghq.com/logs/log_configuration/processors)
- [Learn more about parsing](https://docs.datadoghq.com/logs/log_configuration/parsing)
- [Learn how to explore your logs](https://docs.datadoghq.com/logs/explorer/)
- [Perform Log Analytics](https://docs.datadoghq.com/logs/explorer/#visualize)
- [Log Collection Troubleshooting Guide](https://docs.datadoghq.com/logs/faq/log-collection-troubleshooting-guide/)
- [Glossary entry for "tail"](https://docs.datadoghq.com/glossary/#tail)
- [Serilog.Sinks.Datadog.Logs Package](https://github.com/DataDog/serilog-sinks-datadog-logs/)
