Skip to content

Commit

Permalink
Using @types/web package for CompressionStream usage
Browse files Browse the repository at this point in the history
  • Loading branch information
scheler committed Feb 19, 2024
1 parent 6e4bebb commit bd2b25b
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const { WebTracerProvider } = require( '@opentelemetry/sdk-trace-web');
const { XMLHttpRequestInstrumentation } = require( '@opentelemetry/instrumentation-xml-http-request');
const { ZoneContextManager } = require( '@opentelemetry/context-zone');
const { OTLPTraceExporter } = require( '@opentelemetry/exporter-trace-otlp-http');
const { CompressionAlgorithm } = require('@opentelemetry/otlp-exporter-base');
const { B3Propagator } = require( '@opentelemetry/propagator-b3');
const { registerInstrumentations } = require( '@opentelemetry/instrumentation');

Expand All @@ -13,7 +14,11 @@ const providerWithZone = new WebTracerProvider();
// to your exporter. Using the SimpleSpanProcessor here as it sends the spans immediately to the
// exporter without delay
providerWithZone.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter()));
providerWithZone.addSpanProcessor(new SimpleSpanProcessor(new OTLPTraceExporter()));

const exporterOptions = {};
// Note: test the GZIP compression, you can use the following exporterOptions
// exporterOptions = { compression: CompressionAlgorithm.GZIP }
providerWithZone.addSpanProcessor(new SimpleSpanProcessor(new OTLPTraceExporter( exporterOptions)));

providerWithZone.register({
contextManager: new ZoneContextManager(),
Expand Down
1 change: 1 addition & 0 deletions experimental/packages/otlp-exporter-base/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
"@opentelemetry/api": "1.7.0",
"@types/mocha": "10.0.6",
"@types/node": "18.6.5",
"@types/web":"0.0.135",
"@types/sinon": "10.0.20",
"babel-plugin-istanbul": "6.1.1",
"codecov": "3.8.3",
Expand Down
1 change: 1 addition & 0 deletions experimental/packages/otlp-exporter-base/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export {
OTLPExporterError,
OTLPExporterConfigBase,
ExportServiceError,
CompressionAlgorithm
} from './types';
export {
parseHeaders,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,18 +155,19 @@ export function sendWithXhr(
};

if (compressionAlgorithm === CompressionAlgorithm.GZIP) {

const sendRequest = (requestBody: string | Blob) => {

const send = (body: string | Blob) => {
xhr.send(body);
};

const sendCompressed = (body: string | Blob) => {
const sendCompressed = (body: string | Blob | Uint8Array) => {
xhr.setRequestHeader('Content-Encoding', 'gzip'); // Set the Content-Encoding header to 'gzip' for compressed requests
xhr.send(body);
};

compressContent(requestBody)
compressContent(requestBody, compressionAlgorithm)
.then(sendCompressed)
.catch(() => {
send(requestBody); // Send the original body when compression fails
Expand All @@ -182,66 +183,43 @@ export function sendWithXhr(
sendWithRetry();
}

// src/compressionUtils.ts
export function compressContent(input: string | Blob): Promise<Blob> {
return new Promise((resolve, reject) => {
let contentBytes: Uint8Array;

if (typeof input === 'string') {
// Convert the string to a Uint8Array
contentBytes = new TextEncoder().encode(input);
} else if (input instanceof Blob) {
// Read the Blob content into a Uint8Array
const reader = new FileReader();
reader.onloadend = () => {
const arrayBuffer = reader.result as ArrayBuffer;
contentBytes = new Uint8Array(arrayBuffer);
compressBytes(contentBytes)
.then(resolve)
.catch(reject);
};
reader.onerror = reject;
reader.readAsArrayBuffer(input);
return;
} else {
reject(new Error('Unsupported input type. Expected string or Blob.'));
return;
}
async function compressContent(content: string | Blob, compressionAlgorithm: string): Promise<Uint8Array> {

compressBytes(contentBytes)
.then(resolve)
.catch(reject);
});
}
const compressionStream = new CompressionStream(compressionAlgorithm as CompressionFormat);

function compressBytes(contentBytes: Uint8Array): Promise<Blob> {
return new Promise((resolve, reject) => {
const writableStream = new WritableStream<Uint8Array>({
write(chunk: Uint8Array, controller: WritableStreamDefaultController) {
const compressedChunk = new CompressionStream('gzip').writable.getWriter();
compressedChunk.write(chunk)
.then(() => {
compressedChunk.close();
controller.write(chunk);
})
.catch(reject);
},
close() {
resolve(new Blob([contentBytes], { type: 'application/octet-stream' }));
},
abort() {
reject(new Error('Compression aborted.'));
},
});
// Create a new readable stream from the input content
const reader = typeof content === 'string' ? new ReadableStream({ start(controller) {
controller.enqueue(new TextEncoder().encode(content));
controller.close();
}}) : content.stream();

const readableStream = new ReadableStream<Uint8Array>({
start(controller: ReadableStreamDefaultController) {
controller.enqueue(contentBytes);
controller.close();
},
});
// Pipe the readable stream through the compression stream
const compressedStream = reader.pipeThrough(compressionStream);

// Create a new Uint8Array to hold the compressed data
const compressedChunks: Uint8Array[] = [];

// Read the compressed data from the stream and collect it into chunks
const readerStream = compressedStream.getReader();
try {
while (true) {
const { done, value } = await readerStream.read();
if (done) break;
if (value instanceof Uint8Array) {
compressedChunks.push(value);
}
}
} finally {
readerStream.releaseLock();
}

// Concatenate the compressed chunks into a single Uint8Array
const compressedData = new Uint8Array(compressedChunks.reduce((totalLength, chunk) => totalLength + chunk.length, 0));
let offset = 0;
for (const chunk of compressedChunks) {
compressedData.set(chunk, offset);
offset += chunk.length;
}

readableStream.pipeTo(writableStream)
.catch(reject);
});
return compressedData;
}
27 changes: 27 additions & 0 deletions experimental/packages/otlp-exporter-base/test/browser/util.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import * as sinon from 'sinon';
import { CompressionAlgorithm } from '../../src/types';
import { sendWithXhr } from '../../src/platform/browser/util';
import { nextTick } from 'process';
import { ensureHeadersContain } from '../testHelper';
Expand Down Expand Up @@ -63,6 +64,7 @@ describe('util - browser', () => {
url,
explicitContentType,
exporterTimeout,
CompressionAlgorithm.NONE,
onSuccessStub,
onErrorStub
);
Expand Down Expand Up @@ -95,6 +97,7 @@ describe('util - browser', () => {
url,
emptyHeaders,
exporterTimeout,
CompressionAlgorithm.NONE,
onSuccessStub,
onErrorStub
);
Expand Down Expand Up @@ -126,6 +129,7 @@ describe('util - browser', () => {
url,
customHeaders,
exporterTimeout,
CompressionAlgorithm.NONE,
onSuccessStub,
onErrorStub
);
Expand Down Expand Up @@ -155,5 +159,28 @@ describe('util - browser', () => {
});
});
});
describe('and gzip compression is supported', () => {
beforeEach(() => {
const exporterTimeout = 10000;
sendWithXhr(
body,
url,
{},
exporterTimeout,
CompressionAlgorithm.GZIP,
onSuccessStub,
onErrorStub
);
});

it('should set "Content-Encoding" header to "gzip"', done => {
nextTick(() => {
const { requestHeaders } = server.requests[0];
ensureHeadersContain(requestHeaders, { 'Content-Encoding': 'gzip' });
clock.restore();
done();
});
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import * as assert from 'assert';
import { configureExporterTimeout, invalidTimeout } from '../../src/util';
import { sendWithHttp } from '../../src/platform/node/util';
import { CompressionAlgorithm } from '../../src/platform/node/types';
import { CompressionAlgorithm } from '../../src/types';
import { configureCompression } from '../../src/platform/node/util';
import { diag } from '@opentelemetry/api';
import * as sinon from 'sinon';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
OTLPExporterBrowserBase as OTLPExporterBaseMain,
OTLPExporterError,
OTLPExporterConfigBase,
CompressionAlgorithm,
sendWithXhr,
} from '@opentelemetry/otlp-exporter-base';

Expand Down Expand Up @@ -64,6 +65,7 @@ export abstract class OTLPProtoExporterBrowserBase<
Accept: 'application/x-protobuf',
},
this.timeoutMillis,
CompressionAlgorithm.NONE,
onSuccess,
onError
);
Expand Down

0 comments on commit bd2b25b

Please sign in to comment.