Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,8 @@
<argument>org.apache.druid.extensions.contrib:gce-extensions</argument>
<argument>-c</argument>
<argument>org.apache.druid.extensions.contrib:aliyun-oss-extensions</argument>
<argument>-c</argument>
<argument>org.apache.druid.extensions.contrib:opentelemetry-emitter</argument>
</arguments>
</configuration>
</execution>
Expand Down
166 changes: 166 additions & 0 deletions extensions-contrib/opentelemetry-emitter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
<!--
~ Licensed to the Apache Software Foundation (ASF) under one
~ or more contributor license agreements. See the NOTICE file
~ distributed with this work for additional information
~ regarding copyright ownership. The ASF licenses this file
~ to you under the Apache License, Version 2.0 (the
~ "License"); you may not use this file except in compliance
~ with the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
-->

# OpenTelemetry Emitter

The [OpenTelemetry](https://opentelemetry.io/) emitter generates OpenTelemetry Spans for queries.

## How OpenTelemetry emitter works

The [OpenTelemetry](https://opentelemetry.io/) emitter processes `ServiceMetricEvent` events for the `query/time`
metric. It extracts OpenTelemetry context from
the [query context](https://druid.apache.org/docs/latest/querying/query-context.html). To link druid spans to parent
traces, the query context should contain at least `traceparent` key.
See [context propagation](https://www.w3.org/TR/trace-context/) for more information. If no `traceparent` key is
provided, then spans are created without `parentTraceId` and are not linked to the parent span. In addition, the emitter
also adds other druid context entries to the span attributes.

## Configuration

### Enabling

To enable the OpenTelemetry emitter, add the extension and enable the emitter in `common.runtime.properties`.

Load the plugin:

```
druid.extensions.loadList=[..., "opentelemetry-emitter"]
```

Then there are 2 options:

* You want to use only `opentelemetry-emitter`

```
druid.emitter=opentelemetry
```

* You want to use `opentelemetry-emitter` with other emitters

```
druid.emitter=composing
druid.emitter.composing.emitters=[..., "opentelemetry"]
```

_*More about Druid configuration [here](https://druid.apache.org/docs/latest/configuration/index.html)._

## Testing

### Part 1: Run zipkin and otel-collector

Create `docker-compose.yaml` in your working dir:

```
version: "2"
services:

zipkin-all-in-one:
image: openzipkin/zipkin:latest
ports:
- "9411:9411"

otel-collector:
image: otel/opentelemetry-collector:latest
command: ["--config=otel-local-config.yaml", "${OTELCOL_ARGS}"]
volumes:
- ${PWD}/config.yaml:/otel-local-config.yaml
ports:
- "4317:4317"
```

Create `config.yaml` file with configuration for otel-collector:

```
version: "2"
receivers:
receivers:
otlp:
protocols:
grpc:

exporters:
zipkin:
endpoint: "http://zipkin-all-in-one:9411/api/v2/spans"
format: proto

logging:

processors:
batch:

service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [logging, zipkin]
```

*_How to configure otel-collector you can read [here](https://opentelemetry.io/docs/collector/configuration/)._

Run otel-collector and zipkin.

```
docker-compose up
```

### Part 2: Run Druid

Build Druid:

```
mvn clean install -Pdist
tar -C /tmp -xf distribution/target/apache-druid-0.21.0-bin.tar.gz
cd /tmp/apache-druid-0.21.0
```

Edit `conf/druid/single-server/micro-quickstart/_common/common.runtime.properties` to enable the emitter (
see `Configuration` section above).

Start the quickstart with the apppropriate environment variables for opentelemetry autoconfiguration:

```
OTEL_SERVICE_NAME="org.apache.druid" OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4317" bin/start-micro-quickstart
```

*_More about opentelemetry
autoconfiguration [here](https://github.com/open-telemetry/opentelemetry-java/tree/main/sdk-extensions/autoconfigure)_

Load sample data - [example](https://druid.apache.org/docs/latest/tutorials/index.html#step-4-load-data).

### Part 3: Send queries

Create `query.json`:

```
{
"query":"SELECT COUNT(*) as total FROM wiki WHERE countryName IS NOT NULL",
"context":{
"traceparent":"00-54ef39243e3feb12072e0f8a74c1d55a-ad6d5b581d7c29c1-01"
}
}
```

Send query:

```
curl -XPOST -H'Content-Type: application/json' http://localhost:8888/druid/v2/sql/ -d @query.json
```

Then open `http://localhost:9411/zipkin/` and you can see there your spans.
217 changes: 217 additions & 0 deletions extensions-contrib/opentelemetry-emitter/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Licensed to the Apache Software Foundation (ASF) under one
~ or more contributor license agreements. See the NOTICE file
~ distributed with this work for additional information
~ regarding copyright ownership. The ASF licenses this file
~ to you under the Apache License, Version 2.0 (the
~ "License"); you may not use this file except in compliance
~ with the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.apache.druid</groupId>
<artifactId>druid</artifactId>
<version>0.23.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

<groupId>org.apache.druid.extensions.contrib</groupId>
<artifactId>opentelemetry-emitter</artifactId>
<name>opentelemetry-emitter</name>
<description>Extension support for emitting OpenTelemetry spans for Druid queries</description>

<properties>
<opentelemetry.version>1.7.0</opentelemetry.version>
<opentelemetry.instrumentation.version>1.7.0-alpha</opentelemetry.instrumentation.version>
<!-- These guava and grpc versions are used only in the opentelemetry-extension.
Look at build section for more details about shading. -->
<shade.guava.version>30.1.1-jre</shade.guava.version>
<shade.grpc.version>1.41.0</shade.grpc.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-bom</artifactId>
<version>${opentelemetry.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-bom-alpha</artifactId>
<version>${opentelemetry.version}-alpha</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-instrumentation-bom-alpha</artifactId>
<version>${opentelemetry.instrumentation.version}</version>
<type>pom</type>
<scope>compile</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.druid</groupId>
<artifactId>druid-core</artifactId>
<version>${project.parent.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-context</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-trace</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-common</artifactId>
</dependency>
<!-- OpenTelemetry extension bundles the OpenTelemetry auto-instrumentation,
So it could potentially affect performance -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-extension-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>${shade.grpc.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${shade.guava.version}</version>
</dependency>
<!-- explicitly include perfmark dependency of grpc we exclude from the shaded jar
Note: we could use promoteTransitiveDependencies=true in the shade plugin, but that promotes all
transitive dependencies as well, which unnecessarily pollutes the final pom -->
<dependency>
<groupId>io.perfmark</groupId>
<artifactId>perfmark-api</artifactId>
<version>0.23.0</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>pl.pragmatists</groupId>
<artifactId>JUnitParams</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<configuration>
<ignoredUnusedDeclaredDependencies>
<!-- Transitive dependencies from opentelemetry but explicitly added to be shadowed -->
<ignoredUnusedDeclaredDependency>io.grpc:grpc-netty-shaded</ignoredUnusedDeclaredDependency>
<ignoredUnusedDeclaredDependency>com.google.guava:guava</ignoredUnusedDeclaredDependency>
</ignoredUnusedDeclaredDependencies>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<id>opentelemetry-extension</id>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<!-- grpc stores service providers in META-INF/services/* files,
so we need to relocate the class names of the implementation classes.
More about SPI - https://docs.oracle.com/javase/tutorial/ext/basics/spi.html.
https://maven.apache.org/plugins/maven-shade-plugin/examples/resource-transformers.html. -->
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
<artifactSet>
<includes>
<include>io.opentelemetry</include>
<include>io.grpc</include>
<include>com.google.guava</include>
</includes>
</artifactSet>
<relocations>
<relocation>
<pattern>com.google.common</pattern>
<shadedPattern>org.apache.druid.opentelemetry.shaded.com.google.common</shadedPattern>
</relocation>
<relocation>
<pattern>io.grpc</pattern>
<shadedPattern>org.apache.druid.opentelemetry.shaded.io.grpc</shadedPattern>
<includes>
<include>io.grpc.*</include>
</includes>
</relocation>
<relocation>
<pattern>io.opentelemetry</pattern>
<shadedPattern>org.apache.druid.opentelemetry.shaded.io.opentelemetry</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Loading