Skip to content

Commit 4334eda

Browse files
author
Grzegorz Daszuta
committed
Allow gzip compression in exporter
1 parent 450435b commit 4334eda

File tree

6 files changed

+65
-9
lines changed

6 files changed

+65
-9
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ npm install @microlabs/otel-cf-workers @opentelemetry/api
1212
> To be able to use the Open Telemetry library you have to add the NodeJS compatibility flag in your `wrangler.toml` file.
1313
1414
```
15+
compatibility_flags = [ "nodejs_compat", "nodejs_zlib" ]
16+
```
17+
18+
alternatively, in recent version nodejs_zlib is enabled by default by nodejs_compat
19+
20+
```
21+
compatibility_date = "2024-09-23"
1522
compatibility_flags = [ "nodejs_compat" ]
1623
```
1724

@@ -44,6 +51,7 @@ const config: ResolveConfigFn = (env: Env, _trigger) => {
4451
exporter: {
4552
url: 'https://api.honeycomb.io/v1/traces',
4653
headers: { 'x-honeycomb-team': env.HONEYCOMB_API_KEY },
54+
compression: 'gzip',
4755
},
4856
service: { name: 'greetings' },
4957
}
@@ -263,6 +271,7 @@ One of the advantages of using Open Telemetry is that it makes it easier to do d
263271

264272
- The worker runtime does not expose accurate timing information to protect against side-channel attacks such as Spectre and will only update the clock on IO, so any CPU heavy processing will look like it takes 0 milliseconds.
265273
- Not everything is auto-instrumented yet. See the lists below for what is and isn't.
274+
- Exporter protocol support is currently limited to http/json.
266275

267276
Triggers:
268277

examples/queue/wrangler.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "queues-example"
22
main = "src/index.ts"
33
compatibility_date = "2023-04-02"
4-
compatibility_flags = [ "nodejs_compat" ]
4+
compatibility_flags = [ "nodejs_compat", "nodejs_zlib ]
55
66
# Worker defines a binding, named "QUEUE", which gives it a capability
77
# to send messages to a Queue, named "my-queue".

examples/quickstart/QUICKSTART_GUIDE.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ npm install @microlabs/otel-cf-workers @opentelemetry/api
1212
npx wrangler secret put HONEYCOMB_API_KEY
1313
```
1414

15-
And set the Node Compatibility flag by adding `compatibility_flags = [ "nodejs_compat" ]`
15+
And set the Node Compatibility flag by adding `compatibility_flags = [ "nodejs_compat", "nodejs_zlib ]`
1616
in your `wrangler.toml`
1717

1818
## Example
@@ -52,6 +52,7 @@ const config: ResolveConfigFn = (env: Env, _trigger: any) => {
5252
exporter: {
5353
url: 'https://api.honeycomb.io/v1/traces',
5454
headers: { 'x-honeycomb-team': env.HONEYCOMB_API_KEY },
55+
compression: 'gzip',
5556
},
5657
service: { name: 'my-service-name' },
5758
}

examples/quickstart/wrangler.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "otel-quickstart-example"
33
main = "src/index.ts"
44
compatibility_date = "2024-09-09"
5-
compatibility_flags = [ "nodejs_compat" ]
5+
compatibility_flags = [ "nodejs_compat", "nodejs_zlib ]
66
77
# [vars]
88
HONEYCOMB_API_KEY = "example"

examples/worker/wrangler.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "otel-test"
22
main = "src/index.ts"
33
compatibility_date = "2023-03-27"
4-
compatibility_flags = [ "nodejs_compat" ]
4+
compatibility_flags = [ "nodejs_compat", "nodejs_zlib ]
55
66
kv_namespaces = [
77
{ binding = "OTEL_TEST", id = "f124c9696873443da0a277ddb75000ca", preview_id = "3569aab8617645d9b8ed4bd1d45c8d96" }

src/exporter.ts

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
import { createExportTraceServiceRequest } from '@opentelemetry/otlp-transformer'
1+
import { createExportTraceServiceRequest, IExportTraceServiceRequest } from '@opentelemetry/otlp-transformer'
22
import { ExportServiceError, OTLPExporterError } from '@opentelemetry/otlp-exporter-base'
33
import { ExportResult, ExportResultCode } from '@opentelemetry/core'
44
import { SpanExporter } from '@opentelemetry/sdk-trace-base'
55
import { unwrap } from './wrap.js'
6+
import { gzip } from 'node:zlib'
67

78
export interface OTLPExporterConfig {
89
url: string
910
headers?: Record<string, string>
11+
compression?: 'gzip'
1012
}
1113

1214
const defaultHeaders: Record<string, string> = {
@@ -17,9 +19,11 @@ const defaultHeaders: Record<string, string> = {
1719
export class OTLPExporter implements SpanExporter {
1820
private headers: Record<string, string>
1921
private url: string
22+
private compression?: string
2023
constructor(config: OTLPExporterConfig) {
2124
this.url = config.url
2225
this.headers = Object.assign({}, defaultHeaders, config.headers)
26+
this.compression = config.compression
2327
}
2428

2529
export(items: any[], resultCallback: (result: ExportResult) => void): void {
@@ -42,19 +46,61 @@ export class OTLPExporter implements SpanExporter {
4246
})
4347
}
4448

45-
send(items: any[], onSuccess: () => void, onError: (error: OTLPExporterError) => void): void {
49+
private async gzipCompress(input: string, options = {}): Promise<Buffer> {
50+
const output = (await new Promise((resolve, reject) => {
51+
gzip(input, options, function (error, result) {
52+
if (error) {
53+
reject(error)
54+
} else {
55+
resolve(result)
56+
}
57+
})
58+
})) as Buffer
59+
60+
return output
61+
}
62+
63+
private async getBody(exportMessage: IExportTraceServiceRequest): Promise<string | Buffer> {
64+
const jsonMessage = JSON.stringify(exportMessage)
65+
66+
if (this.compression === 'gzip') {
67+
return await this.gzipCompress(jsonMessage)
68+
}
69+
70+
return jsonMessage
71+
}
72+
73+
private getHeaders(): HeadersInit {
74+
const headers = { ...this.headers }
75+
76+
if (this.compression === 'gzip') {
77+
headers['content-encoding'] = 'gzip'
78+
}
79+
80+
return headers
81+
}
82+
83+
private async prepareRequest(items: any[]): Promise<RequestInit> {
4684
const exportMessage = createExportTraceServiceRequest(items, {
4785
useHex: true,
4886
useLongBits: false,
4987
})
50-
const body = JSON.stringify(exportMessage)
88+
89+
const body = await this.getBody(exportMessage)
90+
const headers = this.getHeaders()
91+
5192
const params: RequestInit = {
5293
method: 'POST',
53-
headers: this.headers,
94+
headers,
5495
body,
5596
}
5697

57-
unwrap(fetch)(this.url, params)
98+
return params
99+
}
100+
101+
send(items: any[], onSuccess: () => void, onError: (error: OTLPExporterError) => void): void {
102+
this.prepareRequest(items)
103+
.then((params) => unwrap(fetch)(this.url, params))
58104
.then((response) => {
59105
if (response.ok) {
60106
onSuccess()

0 commit comments

Comments
 (0)