Skip to content

Commit

Permalink
Added another test
Browse files Browse the repository at this point in the history
  • Loading branch information
davidwitten committed Jun 18, 2020
1 parent 791b0aa commit bbfaae7
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,4 @@
*/

export * from './CollectorExporter';

export * from './CollectorMetricExporter';
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ const DEFAULT_COLLECTOR_URL = 'localhost:55678';
*/
export class CollectorMetricExporter extends CollectorMetricExporterBase {
grpcMetricsQueue: GRPCMetricQueueItem[] = [];

metricServiceClient?: MetricsServiceClient = undefined;
credentials: grpc.ChannelCredentials;
isShutDown: boolean = false;
Expand Down Expand Up @@ -103,7 +102,7 @@ export class CollectorMetricExporter extends CollectorMetricExporterBase {
if (err) {
this.logger.error(
'exportTraceServiceRequest',
{} // exportMetricServiceRequest
exportMetricServiceRequest
);
onError(err);
} else {
Expand Down
47 changes: 23 additions & 24 deletions packages/opentelemetry-exporter-collector/src/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,16 +248,6 @@ export function toCollectorExportTraceServiceRequest<
};
}

export function toStringKeyValue(labels: {
[key: string]: string;
}): opentelemetryProto.common.v1.StringKeyValue[] {
const collectorLabels: opentelemetryProto.common.v1.StringKeyValue[] = [];
for (const [key, value] of Object.entries(labels)) {
collectorLabels.push({ key: key, value: value });
}
return [];
}

export function getCollectorPoints(metric: MetricRecord) {
const metricKind = metric.descriptor.metricKind;
const valueType = metric.descriptor.valueType;
Expand All @@ -268,7 +258,8 @@ export function toCollectorMetricDescriptor(
metric: MetricRecord
): opentelemetryProto.metrics.v1.MetricDescriptor {
let type: opentelemetryProto.metrics.v1.MetricDescriptor_Type;
const temporality = opentelemetryProto.metrics.v1.MetricDescriptor_Temporality.CUMULATIVE;
const temporality =
opentelemetryProto.metrics.v1.MetricDescriptor_Temporality.CUMULATIVE;

if (metric.descriptor.valueType === apiValueType.INT) {
if (metric.descriptor.monotonic) {
Expand All @@ -287,7 +278,6 @@ export function toCollectorMetricDescriptor(
} else {
type = opentelemetryProto.metrics.v1.MetricDescriptor_Type.INVALID_TYPE;
}


return {
name: metric.descriptor.name,
Expand All @@ -303,21 +293,30 @@ export function toCollectorMetric(
metric: MetricRecord,
startTime: number
): opentelemetryProto.metrics.v1.Metric {
let int64DataPoints: opentelemetryProto.metrics.v1.Int64DataPoint[] = [];
let doubleDataPoints: opentelemetryProto.metrics.v1.DoubleDataPoint[] = [];

const points = {
labels: toCollectorLabels(metric.labels),
value: metric.aggregator.toPoint().value as number,
startTimeUnixNano: startTime,
timeUnixNano: core.hrTimeToNanoseconds(
metric.aggregator.toPoint().timestamp
),
};

if (metric.descriptor.valueType == apiValueType.INT) {
int64DataPoints = [points];
} else if (metric.descriptor.valueType === apiValueType.DOUBLE) {
doubleDataPoints = [points];
}

return {
metricDescriptor: toCollectorMetricDescriptor(metric),
doubleDataPoints: [],
histogramDataPoints: [],
doubleDataPoints,
int64DataPoints,
summaryDataPoints: [],
int64DataPoints: [
{
labels: toCollectorLabels(metric.labels),
value: metric.aggregator.toPoint().value as number,
startTimeUnixNano: startTime,
timeUnixNano: core.hrTimeToNanoseconds(
metric.aggregator.toPoint().timestamp
),
},
],
histogramDataPoints: [],
};
}

Expand Down
9 changes: 4 additions & 5 deletions packages/opentelemetry-exporter-collector/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,12 @@ export namespace opentelemetryProto {
value: number;
count: number;
sum: number;
buckets: opentelemetryProto.metrics.v1.HistogramDataPoint_Bucket;
buckets: opentelemetryProto.metrics.v1.HistogramDataPointBucket;
explicitBounds: number[];
}

export interface HistogramDataPoint_Bucket {
export interface HistogramDataPointBucket {
count: number;
exemplar: number; // CHANGE LATER
}

export interface SummaryDataPoint {
Expand All @@ -108,10 +107,10 @@ export namespace opentelemetryProto {
value: number;
count: number;
sum: number;
percentileValues: opentelemetryProto.metrics.v1.SummaryDataPoint_ValueAtPercentile[];
percentileValues: opentelemetryProto.metrics.v1.SummaryDataPointValueAtPercentile[];
}

export interface SummaryDataPoint_ValueAtPercentile {
export interface SummaryDataPointValueAtPercentile {
percentile: number;
value: number;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/*!
* Copyright 2020, OpenTelemetry Authors
*
* Licensed 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
*
* https://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.
*/

import { ExportResult, NoopLogger } from '@opentelemetry/core';
import * as assert from 'assert';
import * as sinon from 'sinon';
import { CollectorMetricExporterBase } from '../../src/CollectorMetricExporterBase';
import { ExporterOptions } from '../../src/types';
import { MetricRecord, MeterProvider } from '@opentelemetry/metrics';
import { Labels } from '@opentelemetry/api';

class CollectorMetricExporter extends CollectorMetricExporterBase {
onInit() {}
onShutdown() {}
sendMetrics() {}
getDefaultUrl(url: string) { return url || '';}
}

describe('CollectorMetricExporter - common', () => {
let collectorExporter: CollectorMetricExporter;
let collectorExporterConfig: ExporterOptions;
let records: MetricRecord[];
describe('constructor', () => {
let onInitSpy: any;

beforeEach(() => {
onInitSpy = sinon.stub(CollectorMetricExporter.prototype, 'onInit');
collectorExporterConfig = {
hostName: 'foo',
logger: new NoopLogger(),
serviceName: 'bar',
attributes: {},
url: 'http://foo.bar.com',
};
collectorExporter = new CollectorMetricExporter(collectorExporterConfig);
const meter = new MeterProvider().getMeter('test-meter');
const labels: Labels = { ['keyb']: 'value2', ['keya']: 'value1' };
const counter = meter.createCounter('name', {
labelKeys: ['keya', 'keyb'],
});
counter.bind(labels).add(10);
meter.collect();
records = meter.getBatcher().checkPointSet();
});

afterEach(() => {
onInitSpy.restore();
});

it('should create an instance', () => {
assert.ok(typeof collectorExporter !== 'undefined');
});

it('should call onInit', () => {
assert.strictEqual(onInitSpy.callCount, 1);
});

describe('when config contains certain params', () => {
it('should set hostName', () => {
assert.strictEqual(collectorExporter.hostName, 'foo');
});

it('should set serviceName', () => {
assert.strictEqual(collectorExporter.serviceName, 'bar');
});

it('should set url', () => {
assert.strictEqual(collectorExporter.url, 'http://foo.bar.com');
});

it('should set logger', () => {
assert.ok(collectorExporter.logger === collectorExporterConfig.logger);
});
});

describe('when config is missing certain params', () => {
beforeEach(() => {
collectorExporter = new CollectorMetricExporter();
});

it('should set default serviceName', () => {
assert.strictEqual(collectorExporter.serviceName, 'collector-metric-exporter');
});

it('should set default logger', () => {
assert.ok(collectorExporter.logger instanceof NoopLogger);
});
});
});

describe('export', () => {
let spySend: any;
beforeEach(() => {
spySend = sinon.stub(CollectorMetricExporter.prototype, 'sendMetrics');
collectorExporter = new CollectorMetricExporter(collectorExporterConfig);
});
afterEach(() => {
spySend.restore();
});

it('should export spans as collectorTypes.Spans', done => {
const metrics: MetricRecord[] = [];
metrics.push(Object.assign({}, records[0]));

collectorExporter.export(metrics, () => {});
setTimeout(() => {
const metric1 = spySend.args[0][0][0] as MetricRecord;
assert.deepStrictEqual(metrics[0], metric1);
done();
});
assert.strictEqual(spySend.callCount, 1);
});

describe('when exporter is shutdown', () => {
it('should not export anything but return callback with code "FailedNotRetryable"', () => {
const metrics: MetricRecord[] = [];
metrics.push(Object.assign({}, records[0]));
collectorExporter.shutdown();
spySend.resetHistory();

const callbackSpy = sinon.spy();
collectorExporter.export(metrics, callbackSpy);
const returnCode = callbackSpy.args[0][0];

assert.strictEqual(
returnCode,
ExportResult.FAILED_NOT_RETRYABLE,
'return value is wrong'
);
assert.strictEqual(spySend.callCount, 0, 'should not call send');
});
});
});

describe('shutdown', () => {
let onShutdownSpy: any;
beforeEach(() => {
onShutdownSpy = sinon.stub(CollectorMetricExporter.prototype, 'onShutdown');
collectorExporterConfig = {
hostName: 'foo',
logger: new NoopLogger(),
serviceName: 'bar',
attributes: {},
url: 'http://foo.bar.com',
};
collectorExporter = new CollectorMetricExporter(collectorExporterConfig);
});
afterEach(() => {
onShutdownSpy.restore();
});

it('should call onShutdown', done => {
collectorExporter.shutdown();
setTimeout(() => {
assert.equal(onShutdownSpy.callCount, 1);
done();
});
});
});
});

0 comments on commit bbfaae7

Please sign in to comment.