Overview
OpenTelemetry uses the OTLP protocol to receive telemetry data (logs, metrics and traces) as well as export it.
Furthermore, it can receive and export OTLP over two underlying transports:
- gRPC - A protobuf-based, binary protocol listening on default port 4317,
- HTTP - An HTTP-based protocol listening on default port 4318.
Most OpenTelemetry users are familiar with using curl to send logs, metrics, and traces to an OpenTelemetry Collector’s OTLP/HTTP port (4318). Often the question comes up on doing the same, but to the gRPC port (4317). Because, gRPC is a binary protocol built using protobuf definitions, curl cannot be used.
However, grpcurl is a command-line tool used to communicate with gRPC services similar to curl.
This example will use gRPCurl to send a JSON OpenTelemetry Log Event to an OpenTelemetry Collector over the OTLP gRPC port.
Prerequisites
Telemetry Format
In order to send a metric, log or trace to an OpenTelemetry Collector via either HTTP or gRPC, we first need a JSON-formatted payload of the metric, log or trace. The easiest way to get this is to either use the fileexporter exporter to write JSON-formatted events to a file, or simply download some samples from the OpenTelemetry docs.
Example Log Event
For this exercise, we’ll use this Log event:
{
"resourceLogs": [
{
"resource": {},
"scopeLogs": [
{
"scope": {},
"logRecords": [
{
"observedTimeUnixNano": "1664827200000000000",
"body": {
"stringValue": "🪵🪵🪵🪵 This is the sample log message."
},
"attributes": [
{
"key": "log.file.name",
"value": {
"stringValue": "access_log"
}
}
],
"traceId": "",
"spanId": ""
}
]
}
]
}
]
}
Clone OpenTelemetry protobuf definitions
To get started, we need to first download the protobufs for the Collector to our local computer:
mkdir $HOME/exercise
cd $HOME/exercise
git clone https://github.com/open-telemetry/opentelemetry-proto.git
Sending with gRPCurl
From within the $HOME/exercise
directory, execute the following:
- Be sure to replace
<collector-hostname>
with the hostname or IP address of the Collector, - The
-plaintext
option is only needed when the Collector does not use TLS encryption.
# Send a log to an OpenTelemetry Collector
grpcurl \
-plaintext \
-v \
-d @ \
-proto opentelemetry-proto/opentelemetry/proto/collector/logs/v1/logs_service.proto \
-import-path ./opentelemetry-proto \
<collector-hostname>:4317 \
<<EOF
opentelemetry.proto.collector.logs.v1.LogsService/Export {
"resourceLogs": [
{
"resource": {},
"scopeLogs": [
{
"scope": {},
"logRecords": [
{
"observedTimeUnixNano": "1664827200000000000",
"body": {
"stringValue": "🪵🪵🪵🪵 This is the sample log message."
},
"attributes": [
{
"key": "log.file.name",
"value": {
"stringValue": "access_log"
}
}
],
"traceId": "",
"spanId": ""
}
]
}
]
}
]
}
EOF
Output:
Resolved method descriptor:
// For performance reasons, it is recommended to keep this RPC
// alive for the entire life of the application.
rpc Export ( .opentelemetry.proto.collector.logs.v1.ExportLogsServiceRequest ) returns ( .opentelemetry.proto.collector.logs.v1.ExportLogsServiceResponse );
Request metadata to send:
(empty)
Response headers received:
content-type: application/grpc
Response contents:
{
"partialSuccess": {}
}
Response trailers received:
(empty)
Sent 1 request and received 1 response
If you have configured a detailed
-level debug
exporter in your Collector:
exporters:
debug/detailed:
verbosity: detailed
service:
pipelines:
logs:
receivers:
...
processors:
...
exporters:
- debug/detailed
you should see the output appear in the Collector’s output:
2024-10-11T08:20:30.377-0500 info LogsExporter {"kind": "exporter", "data_type": "logs", "name": "debug/detailed", "resource logs": 1, "log records": 1}
2024-10-11T08:20:30.378-0500 info ResourceLog #0
Resource SchemaURL:
Resource attributes:
-> env: Str(otel)
-> datadog.host.use_as_metadata: Bool(true)
ScopeLogs #0
ScopeLogs SchemaURL:
InstrumentationScope
LogRecord #0
ObservedTimestamp: 2022-10-03 20:00:00 +0000 UTC
Timestamp: 1970-01-01 00:00:00 +0000 UTC
SeverityText:
SeverityNumber: Unspecified(0)
Body: Str(🪵🪵🪵🪵 This is the sample log message.)
Attributes:
-> log.file.name: Str(access_log)
-> env: Str(otel)
Trace ID:
Span ID:
Flags: 0
{"kind": "exporter", "data_type": "logs", "name": "debug/detailed"}