Partilhar via


Portas de diagnóstico

Este artigo aplica-se a: ✔️ .NET Core 3.1 e versões posteriores

O tempo de execução do .NET expõe um ponto de extremidade de serviço que permite que outros processos enviem comandos de diagnóstico e recebam respostas por um canal IPC. Esse ponto de extremidade é chamado de porta de diagnóstico. Os comandos podem ser enviados para a porta de diagnóstico para:

  • Capture um despejo de memória.
  • Inicie um rastreamento do EventPipe .
  • Solicite a linha de comando usada para iniciar o aplicativo.

A porta de diagnóstico suporta diferentes transportes, dependendo da plataforma. Atualmente, as implementações de tempo de execução CoreCLR e Mono usam Named Pipes no Windows e Unix Domain Sockets no Linux e macOS. A implementação de tempo de execução Mono no Android, iOS e tvOS usa TCP/IP. O canal usa um protocolo binário personalizado. A maioria dos desenvolvedores nunca interagirá diretamente com o canal e o protocolo subjacentes, mas usará ferramentas GUI ou CLI que se comunicam em seu nome. Por exemplo, as ferramentas dotnet-dump e dotnet-trace abstraem comandos de protocolo de envio para capturar dumps e iniciar rastreamentos. Para desenvolvedores que desejam escrever ferramentas personalizadas, o pacote NuGet Microsoft.Diagnostics.NETCore.Client fornece uma abstração da API .NET do transporte e protocolo subjacentes.

Considerações de segurança

A porta de diagnóstico expõe informações confidenciais sobre um aplicativo em execução. Se um usuário não confiável obtiver acesso a esse canal, ele poderá observar o estado detalhado do programa, incluindo quaisquer segredos que estejam na memória, e modificar arbitrariamente a execução do programa. No tempo de execução do CoreCLR, a porta de diagnóstico padrão é configurada para ser acessível apenas pela mesma conta de usuário que iniciou o aplicativo ou por uma conta com permissões de superusuário. Se o seu modelo de segurança não confiar em outros processos com as mesmas credenciais de conta de usuário, você poderá desabilitar todas as portas de diagnóstico definindo a variável DOTNET_EnableDiagnostics=0de ambiente . Essa configuração bloqueará sua capacidade de usar ferramentas externas, como depuração .NET ou qualquer uma das ferramentas de diagnóstico dotnet-*.

Nota

O .NET 6 padroniza o prefixo DOTNET_ em vez de variáveis de ambiente que configuram o comportamento em tempo de execução do COMPlus_ .NET. No entanto, o prefixo COMPlus_ continuará a funcionar. Se você estiver usando uma versão anterior do tempo de execução do .NET, ainda deverá usar o prefixo COMPlus_ para variáveis de ambiente.

Porta de diagnóstico padrão

No Windows, Linux e macOS, o tempo de execução tem uma porta de diagnóstico aberta por padrão em um ponto de extremidade conhecido. Esta é a porta à qual as ferramentas de diagnóstico dotnet-* se conectam automaticamente quando não foram explicitamente configuradas para usar uma porta alternativa. O parâmetro de avaliação é:

  • Windows - Pipe nomeado \\.\pipe\dotnet-diagnostic-{pid}
  • Linux e macOS - Unix Domain Socket {temp}/dotnet-diagnostic-{pid}-{disambiguation_key}-socket

{pid} é o id do processo escrito em decimal, {temp} é a TMPDIR variável de ambiente ou o valor /tmp se TMPDIR é indefinido/vazio, e {disambiguation_key} é a hora de início do processo escrita em decimal. No macOS e no NetBSD, o tempo de início do processo é o número de segundos desde a época do UNIX. Em todas as outras plataformas, é jiffies desde o momento da inicialização.

Suspender o tempo de execução na inicialização

Por padrão, o tempo de execução executa o código gerenciado assim que é iniciado, independentemente de alguma ferramenta de diagnóstico ter se conectado à porta de diagnóstico. Às vezes, é útil fazer com que o tempo de execução aguarde para executar o código gerenciado até que uma ferramenta de diagnóstico seja conectada, para observar o comportamento inicial do programa. A configuração da variável DOTNET_DefaultDiagnosticPortSuspend=1 de ambiente faz com que o tempo de execução aguarde até que uma ferramenta se conecte à porta padrão. Se nenhuma ferramenta for anexada após vários segundos, o tempo de execução imprimirá uma mensagem de aviso no console explicando que ainda está aguardando a conexão de uma ferramenta.

Configurar portas de diagnóstico adicionais

Nota

Isso funciona apenas para aplicativos que executam o .NET 5 ou posterior.

Os tempos de execução Mono e CoreCLR podem usar portas de diagnóstico configuradas connect personalizadas na função. O Mono também suporta portas TCP/IP personalizadas na listen função, quando usado com dotnet-dsrouter no Android ou iOS. Essas portas personalizadas são adicionais à porta padrão que permanece disponível. Existem algumas razões comuns pelas quais as portas personalizadas são úteis:

  • No Android, iOS e tvOS não há uma porta padrão, portanto, configurar uma porta é necessário para usar ferramentas de diagnóstico.
  • Em ambientes com contêineres ou firewalls, convém configurar um endereço de ponto de extremidade previsível que não varie com base na ID do processo, como faz a porta padrão. Em seguida, a porta personalizada pode ser explicitamente adicionada a uma lista de permissões ou intermediada por proxy em algum limite de segurança.
  • Para ferramentas de monitoramento, é útil fazer com que a ferramenta escute em um ponto de extremidade e o tempo de execução tente ativamente se conectar a ele. Isso evita a necessidade da ferramenta de monitoramento para pesquisar continuamente se novos aplicativos estão começando. Em ambientes onde a porta de diagnóstico padrão não está acessível, ela também evita a necessidade de configurar o monitor com um ponto de extremidade personalizado para cada aplicativo monitorado.

Em cada canal de comunicação entre uma ferramenta de diagnóstico e o tempo de execução do .NET, um lado precisa ser o ouvinte e esperar que o outro lado se conecte. O tempo de execução pode ser configurado para atuar na connect função para qualquer porta. (O tempo de execução do Mono também pode ser configurado para atuar na listen função para qualquer porta.) As portas também podem ser configuradas de forma independente para suspender na inicialização, aguardando que uma ferramenta de diagnóstico emita um comando resume. As portas configuradas para conexão repetem suas tentativas de conexão indefinidamente se o ponto de extremidade remoto não estiver escutando ou se a conexão for perdida. Mas o aplicativo não suspende automaticamente o código gerenciado enquanto aguarda para estabelecer essa conexão. Se você quiser que o aplicativo aguarde que uma conexão seja estabelecida, use a opção suspender na inicialização.

As portas personalizadas são configuradas usando a DOTNET_DiagnosticPorts variável de ambiente. Esta variável deve ser definida como uma lista delimitada por ponto-e-vírgula de descrições de portas. Cada descrição de porta consiste em um endereço de ponto de extremidade e modificadores opcionais que controlam o tempo de connect execução ou listen função e se o tempo de execução deve ser suspenso na inicialização. No Windows, o endereço do ponto de extremidade é o nome de um pipe nomeado sem o prefixo \\.\pipe\ . No Linux e macOS, é o caminho completo para um soquete de domínio Unix. No Android, iOS e tvOS, o endereço é um IP e uma porta. Por exemplo:

  1. DOTNET_DiagnosticPorts=my_diag_port1 - (Windows) O tempo de execução se conecta ao pipe \\.\pipe\my_diag_port1nomeado.
  2. DOTNET_DiagnosticPorts=/foo/tool1.socket;foo/tool2.socket - (Linux e macOS) O tempo de execução se conecta aos soquetes /foo/tool1.socket de domínio Unix e /foo/tool2.socket.
  3. DOTNET_DiagnosticPorts=127.0.0.1:9000 - (Android, iOS e tvOS) O tempo de execução se conecta ao IP 127.0.0.1 na porta 9000.
  4. DOTNET_DiagnosticPorts=/foo/tool1.socket,nosuspend - (Linux e macOS) Este exemplo tem o nosuspend modificador. O tempo de execução tenta se conectar ao Unix Domain Socket /foo/tool1.socket que uma ferramenta externa cria. Portas de diagnóstico adicionais normalmente fariam com que o tempo de execução fosse suspenso na inicialização aguardando um comando resume, mas nosuspend faz com que o tempo de execução não aguarde.

A sintaxe completa de uma porta é address[,(listen|connect)][,(suspend|nosuspend)]. connect é o padrão se nenhum dos dois connect ou listen for especificado (e listen só é suportado pelo tempo de execução do Mono no Android ou iOS). suspend é o padrão se nenhum dos dois suspend ou nosuspend for especificado.

Uso em ferramentas de diagnóstico dotnet

Ferramentas como dotnet-dump, dotnet-counters e dotnet-trace suportam ou collectmonitor verbos que se comunicam com um aplicativo .NET por meio da porta de diagnóstico.

  • Quando essas ferramentas usam o --processId argumento, a ferramenta calcula automaticamente o endereço da porta de diagnóstico padrão e se conecta a ele.
  • Ao especificar o --diagnostic-port argumento, a ferramenta escuta no endereço fornecido e você deve usar a DOTNET_DiagnosticPorts variável de ambiente para configurar seu aplicativo para se conectar. Para obter um exemplo completo com contadores de pontos, consulte Usando a porta de diagnóstico.

Use o ds-router para fazer proxy da porta de diagnóstico

Todas as ferramentas de diagnóstico dotnet-* esperam se conectar a uma porta de diagnóstico que seja um Named Pipe local ou um soquete de domínio Unix. O Mono geralmente é executado em hardware isolado ou em emuladores que precisam de um proxy sobre TCP para se tornarem acessíveis. A ferramenta dotnet-dsrouter pode fazer proxy de um Named Pipe local ou Unix Domain Socket para TCP para que as ferramentas possam ser usadas nesses ambientes. Para obter mais informações, consulte dotnet-dsrouter.