Telemetria com o Application Insights
Telemetria opcional do Azure Application Insights sobre o pipeline de assinatura — como habilitá-la, o que é coletado, o que é intencionalmente excluído e as consultas KQL para encontrar gargalos.
A telemetria vem desligada por padrão. Com ela desabilitada, o serviço não tem dependência do Application Insights e não faz conexões de saída em nome dele. Tudo nesta página descreve uma funcionalidade opcional.
Em resumo
| Pergunta | Resposta |
|---|---|
| Como habilitar? | Defina Telemetry:Enabled = true e forneça uma connection string (Telemetry:ConnectionString ou a variável de ambiente APPLICATIONINSIGHTS_CONNECTION_STRING). |
| Estado padrão? | Desligado. |
| Qual é o SDK? | A distro do Azure Monitor OpenTelemetry — activities e meters padrão do OpenTelemetry, não o SDK clássico do Application Insights. |
| O que é coletado? | Um trace correlacionado por job, os passos do ciclo de vida como span events, chamadas do PKI SDK como dependências, métricas de duração de assinatura e de processamento total, e exceções de processamento. |
| O que é excluído? | Logs (logs estruturados não são encaminhados), segredos (mascarados), conteúdo de arquivos, material de certificado e o caminho remoto do Lacuna Signer. |
| Quais tabelas do Application Insights? | Spans → dependencies; métricas → customMetrics; exceções → exceptions; requisições web coletadas automaticamente → requests. Não há customEvents — veja abaixo. |
Escopo: esta página cobre a assinatura local. O fluxo remoto do Lacuna Signer é apenas parcialmente rastreado — veja O que é intencionalmente excluído.
Habilitando o Application Insights
1. Crie o recurso e copie a connection string
Crie um recurso do Application Insights no portal do Azure e copie sua connection string (painel Overview → Connection String). Ela tem este formato:
InstrumentationKey=00000000-0000-0000-0000-000000000000;IngestionEndpoint=https://<region>.in.applicationinsights.azure.com/;LiveEndpoint=https://<region>.livediagnostics.monitor.azure.com/
2. Configure o Bulk Signer
A connection string carrega a instrumentation key e é tratada como um segredo — nunca faça commit dela. Prefira a variável de ambiente.
Opção A — variável de ambiente (recomendada):
# Linux / Docker
export Telemetry__Enabled=true
export APPLICATIONINSIGHTS_CONNECTION_STRING="InstrumentationKey=...;IngestionEndpoint=https://.../"
# Windows
[Environment]::SetEnvironmentVariable("Telemetry__Enabled", "true", "Machine")
[Environment]::SetEnvironmentVariable("APPLICATIONINSIGHTS_CONNECTION_STRING", "InstrumentationKey=...;IngestionEndpoint=https://.../", "Machine")
Opção B — arquivo de configuração do operador (por exemplo, appsettings.Production.json):
{
"Telemetry": {
"Enabled": true,
"ConnectionString": "InstrumentationKey=...;IngestionEndpoint=https://.../",
"RoleName": "Lacuna.BulkSigner"
}
}
| Chave | Tipo | Padrão | Override por env | Observações |
|---|---|---|---|---|
Telemetry:Enabled | bool | false | Telemetry__Enabled | Chave mestra. Quando true, uma connection string é obrigatória — o serviço se recusa a iniciar sem ela. |
Telemetry:ConnectionString | string | "" | Telemetry__ConnectionString | SECRET. Deixe vazia para usar a variável de ambiente padrão abaixo. |
| (variável de ambiente padrão) | string | (não definida) | APPLICATIONINSIGHTS_CONNECTION_STRING | Lida diretamente pela distro e respeitada pelo validador de inicialização. Use-a para manter o segredo fora dos arquivos de configuração. |
Telemetry:RoleName | string | Lacuna.BulkSigner | Telemetry__RoleName | Informado como cloud_RoleName, para que vários serviços no mesmo recurso continuem distinguíveis. |
3. Reinicie e verifique
Reinicie o serviço. Um ou dois minutos depois de processar um job, você deve ver entradas no recurso do
Application Insights: uma linha em dependencies chamada signing.job por job, dependências filhas
Lacuna.Pki … e linhas em customMetrics para bulksigner.signing.duration e
bulksigner.job.duration.
O que é coletado
Traces — span por job mais eventos de ciclo de vida
Cada job abre um span raiz (signing.job, tipo Internal, que aparece no Application Insights como
dependencies) no momento da captura, com as tags job.id, signing.profile, signing.method e
signing.format. Cada passo abaixo é registrado como um span event nesse span, de modo que todos
compartilham o mesmo operation_Id para correlação:
| Evento | Quando |
|---|---|
JobCreated | No enfileiramento (um trace signing.job.created independente — o span do worker ainda não existe) |
JobPickedForProcessing | O worker reivindica o job |
SigningStarted / SigningCompleted | Em torno da chamada de assinatura local |
VerificationStarted / VerificationCompleted | Em torno da chamada de verificação (somente quando o perfil tem Verify = true) |
OutputFileCreated | Artefato assinado promovido para output/ |
JobCompleted | Sucesso terminal (status do span Ok) |
JobFailed | Falha terminal (status do span Error) |
JobCanceled | Cancelamento pelo operador (um trace signing.job.canceled independente) |
DispatchedToSigner | Job entregue ao Lacuna Signer (caminho remoto — cobertura parcial) |
Cnab240PaymentDateCheckSkipped | Uma remessa CNAB240 cuja data de pagamento mais antiga já havia passado foi liberada em vez de recusada, porque a verificação da data de pagamento do perfil (ou a verificação de CNAB240) está desligada — uma decisão, não uma assinatura |
Dependências — chamadas do PKI SDK
As chamadas de assinatura e verificação do Lacuna PKI SDK são encapsuladas em spans filhos do tipo
Client, chamados Lacuna.Pki SignAsync e Lacuna.Pki VerifyAsync, que aparecem como dependencies.
Cada um tem sua própria duração e uma flag de sucesso; uma chamada que falhou é marcada como Error,
com uma mensagem mascarada, para que chamadas externas com problema fiquem visíveis com contexto de
diagnóstico.
Métricas — customMetrics
| Métrica | Unidade | Dimensões |
|---|---|---|
bulksigner.signing.duration | ms | signing.method, signing.profile, signing.format, job.status (Success / Failed) |
bulksigner.job.duration | ms | job.status (Success / Failed), signing.profile, signing.method |
O bulksigner.signing.duration é o tempo decorrido da própria operação de assinatura; o
bulksigner.job.duration é o total, da criação do job até o estado terminal.
Exceções — exceptions
Exceções de processamento tratadas e não tratadas são registradas no span do job com o id do job, o perfil, o método de assinatura e o passo de processamento em que o erro ocorreu. Mensagens e stack traces são mascarados antes de deixarem o processo.
O que é intencionalmente excluído
- Segredos. A licença do PKI, senhas de certificado e de PFX, o PIN do PKCS#11, o client secret do Azure Key Vault, chaves de API, a senha de criptografia e connection strings são mascarados em todo valor anexado à telemetria — inclusive mensagens de exceção e stack traces. Veja Segurança.
- Conteúdo de arquivos e material de certificado. Nunca são anexados a nenhum span, evento ou métrica.
- Logs da aplicação. Logs estruturados não são encaminhados ao Application Insights. Somente spans, métricas e exceções explicitamente registradas são enviados; os logs permanecem nos destinos de arquivo e de console.
- O id do job como dimensão de métrica. Mantido fora dos histogramas para limitar a cardinalidade; a medição de tempo por job fica nos spans correlacionados.
- O caminho remoto do Lacuna Signer. A cobertura prioriza a assinatura local. Um job remoto emite apenas um span da captura até o despacho; a espera pelo assinante e a conclusão remota não são rastreadas.
Consultas de exemplo (KQL)
Execute estas consultas no recurso do Application Insights (painel Logs). Ajuste o intervalo de tempo conforme necessário.
Tempo médio de assinatura (local), últimas 24 h:
customMetrics
| where name == "bulksigner.signing.duration"
| where timestamp > ago(24h)
| summarize avg(value), percentiles(value, 50, 95) by tostring(customDimensions["signing.profile"])
Jobs de assinatura mais lentos:
dependencies
| where name == "signing.job"
| where timestamp > ago(24h)
| project timestamp, jobId = tostring(customDimensions["job.id"]),
profile = tostring(customDimensions["signing.profile"]), duration, success
| top 20 by duration desc
Falhas de assinatura por método de assinatura:
customMetrics
| where name == "bulksigner.signing.duration"
| where tostring(customDimensions["job.status"]) == "Failed"
| summarize failures = count() by method = tostring(customDimensions["signing.method"])
Tempo médio total de processamento:
customMetrics
| where name == "bulksigner.job.duration"
| where tostring(customDimensions["job.status"]) == "Success"
| summarize avg(value), percentiles(value, 50, 95)
Chamadas do PKI SDK que falharam (diagnóstico de chamadas externas):
dependencies
| where name startswith "Lacuna.Pki"
| where success == false
| project timestamp, name, jobId = tostring(customDimensions["job.id"]),
operation = tostring(customDimensions["pki.operation"]), resultCode
| order by timestamp desc
Exceções de processamento por passo:
exceptions
| where timestamp > ago(24h)
| summarize count() by step = tostring(customDimensions["processing.step"]), type
| order by count_ desc
Por que não há customEvents
O Bulk Signer usa a distro do Azure Monitor OpenTelemetry, que não tem equivalente ao TrackEvent —
o OpenTelemetry não tem uma primitiva de "evento personalizado". Por isso, os passos do ciclo de vida são
modelados como span events no span por job e consultados pela tabela dependencies e seu
customDimensions, e não por customEvents. Consultas escritas para uma aplicação com o SDK clássico
precisarão ser adaptadas.
Relacionados
- Estatísticas de jobs — os tempos por etapa do dashboard, mantidos no banco de dados operacional e lidos no escopo de toda a implantação.
- API REST — o endpoint Prometheus
/api/metrics, o registro durável, baseado em coleta (scrape). - Configuração — cada chave de configuração.
- Segurança — tratamento de segredos e o mascaramento de logs em duas camadas.
A seguir: API REST — endpoints, autenticação e o envelope de erro. Anterior: Estatísticas de jobs.