No dia 30 de março foi anunciada a fase beta do OpenTelemetry. O objetivo do projeto é facilitar o rastreamento distribuído através de uma série de ferramentas integradas como descrito no meu primeiro artigo sobre o assunto. Entre as metas estabelecidas para o lançamento do beta estava a integração de plugins que permitem instrumentação automática das aplicações, diminuindo de forma significativa o trabalho necessário para implementação. Os repositórios das bibliotecas já funcionais e em desenvolvimento podem ser encontrados na página do projeto no github.
Esse artigo trás um exemplo de Distributed Tracing de aplicações Node usando http, Express e IORedis para simular o monitoramento de uma arquitetura de micro serviços usando a API javascript do OpenTelemetry e os plugins de instrumentação automática de cada módulo. Vamos explorar brevemente pedaços de código para ilustrar o funcionamento do sistema e o que é necessário ser feito para ter as informações de execução disponíveis no Jaeger como na imagem:
Nossa implementação de exemplo consiste em dois servidores, o primeiro simula uma API que serve de primeiro ponto de contato na comunicação e repassa as requisições para o segundo, que é responsável por buscar os dados necessários acessando o redis. Recomendo muito dar uma olhada no código completo aqui e para rodar basta fazer docker-compose up
ou seguir as instruções para cada serviço. No compose temos os containers de cada serviço e o Jaeger que vai servir como backend e interface para análise dos spans coletados.
Como uma aplicação de exemplo, o funcionamento é bem simplificado. Ao acessar localhost:3000
pela primeira vez um resultado vazio é retornado.
Essa rota acessa o middleware e pede os valores para as keys key1
, key2
e key3
.
// api.js
...
const values = ['key1', 'key2', 'key3']
app.get('/', async (_, res) => {
console.log('get /', middleware_url);
const resultList = await Promise.all(
values.map(v => httpRequest(middleware_url, 4000, '/' + v))
)
console.log({ resultList });
res.status(200).send(resultList.toString());
})
...
Usamos a rota /set-values
para popular esses valores:
// api.js
...
app.get('/set-values', async (_, res) => {
const testItens = [
{ key: 'key1', value: 'value1' },
{ key: 'key2', value: 'value2' },
{ key: 'key3', value: 'value3' },
]
await Promise.all(
testItens.map(i => httpRequest(middleware_url, 4000, `/set?key=${i.key}&value=${i.value}`))
).then((result) => {
res.status(200).send(result.toString());
})
})
...
e agora ao acessar localhost:3000
obtemos os valores para as chaves solicitadas:
Se você rodou o código a partir do repositório completo e fez esses 3 passos já pode visualizar os traces gerados na interface do Jaeger em: http://localhost:16686 selecionando o Service api
e clicando em find traces.
Isso é possível graças aos plugins do OpenTelemetry. Com a instrumentação automática não é preciso mudar cada parte do código para adicionar o tracing. Os plugins fazem patch dos módulos e escutam as chamadas internas adicionando a passagem de contexto onde é necessário.
No topo dos arquivos api.js
e middleware.js
você verá:
const { createTracer } = require('./tracer');
createTracer('api');
O tracer importa as bibliotecas do OpenTelemetry e inicializa o NodeTracerProvider
que precisa ser definido antes do import dos módulos suportados. Aqui também é configurado o exporter do Jaeger.
// tracer.js
const opentelemetry = require('@opentelemetry/api');
const { NodeTracerProvider } = require('@opentelemetry/node');
const { JaegerExporter } = require('@opentelemetry/exporter-jaeger');
const { SimpleSpanProcessor } = require('@opentelemetry/tracing');
const createTracer = (serviceName) => {
const provider = new NodeTracerProvider();
exporter = new JaegerExporter({
serviceName,
host: 'jaeger'
});
provider.addSpanProcessor(new SimpleSpanProcessor(exporter));
provider.register();
return opentelemetry.trace.getTracer(serviceName)
}
module.exports = {
createTracer,
}
Top comments (0)