Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions docs/core/diagnostics/diagnostic-port.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
title: Diagnostic Port
description: Learn about .NET Core diagnostic ports
ms.date: 4/11/2022
ms.topic: overview
---

# Diagnostic Port

**This article applies to: ✔️** .NET Core 3.1 and later versions

The .NET Core runtime exposes a service endpoint that allows other processes to send diagnostic commands and receive responses over an [IPC channel](https://en.wikipedia.org/wiki/Inter-process_communication). This endpoint is called a diagnostic port. Some of the commands that can be sent to the diagnostic port are capturing a memory dump, starting an [EventPipe](./eventpipe.md) trace, or requesting the command-line used to launch the app. The diagnostic port supports different transports depending on runtime implementation and platform. Currently the CoreCLR runtime implementation on Windows uses Named Pipes and on other platforms uses Unix Domain Sockets. The Mono runtime implementation on Android, iOS, and tvOS uses TCP/IP. The channel uses a [custom binary protocol](https://github.com/dotnet/diagnostics/blob/main/documentation/design-docs/ipc-protocol.md). Most developers will never directly interact with the underlying channel and protocol, but rather will use GUI or CLI tools that communicate on their behalf. For example the [dotnet-dump](./dotnet-dump.md) and [dotnet-trace](./dotnet-trace.md) tools abstract sending protocol commands to capture dumps and start traces. For developers that want to write custom tooling the [Microsoft.Diagnsotics.NETCore.Client NuGet package](./diagnostics-client-library.md) provides a .NET API abstraction of the underlying transport and protocol.

## Security Considerations

The diagnostic port exposes sensitive information about a running application. If an untrusted user gains access to this channel they could observe detailed program state, including any secrets which are in memory, and arbitrarily modify the execution of the program. On the CoreCLR runtime the default diagnostic port is configured to only be accessible by the same user account which launched the app or by an account with super-user permissions. If your security model does not trust other processes with the same user account credentials all diagnostic ports can be disabled by setting environment variable `DOTNET_EnableDiagnostics=0`. Doing this will block your ability to use external tooling such as .NET debugging or any of the dotnet-* diagnostic tools.

[!INCLUDE [complus-prefix](../../../includes/complus-prefix.md)]

## Default Diagnostic Port (CoreCLR only)

The CoreCLR runtime has one diagnostic port open by default at a well-known endpoint. This is the port that the dotnet-* diagnostic tools are connecting to automatically when they haven't been explicitly configured to use an alternate port. The endpoint is:

- Windows - Named Pipe `\\.\pipe\dotnet-diagnostic-{pid}`
- Other OSes - Unix Domain Socket `{temp}/dotnet-diagnostic-{pid}-{disambiguation_key}-socket`

`{pid}` is the process id written in decimal, `{temp}` is the `TMPDIR` environment variable or the value `/tmp` if `TMPDIR` is undefined/empty, and `{disambiguation_key}` is the process start time written in decimal. On MacOS and NetBSD the process start time is number of seconds since UNIX epoch time and on all other platforms it is jiffies since boot time.

## Suspending the runtime at startup

By default the runtime executes managed code as soon as it starts, regardless whether any diagnostic tools have connected to the diagnostic port. Sometime it is useful to have the runtime wait to run managed code until after a diagnostic tool is connected to observe the initial program behavior. Setting environment variable `DOTNET_DefaultDiagnosticPortSuspend=1` causes the runtime to wait until a tool connects to the default port. If no tool is attached after several seconds the runtime prints a warning message to the console explaining that it is still waiting for a tool to attach.

## Configuring additional diagnostic ports

> [!IMPORTANT]
> This works for apps running .NET 5 or later only.

Both the Mono and CoreCLR runtimes can use custom configured diagnostic ports. For CoreCLR these ports are in addition to the default port that remains available. There are a few common reasons this is useful:

- For Mono there is no default port so configuring a port is necessary to use diagnostic tools.
- In environments with containers or firewalls you may want to set up a predictable endpoint address that doesn't vary based on process id as CoreCLR's default port does. Then the custom port can be explicitly added to an allow list or proxied across some security boundary.
- For monitoring tools it is useful to have the tool listen on an endpoint and the runtime actively attempts to connect to it. This avoids needing the monitoring tool to continuously poll for new apps starting. In environments where the default diagnostic port isn't accessible it also avoids needing to configure the monitor with a custom endpoint for each monitored app.

In each communication channel between a diagnostic tool and the .NET runtime, one side needs to be the listener and it waits for the other side to connect. The runtime can be configured to act in either role for each port. Ports can also be independently configured to suspend at startup waiting for a diagnostic tool to issue a resume command. Ports configured to connect will repeat their connection attempts indefinitely if the remote endpoint isn't listening or if the connection is lost, but the app does not automatically suspend managed code while waiting to establish that connection. If you want the app to wait for a connection to be established use the suspend at startup option.

Custom ports are configured using the `DOTNET_DiagnosticPorts` environment variable. This variable should be set to a semi-colon delimited list of port descriptions. Each port description consists of an endpoint address and optional modifiers that control the runtime's connect or listen role and if the runtime should suspend on startup. On Windows CoreCLR the endpoint address is the name of a named pipe without the `\\.\pipe\` prefix. On CoreCLR for other OSes it is the full path to a Unix Domain Socket. On Mono the address is an IP and port. For example:

1. `DOTNET_DiagnosticPorts=my_diag_port1` - (Windows CoreCLR) The runtime connects to the named pipe `\\.\pipe\my_diag_port1`.
1. `DOTNET_DiagnosticPorts=/foo/tool1.socket;foo/tool2.socket` - (Non-Windows CoreCLR) The runtime connects to both the Unix Domain Sockets `/foo/tool1.socket` and `/foo/tool2.socket`.
1. `DOTNET_DiagnosticPorts=127.0.0.1:9000` - (Mono) The runtime connects to IP 127.0.0.1 on port 9000.
1. `DOTNET_DiagnosticPorts=/foo/tool1.socket,listen,suspend` - (Non-Windows CoreCLR) This example has the `listen` and `suspend` modifiers. The runtime creates and listens to Unix Domain Socket `/foo/tool1.socket` instead of connecting to it. It also waits to run managed code until some diagnostic tool sends a resume command to `/foo/tool1.socket`.

The complete syntax for a port is `address[,(listen|connect)][,(suspend|nosuspend)]`. `connect` is the default if neither `connect` or `listen` is specified. `nosuspend` is the default if neither `suspend` or `nosuspend` is specified.

## Usage in dotnet diagnostic tools

Tools such as [dotnet-dump](./dotnet-dump.md), [dotnet-counters](./dotnet-counters.md), or [dotnet-trace](./dotnet-trace.md) all support `collect` or `monitor` verbs which communicate to a .NET app via the diagnostic port. When these tools are using the `--processId` argument the tool automatically computes the default diagnostic port address and connects to it. When specifying the `--diagnostic-port` argument the tool listens at the given address and you should use `DOTNET_DiagnosticPorts` environment variable to configure your app to connect. For a complete example with dotnet-counters see [Using the Diagnostic Port](./dotnet-counters.md#using-diagnostic-port).

## Using ds-router to proxy the diagnostic port

All of the dotnet-* diagnostic tools expect to connect to a diagnostic port which is a local Named Pipe or Unix Domain Socket. Mono often runs on isolated hardware or in emulators which need a proxy to become accessible. The [dotnet-dsrouter tool](./dotnet-dsrouter.md) can proxy a local Named Pipe or Unix Domain Socket to TCP so that the tools can also be used with Mono. See the docs for [dotnet-dsrouter](./dotnet-dsrouter.md) to learn more.
2 changes: 1 addition & 1 deletion docs/core/diagnostics/dotnet-counters.md
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ dotnet-counters ps [-h|--help]
> [!IMPORTANT]
> This works for apps running .NET 5 or later only.

Diagnostic port is a new runtime feature that was added in .NET 5 that allows you to start monitoring or collecting counters from app startup. To do this using `dotnet-counters`, you can either use `dotnet-counters <collect|monitor> -- <command>` as described in the examples above, or use the `--diagnostic-port` option.
[Diagnostic port](./diagnostic-port.md) is a new runtime feature that was added in .NET 5 that allows you to start monitoring or collecting counters from app startup. To do this using `dotnet-counters`, you can either use `dotnet-counters <collect|monitor> -- <command>` as described in the examples above, or use the `--diagnostic-port` option.

Using `dotnet-counters <collect|monitor> -- <command>` to launch the application as a child process is the simplest way to quickly monitor it from its startup.

Expand Down
2 changes: 1 addition & 1 deletion docs/core/diagnostics/dotnet-trace.md
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ You can stop collecting the trace by pressing `<Enter>` or `<Ctrl + C>` key. Doi
> [!IMPORTANT]
> This works for apps running .NET 5 or later only.

Diagnostic port is a new runtime feature that was added in .NET 5 that allows you to start tracing from app startup. To do this using `dotnet-trace`, you can either use `dotnet-trace collect -- <command>` as described in the examples above, or use the `--diagnostic-port` option.
[Diagnostic port](./diagnostic-port.md) is a new runtime feature that was added in .NET 5 that allows you to start tracing from app startup. To do this using `dotnet-trace`, you can either use `dotnet-trace collect -- <command>` as described in the examples above, or use the `--diagnostic-port` option.

Using `dotnet-trace <collect|monitor> -- <command>` to launch the application as a child process is the simplest way to quickly trace the application from its startup.

Expand Down
4 changes: 2 additions & 2 deletions docs/core/diagnostics/eventpipe.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ This article is a high-level overview of EventPipe. It describes when and how to

EventPipe aggregates events emitted by runtime components - for example, the Just-In-Time compiler or the garbage collector - and events written from [EventSource](xref:System.Diagnostics.Tracing.EventSource) instances in the libraries and user code.

The events are then serialized and can be written directly to a file or consumed through a Diagnostics Port from out-of-process. On Windows, Diagnostic Ports are implemented as `NamedPipe`s. On non-Windows platforms, such as Linux or macOS, it is implemented using Unix Domain Sockets. For more information about the Diagnostics Port and how to interact with it via its custom inter-process communication protocol, see the [diagnostics IPC protocol documentation](https://github.com/dotnet/diagnostics/blob/main/documentation/design-docs/ipc-protocol.md).
The events are then serialized in the `.nettrace` file format and can be written directly to a file or streamed through a [diagnostic port](./diagnostic-port.md) for out-of-process consumption.

EventPipe then writes the serialized events in the `.nettrace` file format, either as a stream via Diagnostic Ports or directly to a file. To learn more about the EventPipe serialization format, refer to the [EventPipe format documentation](https://github.com/microsoft/perfview/blob/main/src/TraceEvent/EventPipe/EventPipeFormat.md).
To learn more about the EventPipe serialization format, refer to the [EventPipe format documentation](https://github.com/microsoft/perfview/blob/main/src/TraceEvent/EventPipe/EventPipeFormat.md).

## EventPipe vs. ETW/LTTng

Expand Down
22 changes: 14 additions & 8 deletions docs/core/tools/dotnet-environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,17 +156,23 @@ When <xref:System.Console.IsOutputRedirected?displayProperty=nameWithType> is `t

### `DOTNET_DiagnosticPorts`

Configures .NET processes to connect to [dotnet monitor](https://github.com/dotnet/dotnet-monitor/blob/main/documentation/configuration.md#connection-mode) when dotnet monitor is in Listen mode.
Configures alternate endpoints where diagnostic tools can communicate with the .NET runtime. See the [Diagnostic Port documentation](../diagnostics/diagnostic-port.md) for more information.

### Mono-specific variables
### `DOTNET_DefaultDiagnosticPortSuspend`

- `DOTNET_DefaultDiagnosticPortSuspend`: Configures the runtime to pause during startup and wait for the _Diagnostics IPC ResumeStartup_ command from the specified diagnostic port.
- `DOTNET_EnableDiagnostics`: When set to `1`, enables Mono diagnostics.
- `DOTNET_EnableEventPipe`: When set to `1`, enables the Mono event pipe.
- `DOTNET_EventPipeOutputPath`: The output path for the Mono event pipe.
- `DOTNET_EventPipeOutputStreaming`: When set to `1`, enables Mono event pipe output streaming.
Configures the runtime to pause during startup and wait for the _Diagnostics IPC ResumeStartup_ command from the specified diagnostic port when set to 1. Defaults to 0. See the [Diagnostic Port documentation](../diagnostics/diagnostic-port.md) for more information.

For more information, see [.NET runtime: Mono diagnostics and tracing](https://github.com/dotnet/runtime/blob/main/docs/design/mono/diagnostics-tracing.md).
### `DOTNET_EnableDiagnostics`

When set to `1`, enables debugging, profiling, and other diagnostics via the [Diagnostic Port](../diagnostics/diagnostic-port.md). Defaults to 1.

### EventPipe variables

See [EventPipe environment variables](../diagnostics/eventpipe.md#trace-using-environment-variables) for more information.

- `DOTNET_EnableEventPipe`: When set to `1`, enables tracing via EventPipe.
- `DOTNET_EventPipeOutputPath`: The output path where the trace will be written.
- `DOTNET_EventPipeOutputStreaming`: When set to `1`, enables streaming to the output file while the app is running. By default trace information is accumulated in a circular buffer and the contents are written at app shutdown.

## .NET SDK and CLI environment variables

Expand Down