---
title: "Send from an SDK"
description: "Configure OpenTelemetry SDKs and language agents to send logs over OTLP/gRPC or OTLP/HTTP."
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.ezghcloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Send from an SDK

OpenTelemetry SDKs and language agents read their exporter settings from environment variables.
The same variables work for every language and both protocols.

## The environment variables

```sh
export OTEL_EXPORTER_OTLP_ENDPOINT=https://obs-ingest.ezghcloud.com
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf          # or grpc, or http/json
export OTEL_EXPORTER_OTLP_HEADERS="authorization=Bearer%20${EZGH_INGEST_KEY}"
export OTEL_RESOURCE_ATTRIBUTES="service.name=checkout,ezgh.metadata.application=storefront,ezgh.metadata.environment=production"
export OTEL_LOGS_EXPORTER=otlp
export OTEL_TRACES_EXPORTER=none
export OTEL_METRICS_EXPORTER=none
```

| Variable | Value |
| --- | --- |
| `OTEL_EXPORTER_OTLP_ENDPOINT` | `https://obs-ingest.ezghcloud.com`, the base URL, for every protocol. HTTP exporters add `/v1/logs`; gRPC exporters connect to port 443 with TLS. |
| `OTEL_EXPORTER_OTLP_PROTOCOL` | `grpc`, `http/protobuf` or `http/json`. All three are accepted. Set it explicitly: defaults differ between SDKs. |
| `OTEL_EXPORTER_OTLP_HEADERS` | `authorization=Bearer%20<ingest key>`. The value uses the W3C Baggage format, where the space is written `%20`; SDKs decode it. |
| `OTEL_RESOURCE_ATTRIBUTES` | `service.name`, `ezgh.metadata.application` and `ezgh.metadata.environment`. See [service metadata](/observability#service-metadata). |
| `OTEL_LOGS_EXPORTER` | `otlp`. |
| `OTEL_TRACES_EXPORTER`, `OTEL_METRICS_EXPORTER` | `none`. Only logs are accepted today; traces and metrics are refused with `404` / `UNIMPLEMENTED`. |

Keep the ingest key in your secret manager and pass it in as `EZGH_INGEST_KEY`. Don't put it in
code or images. Don't set `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT` unless you need it: it's used as
the exact URL, without `/v1/logs` added.

## Java

The [OpenTelemetry Java agent](https://opentelemetry.io/docs/zero-code/java/agent/) sends what
your application logs through Logback, Log4j or `java.util.logging`.

```sh
java -javaagent:opentelemetry-javaagent.jar -jar app.jar
```

## Python

```sh
pip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install
export OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true
opentelemetry-instrument python app.py
```

Records written with the standard `logging` module are sent.

## Node.js

```sh
npm install @opentelemetry/api @opentelemetry/auto-instrumentations-node
node --require @opentelemetry/auto-instrumentations-node/register app.js
```

Records written with winston, pino or bunyan are sent through their instrumentations.

## Go

Go has no agent: create a logger provider with an OTLP exporter. The exporters and
`resource.Default()` read the environment variables above.

```go
import (
	"context"

	"go.opentelemetry.io/contrib/bridges/otelslog"
	"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp" // or otlploggrpc
	"go.opentelemetry.io/otel/log/global"
	sdklog "go.opentelemetry.io/otel/sdk/log"
	"go.opentelemetry.io/otel/sdk/resource"
)

func setupLogs(ctx context.Context) (*sdklog.LoggerProvider, error) {
	exporter, err := otlploghttp.New(ctx)
	if err != nil {
		return nil, err
	}
	provider := sdklog.NewLoggerProvider(
		sdklog.WithResource(resource.Default()),
		sdklog.WithProcessor(sdklog.NewBatchProcessor(exporter)),
	)
	global.SetLoggerProvider(provider)
	return provider, nil // call provider.Shutdown(ctx) before exiting
}

// Then log with log/slog through the bridge:
//   logger := otelslog.NewLogger("checkout")
//   logger.ErrorContext(ctx, "payment timeout", "order", orderID)
```

## .NET

```csharp
builder.Logging.AddOpenTelemetry(logging =>
{
    logging.IncludeFormattedMessage = true;
    logging.AddOtlpExporter();
});
```

`AddOtlpExporter` reads the environment variables above, including `OTEL_EXPORTER_OTLP_PROTOCOL`.

## Check that it works

Send a log line, then search for it a few seconds later:

```sh
ezgh obs search --environment production --from 5m --project web
```

If nothing arrives, see [Troubleshooting](/observability/troubleshooting). An exporter logs the
status it gets back.

Source: https://docs.ezghcloud.com/observability/send-with-sdks/index.mdx
