Recursos

Adicione detalhes sobre o ambiente das suas aplicações à sua telemetria

Um recurso representa a entidade que está gerando telemetria como atributos do recurso. Por exemplo, um processo que está gerando telemetria e que está sendo executado em um container no Kubernetes tem o nome de um processo, um nome de pod, um namespace e possivelmente um nome de deployment. Todos esses quatro atributos podem ser incluídos em um recurso.

No seu backend de observabilidade, você pode usar as informações de um recurso para refinar a investigação de comportamentos relevantes. Por exemplo, se seus dados de rastros ou métricas indicarem latência no seu sistema, você pode restringir a investigação para um determinado container, pod ou deployment do Kubernetes.

Abaixo você encontrará introduções sobre como configurar a detecção de recursos com o SDK do Node.js.

Configuração

Siga as instruções em Primeiros Passos - Node.js para ter os arquivos package.json, app.js (ou app.ts) e instrumentation.mjs (ou instrumentation.ts).

Detecção de recursos de processo e ambiente

Por padrão, o SDK do Node.js detecta recursos de processo e do runtime de processo e obtém atributos da variável de ambiente OTEL_RESOURCE_ATTRIBUTES. É possível verificar o que é detectado ativando o registro de diagnóstico no arquivo de instrumentação:

// Para investigação de problemas, defina o nível de log como DiagLogLevel.DEBUG
diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG);

Execute a aplicação com alguns valores definidos em OTEL_RESOURCE_ATTRIBUTES, por exemplo, definimos o host.name para identificar o Host:

$ env OTEL_RESOURCE_ATTRIBUTES="host.name=localhost" \
  node --import ./instrumentation.mjs app.js
@opentelemetry/api: Registered a global for diag v1.2.0.
...
Listening for requests on http://localhost:8080
EnvDetector found resource. Resource { attributes: { 'host.name': 'localhost' } }
ProcessDetector found resource. Resource {
  attributes: {
    'process.pid': 12345,
    'process.executable.name': 'node',
    'process.command': '/app.js',
    'process.command_line': '/bin/node /app.js',
    'process.runtime.version': '16.17.0',
    'process.runtime.name': 'nodejs',
    'process.runtime.description': 'Node.js'
  }
}
...

Adicionando recursos com variáveis de ambiente

No exemplo acima, o SDK detectou o processo e também adicionou automaticamente o atributo host.name=localhost definido pela variável de ambiente.

Abaixo estão instruções para que os recursos sejam detectados automaticamente. No entanto, pode acontecer de não existir um detector para o recurso necessário. Nesse caso, use a variável de ambiente OTEL_RESOURCE_ATTRIBUTES para injetar o que for preciso. Além disso, é possível usar a variável de ambiente OTEL_SERVICE_NAME para definir o valor do atributo de recurso service.name. Por exemplo, o script a seguir adiciona atributos de recurso de Serviço, Host e Sistema Operacional:

$ env OTEL_SERVICE_NAME="app.js" OTEL_RESOURCE_ATTRIBUTES="service.namespace=tutorial,service.version=1.0,service.instance.id=`uuidgen`,host.name=${HOSTNAME},host.type=`uname -m`,os.name=`uname -s`,os.version=`uname -r`" \
  node --import ./instrumentation.mjs app.js
...
EnvDetector found resource. Resource {
  attributes: {
    'service.name': 'app.js',
    'service.namespace': 'tutorial',
    'service.version': '1.0',
    'service.instance.id': '46D99F44-27AB-4006-9F57-3B7C9032827B',
    'host.name': 'myhost',
    'host.type': 'arm64',
    'os.name': 'linux',
    'os.version': '6.0'
  }
}
...

Adicionando recursos no código

Também é possível configurar recursos personalizados no código. O NodeSDK oferece uma opção de configuração para defini-los. Por exemplo, atualize o arquivo de instrumentação como no exemplo a seguir para definir os atributos service.*:

...
const { resourceFromAttributes } = require('@opentelemetry/resources');
const { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } = require('@opentelemetry/semantic-conventions');
...
const sdk = new opentelemetry.NodeSDK({
  ...
  resource: resourceFromAttributes({
    [ ATTR_SERVICE_NAME ]: "yourServiceName",
    [ ATTR_SERVICE_VERSION ]: "1.0",
  })
  ...
});
...

Detecção de recursos de contêiner

Use a mesma configuração (package.json, app.js e instrumentation.mjs com a depuração ativada) e um Dockerfile com o seguinte conteúdo no mesmo diretório:

FROM node:latest
WORKDIR /usr/src/app
COPY package.json ./
RUN npm install
COPY . .
EXPOSE 8080
CMD [ "node", "--import", "./instrumentation.mjs", "app.js" ]

Para garantir que o contêiner Docker possa ser interrompido com Ctrl + C (SIGINT), adicione o seguinte ao final do app.js:

process.on('SIGINT', function () {
  process.exit();
});

Para que o ID do contêiner seja detectado automaticamente, instale a seguinte dependência adicional:

npm install @opentelemetry/resource-detector-container

Em seguida, atualize o instrumentation.mjs como a seguir:

const opentelemetry = require('@opentelemetry/sdk-node');
const {
  getNodeAutoInstrumentations,
} = require('@opentelemetry/auto-instrumentations-node');
const { diag, DiagConsoleLogger, DiagLogLevel } = require('@opentelemetry/api');
const {
  containerDetector,
} = require('@opentelemetry/resource-detector-container');

// Para investigação de problemas, defina o nível de log como DiagLogLevel.DEBUG
diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG);

const sdk = new opentelemetry.NodeSDK({
  traceExporter: new opentelemetry.tracing.ConsoleSpanExporter(),
  instrumentations: [getNodeAutoInstrumentations()],
  resourceDetectors: [containerDetector],
});

sdk.start();

Crie a imagem Docker:

docker build . -t nodejs-otel-getting-started

Execute o contêiner:

$ docker run --rm -p 8080:8080 nodejs-otel-getting-started
@opentelemetry/api: Registered a global for diag v1.2.0.
...
Listening for requests on http://localhost:8080
DockerCGroupV1Detector found resource. Resource {
  attributes: {
    'container.id': 'fffbeaf682f32ef86916f306ff9a7f88cc58048ab78f7de464da3c3201db5c54'
  }
}

O detector extraiu o container.id. No entanto, note que, neste exemplo, os atributos de processo e os atributos definidos por variável de ambiente estão ausentes! Para resolver isso, ao definir a lista resourceDetectors, é necessário também especificar os detectores envDetector e processDetector:

const opentelemetry = require('@opentelemetry/sdk-node');
const {
  getNodeAutoInstrumentations,
} = require('@opentelemetry/auto-instrumentations-node');
const { diag, DiagConsoleLogger, DiagLogLevel } = require('@opentelemetry/api');
const {
  containerDetector,
} = require('@opentelemetry/resource-detector-container');
const { envDetector, processDetector } = require('@opentelemetry/resources');

// Para investigação de problemas, defina o nível de log como DiagLogLevel.DEBUG
diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG);

const sdk = new opentelemetry.NodeSDK({
  traceExporter: new opentelemetry.tracing.ConsoleSpanExporter(),
  instrumentations: [getNodeAutoInstrumentations()],
  // Certifique-se de adicionar aqui todos os detectores necessários!
  resourceDetectors: [envDetector, processDetector, containerDetector],
});

sdk.start();

Reconstrua a imagem e execute o contêiner mais uma vez:

docker run --rm -p 8080:8080 nodejs-otel-getting-started
@opentelemetry/api: Registered a global for diag v1.2.0.
...
Listening for requests on http://localhost:8080
EnvDetector found resource. Resource { attributes: {} }
ProcessDetector found resource. Resource {
  attributes: {
    'process.pid': 1,
    'process.executable.name': 'node',
    'process.command': '/usr/src/app/app.js',
    'process.command_line': '/usr/local/bin/node /usr/src/app/app.js',
    'process.runtime.version': '18.9.0',
    'process.runtime.name': 'nodejs',
    'process.runtime.description': 'Node.js'
  }
}
DockerCGroupV1Detector found resource. Resource {
  attributes: {
    'container.id': '654d0670317b9a2d3fc70cbe021c80ea15339c4711fb8e8b3aa674143148d84e'
  }
}
...

Próximos passos

Existem mais detectores de recursos que podem ser adicionados à configuração, por exemplo, para obter detalhes sobre o seu ambiente de Nuvem ou Implantação. Para mais, veja os pacotes nomeados resource-detector-* no repositório opentelemetry-js-contrib.