Compartilhar via


Portas de diagnóstico

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

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

  • Capturar um despejo de memória.
  • Inicie um rastreamento EventPipe.
  • Solicitar a linha de comando usada para iniciar o aplicativo.

A porta de diagnóstico dá suporte a transportes diferentes dependendo da plataforma. Atualmente, as implementações de runtime CoreCLR e Mono usam Named Pipes no Windows e soquetes de domínio Unix no Linux e no macOS. A implementação do runtime 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 de GUI ou CLI que se comunicam em seu nome. Por exemplo, as ferramentas dotnet-dump e dotnet-trace abstraem o envio de comandos de protocolo para capturar despejos e iniciar rastreamentos. Para desenvolvedores que desejam escrever ferramentas personalizadas, o pacote NuGet Microsoft.Diagnostics.NETCore.Client fornece uma abstração da API .NET sobre o transporte e o 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 todos os segredos que estão na memória e modificar arbitrariamente a execução do programa. No runtime 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 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 o debugging do .NET ou qualquer uma das ferramentas de diagnóstico dotnet-*.

Porta de diagnóstico padrão

No Windows, linux e macOS, o runtime tem uma porta de diagnóstico aberta por padrão em um ponto de extremidade conhecido. Essa é a porta à qual as ferramentas de diagnóstico dotnet-* se conectam automaticamente quando não foram configuradas explicitamente para usar uma porta alternativa. O endpoint é:

  • Windows – Named Pipe \\.\pipe\dotnet-diagnostic-{pid}
  • Linux e macOS – Soquete de Domínio Unix {temp}/dotnet-diagnostic-{pid}-{disambiguation_key}-socket

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

Suspender o runtime na inicialização

Por padrão, o runtime executa o código gerenciado assim que é iniciado, independentemente de qualquer ferramenta de diagnóstico ter se conectado à porta de diagnóstico. Às vezes, é útil fazer o runtime aguardar 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 runtime aguarde até que uma ferramenta se conecte à porta padrão. Se nenhuma ferramenta for anexada após vários segundos, o runtime imprimirá uma mensagem de aviso no console explicando que ainda está aguardando a anexação de uma ferramenta.

Configurar portas de diagnóstico adicionais

Observação

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

Os runtimes Mono e CoreCLR podem usar portas de diagnóstico configuradas personalizadas na connect função. O Mono também oferece suporte a portas TCP/IP personalizadas na função listen, quando usado com dotnet-dsrouter no Android ou iOS. Essas portas personalizadas são além da porta padrão que permanece disponível. Há alguns motivos comuns para que as portas personalizadas sejam úteis:

  • No Android, iOS e tvOS não há porta padrão, portanto, a configuração de uma porta é necessária para usar ferramentas de diagnóstico.
  • Em ambientes com contêineres ou firewalls, convém configurar um endereço de endpoint previsível que não varie com base na ID do processo, como acontece com a porta padrão. Em seguida, a porta personalizada pode ser explicitamente adicionada a uma lista de permissões ou configurada por um proxy em algum limite de segurança.
  • Para ferramentas de monitoramento, é útil fazer com que a ferramenta ouça em um ponto de extremidade e o runtime tenta ativamente se conectar a ele. Isso evita a necessidade da ferramenta de monitoramento sondar novos aplicativos de forma contínua para iniciar. Em ambientes em que 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 runtime do .NET, um lado precisa ser o ouvinte e aguardar a conexão do outro lado. O runtime pode ser configurado para desempenhar a função de connect em qualquer porta. (O runtime do Mono também pode ser configurado para atuar na listen função de 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 de retomada. As portas configuradas para se conectar 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 a conclusão de uma conexão, use a opção suspender na inicialização.

As portas personalizadas são configuradas usando a variável de DOTNET_DiagnosticPorts ambiente. Essa variável deve ser definida como uma lista delimitada por ponto-e-vírgula de descrições de porta. Cada descrição de porta consiste em um endereço de ponto de extremidade e modificadores opcionais que controlam a função do connect runtime listen e se ele deve ser suspenso na inicialização. No Windows, o endereço do ponto de extremidade é o nome de um tubo nomeado sem o prefixo \\.\pipe\. No Linux e no 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 runtime conecta-se ao pipe nomeado \\.\pipe\my_diag_port1.
  2. DOTNET_DiagnosticPorts=/foo/tool1.socket;foo/tool2.socket - (Linux e macOS) O runtime conecta-se aos soquetes de domínio Unix /foo/tool1.socket e /foo/tool2.socket.
  3. DOTNET_DiagnosticPorts=127.0.0.1:9000 - (Android, iOS e tvOS) O runtime conecta-se 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 runtime tenta se conectar ao Soquete /foo/tool1.socket de Domínio Unix criado por uma ferramenta externa. Portas de diagnóstico adicionais normalmente fazem com que o runtime seja suspenso na inicialização aguardando um comando de retomada, mas nosuspend faz com que o runtime não aguarde.

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

Uso em ferramentas de diagnóstico do .NET

Ferramentas como dotnet-dump, dotnet-counters e dotnet-trace todas suportam collect ou monitor verbos que se comunicam com um aplicativo .NET através 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 o 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 dotnet-counters, consulte Usando a porta de diagnóstico.

Usar o ds-router para 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 por TCP para se tornarem acessíveis. A ferramenta dotnet-dsrouter pode fazer a intermediação de um Pipe Nomeado Local ou Socket de Domínio Unix para TCP para que as ferramentas possam ser usadas nesses ambientes. Para obter mais informações, consulte dotnet-dsrouter.