From d86260b702193b84692ce007d1ad63c8bf21c45d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cnico-shishkin=E2=80=9D?= <“nicoshishkinatlogz@outlook.com”> Date: Mon, 26 Aug 2024 09:40:53 +0100 Subject: [PATCH] Update OTEL SDKSs --- docs/shipping/Code/dotnet.md | 5 +- docs/shipping/Code/go.md | 180 ++++++++++++++-------------------- docs/shipping/Code/node-js.md | 172 -------------------------------- 3 files changed, 75 insertions(+), 282 deletions(-) diff --git a/docs/shipping/Code/dotnet.md b/docs/shipping/Code/dotnet.md index c9eb0679..03a387fa 100644 --- a/docs/shipping/Code/dotnet.md +++ b/docs/shipping/Code/dotnet.md @@ -1271,9 +1271,7 @@ Next, we'll configure the OpenTelemetry logging exporter to send logs to Logz.io This configuration is designed to send logs to your Logz.io account via the OpenTelemetry Protocol (OTLP) listener. You need to specify your Logz.io token and configure the listener endpoint to match the correct region. By default, the endpoint is `https://otlp-listener.logz.io/v1/logs`, but it should be adjusted based on your region. You can find more details on the regional configurations in the [Hosting Regions Documentation](https://docs.logz.io/docs/user-guide/admin/hosting-regions/account-region/#available-regions). -:::note -Ensure that you include the `user-agent` header in the format: `"user-agent=logzio-python-logs-otlp"`. -::: + 1. Add the packages @@ -1319,6 +1317,7 @@ Ensure that you include the `user-agent` header in the format: `"user-agent=logz ``` {@include: ../../_include/log-shipping/log-shipping-token.md} + Update the `listener.logz.io` parth in `https://otlp-listener.logz.io/v1/logs` with the URL for [your hosting region](https://docs.logz.io/docs/user-guide/admin/hosting-regions/account-region). 3. Run your **application** once again: diff --git a/docs/shipping/Code/go.md b/docs/shipping/Code/go.md index 5a12b87f..e27dd84b 100644 --- a/docs/shipping/Code/go.md +++ b/docs/shipping/Code/go.md @@ -492,9 +492,7 @@ Next, we'll configure the OpenTelemetry logging exporter to send logs to Logz.io This configuration is designed to send logs to your Logz.io account via the OpenTelemetry Protocol (OTLP) listener. You need to specify your Logz.io token and configure the listener endpoint to match the correct region. By default, the endpoint is `https://otlp-listener.logz.io/v1/logs`, but it should be adjusted based on your region. You can find more details on the regional configurations in the [Hosting Regions Documentation](https://docs.logz.io/docs/user-guide/admin/hosting-regions/account-region/#available-regions). -:::note -Ensure that you include the `user-agent` header in the format: `"user-agent=logzio-python-logs-otlp"`. -::: + 1. Install OpenTelemetry dependencies: @@ -509,133 +507,101 @@ Ensure that you include the `user-agent` header in the format: `"user-agent=logz ```go - package main + // Copyright The OpenTelemetry Authors + // SPDX-License-Identifier: Apache-2.0 + + package main + import ( - "context" - "errors" - "fmt" - "time" + "context" + "errors" + "fmt" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp" - "go.opentelemetry.io/otel/exporters/stdout/stdoutlog" - "go.opentelemetry.io/otel/exporters/stdout/stdoutmetric" - "go.opentelemetry.io/otel/log/global" - "go.opentelemetry.io/otel/propagation" - "go.opentelemetry.io/otel/sdk/log" - "go.opentelemetry.io/otel/sdk/metric" - "go.opentelemetry.io/otel/sdk/trace" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp" + "go.opentelemetry.io/otel/exporters/stdout/stdoutlog" + "go.opentelemetry.io/otel/log/global" + "go.opentelemetry.io/otel/propagation" + "go.opentelemetry.io/otel/sdk/log" ) + // setupOTelSDK bootstraps the OpenTelemetry pipeline. + // If it does not return an error, make sure to call shutdown for proper cleanup. func setupOTelSDK(ctx context.Context) (shutdown func(context.Context) error, err error) { - var shutdownFuncs []func(context.Context) error + var shutdownFuncs []func(context.Context) error - shutdown = func(ctx context.Context) error { - var err error - for _, fn := range shutdownFuncs { - err = errors.Join(err, fn(ctx)) - } - shutdownFuncs = nil - return err - } + // shutdown calls cleanup functions registered via shutdownFuncs. + // The errors from the calls are joined. + // Each registered cleanup will be invoked once. + shutdown = func(ctx context.Context) error { + var err error + for _, fn := range shutdownFuncs { + err = errors.Join(err, fn(ctx)) + } + shutdownFuncs = nil + return err + } - handleErr := func(inErr error) { - err = errors.Join(inErr, shutdown(ctx)) - } - - prop := newPropagator() - otel.SetTextMapPropagator(prop) - - tracerProvider, err := newTraceProvider() - if err != nil { - handleErr(err) - return - } - shutdownFuncs = append(shutdownFuncs, tracerProvider.Shutdown) - otel.SetTracerProvider(tracerProvider) + // handleErr calls shutdown for cleanup and makes sure that all errors are returned. + handleErr := func(inErr error) { + err = errors.Join(inErr, shutdown(ctx)) + } - meterProvider, err := newMeterProvider() - if err != nil { - handleErr(err) - return - } - shutdownFuncs = append(shutdownFuncs, meterProvider.Shutdown) - otel.SetMeterProvider(meterProvider) + // Set up propagator. + prop := newPropagator() + otel.SetTextMapPropagator(prop) - loggerProvider, err := newLoggerProvider() - if err != nil { - handleErr(err) - return - } - shutdownFuncs = append(shutdownFuncs, loggerProvider.Shutdown) - global.SetLoggerProvider(loggerProvider) + // Set up logger provider. + loggerProvider, err := newLoggerProvider() + if err != nil { + handleErr(err) + return + } + shutdownFuncs = append(shutdownFuncs, loggerProvider.Shutdown) + global.SetLoggerProvider(loggerProvider) - return + return } func newPropagator() propagation.TextMapPropagator { - return propagation.NewCompositeTextMapPropagator( - propagation.TraceContext{}, - propagation.Baggage{}, - ) - } - - func newTraceProvider() (*trace.TracerProvider, error) { - traceExporter, err := stdouttrace.New( - stdouttrace.WithPrettyPrint()) - if err != nil { - return nil, err - } - - traceProvider := trace.NewTracerProvider( - trace.WithBatcher(traceExporter, - trace.WithBatchTimeout(time.Second)), - ) - return traceProvider, nil - } - - func newMeterProvider() (*metric.MeterProvider, error) { - metricExporter, err := stdoutmetric.New() - if err != nil { - return nil, err - } - - meterProvider := metric.NewMeterProvider( - metric.WithReader(metric.NewPeriodicReader(metricExporter, - metric.WithInterval(3*time.Second))), - ) - return meterProvider, nil + return propagation.NewCompositeTextMapPropagator( + propagation.TraceContext{}, + propagation.Baggage{}, + ) } func newLoggerProvider() (*log.LoggerProvider, error) { - stdoutExporter, err := stdoutlog.New(stdoutlog.WithPrettyPrint()) - if err != nil { - return nil, fmt.Errorf("failed to create stdout exporter: %w", err) - } + // Create stdout log exporter + stdoutExporter, err := stdoutlog.New(stdoutlog.WithPrettyPrint()) + if err != nil { + return nil, fmt.Errorf("failed to create stdout exporter: %w", err) + } - httpExporter, err := otlploghttp.New(context.Background(), - otlploghttp.WithEndpoint("otlp-listener.logz.io"), - otlploghttp.WithHeaders(map[string]string{ - "Authorization": "Bearer ", - "user-agent": "logzio-go-logs-otlp", - }), - otlploghttp.WithURLPath("/v1/logs"), - ) - if err != nil { - return nil, fmt.Errorf("failed to create OTLP HTTP exporter: %w", err) - } + // Create OTLP HTTP log exporter for Logz.io + httpExporter, err := otlploghttp.New(context.Background(), + otlploghttp.WithEndpoint("otlp-listener.logz.io"), + otlploghttp.WithHeaders(map[string]string{ + "Authorization": "Bearer ", + }), + otlploghttp.WithURLPath("/v1/logs"), + ) + if err != nil { + return nil, fmt.Errorf("failed to create OTLP HTTP exporter: %w", err) + } - loggerProvider := log.NewLoggerProvider( - log.WithProcessor(log.NewBatchProcessor(stdoutExporter)), - log.WithProcessor(log.NewBatchProcessor(httpExporter)), - ) + // Create a logger provider with both exporters + loggerProvider := log.NewLoggerProvider( + log.WithProcessor(log.NewBatchProcessor(stdoutExporter)), // For stdout + log.WithProcessor(log.NewBatchProcessor(httpExporter)), // For HTTP export + ) - return loggerProvider, nil + return loggerProvider, nil } - ``` + {@include: ../../_include/log-shipping/log-shipping-token.md} + Update the `listener.logz.io` parth in `https://otlp-listener.logz.io/v1/logs` with the URL for [your hosting region](https://docs.logz.io/docs/user-guide/admin/hosting-regions/account-region). 3. Run your **application** once again: diff --git a/docs/shipping/Code/node-js.md b/docs/shipping/Code/node-js.md index 26df0c75..8a138b90 100644 --- a/docs/shipping/Code/node-js.md +++ b/docs/shipping/Code/node-js.md @@ -360,179 +360,7 @@ logger.log(obj); ``` - -### Prerequisites - -Ensure that you have the following installed locally: -- [Node.js](https://nodejs.org/) (latest LTS version recommended) - -### Example Application -The following example uses a basic Express application in Node.js - -### Create and launch an HTTP Server - -1. Set up an environment in a new directory called `nodejs-simple`: - - - ```bash - mkdir nodejs-simple - cd nodejs-simple - npm init -y - ``` - -2. Install Express JS: - - ```bash - npm install express - ``` - -3. In this directory, create a file named `app.js` and add the following code: - - ```javascript - const express = require('express'); - - const PORT = parseInt(process.env.PORT || '8080'); - const app = express(); - - function getRandomNumber(min, max) { - return Math.floor(Math.random() * (max - min + 1)) + min; - } - - app.get('/rolldice', (req, res) => { - res.send(getRandomNumber(1, 6).toString()); - }); - - app.listen(PORT, () => { - console.log(`Listening for requests on http://localhost:${PORT}`); - }); - - ``` - -4. Run the application with the following command: - - ```bash - node app.js - ``` - -5. Open http://localhost:8080/rolldice in your web browser to ensure it is working. - - -### Instrumentation - -Next, we'll configure the OpenTelemetry logging exporter to send logs to Logz.io via the OTLP listener. - -This configuration is designed to send logs to your Logz.io account via the OpenTelemetry Protocol (OTLP) listener. You need to specify your Logz.io token and configure the listener endpoint to match the correct region. By default, the endpoint is `https://otlp-listener.logz.io/v1/logs`, but it should be adjusted based on your region. You can find more details on the regional configurations in the [Hosting Regions Documentation](https://docs.logz.io/docs/user-guide/admin/hosting-regions/account-region/#available-regions). - -:::note -Ensure that you include the `user-agent` header in the format: `"user-agent=logzio-python-logs-otlp"`. -::: - - -1. Add the packages - ```bash - npm install winston axios - ``` - -2. Create a custom Logz.io transport for Winston with a file named `logzio-transport.js` and add the following code: - - ```javascript - const Transport = require('winston-transport'); - const axios = require('axios'); - - class LogzIoTransport extends Transport { - constructor(opts) { - super(opts); - this.endpoint = opts.endpoint; - this.token = opts.token; - this.serviceName = opts.serviceName; - } - - log(info, callback) { - setImmediate(() => this.emit('logged', info)); - - const logEntry = { - message: info.message, - level: info.level, - service: this.serviceName, - ...info.meta, - }; - - axios.post(this.endpoint, logEntry, { - headers: { - 'Authorization': `Bearer ${this.token}`, - 'Content-Type': 'application/json', - 'user-agent': 'logzio-nodejs-logs-otlp', - }, - }) - .then(() => callback()) - .catch(err => { - console.error('Error sending log to Logz.io:', err); - callback(); - }); - } - } - - module.exports = LogzIoTransport; - ``` - -3. Set up the logging configuration in your `app.js`, by replacing its content with the following: - - ```javascript - const express = require('express'); - const winston = require('winston'); - const LogzIoTransport = require('./logzio-transport'); - - const PORT = process.env.PORT || 8080; - const app = express(); - - const logger = winston.createLogger({ - level: 'info', - format: winston.format.json(), - transports: [ - new LogzIoTransport({ - endpoint: 'https://listener.logz.io:8071', - token: '', - serviceName: 'nodejs-roll-dice', - }), - ], - }); - - function getRandomNumber(min, max) { - return Math.floor(Math.random() * (max - min + 1)) + min; - } - - app.get('/rolldice', (req, res) => { - const result = getRandomNumber(1, 6); - logger.info(`Rolled dice: ${result}`); - res.send(result.toString()); - }); - - app.listen(PORT, () => { - logger.info(`Listening for requests on http://localhost:${PORT}`); - console.log(`Listening for requests on http://localhost:${PORT}`); - }); - ``` - - {@include: ../../_include/log-shipping/log-shipping-token.md} - -4. Run your **application** once again: - - ```bash - node app.js - ``` - -4. From another terminal, send a request using curl: - - ``` - curl localhost:8080/rolldice - ``` -5. After about 30 sec, stop the server process. - -At this point, you should see log output from the server and client on your Logz.io account. - - -