Skip to content
This repository was archived by the owner on Oct 3, 2023. It is now read-only.

Commit f522ce2

Browse files
authored
Exporter/Stackdriver: Support Exemplar in Stackdriver TimeSeries (#520)
* Add Exporter/Stackdriver: Support Exemplar in Stackdriver TimeSeries. * Add helper function to convert OC attachments to SD * update CHANGELOG
1 parent 8481335 commit f522ce2

File tree

4 files changed

+112
-5
lines changed

4 files changed

+112
-5
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file.
44

55
## Unreleased
66

7+
- Exporter/Stats/Stackdriver: Add support for exemplar
8+
79
## 0.0.13 - 2019-05-20
810
- Exporter/Stats/Prometheus: Fix missing tags for HTTP metrics
911
- http-instrumentation: add support for the addition of custom attributes to spans

packages/opencensus-exporter-stackdriver/src/stackdriver-monitoring-utils.ts

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,26 @@
1414
* limitations under the License.
1515
*/
1616

17-
import {BucketOptions, DistributionBucket, DistributionValue, LabelKey, LabelValue, Metric, MetricDescriptor as OCMetricDescriptor, MetricDescriptorType, TimeSeriesPoint, Timestamp} from '@opencensus/core';
17+
import {BucketOptions, DistributionBucket, DistributionValue, Exemplar as OCExemplar, LabelKey, LabelValue, Metric, MetricDescriptor as OCMetricDescriptor, MetricDescriptorType, TimeSeriesPoint, Timestamp} from '@opencensus/core';
1818
import * as os from 'os';
1919
import * as path from 'path';
20-
import {Distribution, LabelDescriptor, MetricDescriptor, MetricKind, MonitoredResource, Point, TimeSeries, ValueType} from './types';
20+
import {Any, Distribution, Exemplar, LabelDescriptor, MetricDescriptor, MetricKind, MonitoredResource, Point, TimeSeries, ValueType} from './types';
2121

2222
const OPENCENSUS_TASK = 'opencensus_task';
2323
const OPENCENSUS_TASK_DESCRIPTION = 'Opencensus task identifier';
2424
export const OPENCENSUS_TASK_VALUE_DEFAULT = generateDefaultTaskValue();
2525

26+
const EXEMPLAR_ATTACHMENT_TYPE_STRING =
27+
'type.googleapis.com/google.protobuf.StringValue';
28+
// TODO: add support for SpanContext attachment.
29+
// const EXEMPLAR_ATTACHMENT_TYPE_SPAN_CONTEXT =
30+
// 'type.googleapis.com/google.monitoring.v3.SpanContext';
31+
const ATTACHMENT_KEY_SPAN_CONTEXT = 'SpanContext';
32+
33+
// TODO: add support for dropped label attachment.
34+
// const EXEMPLAR_ATTACHMENT_TYPE_DROPPED_LABELS =
35+
// 'type.googleapis.com/google.monitoring.v3.DroppedLabels';
36+
2637
/** Converts a OpenCensus MetricDescriptor to a StackDriver MetricDescriptor. */
2738
export function createMetricDescriptorData(
2839
metricDescriptor: OCMetricDescriptor, metricPrefix: string,
@@ -189,7 +200,8 @@ function createDistribution(distribution: DistributionValue): Distribution {
189200
explicitBuckets:
190201
{bounds: createExplicitBucketOptions(distribution.bucketOptions)}
191202
},
192-
bucketCounts: createBucketCounts(distribution.buckets)
203+
bucketCounts: createBucketCounts(distribution.buckets),
204+
exemplars: createExemplars(distribution.buckets)
193205
};
194206
}
195207

@@ -216,6 +228,36 @@ function createBucketCounts(buckets: DistributionBucket[]): number[] {
216228
return bucketCounts;
217229
}
218230

231+
/** Converts a OpenCensus Buckets to a list of proto Exemplars. */
232+
function createExemplars(buckets: DistributionBucket[]): Exemplar[] {
233+
return buckets.filter((bucket => !!bucket.exemplar))
234+
.map((bucket) => ({
235+
value: bucket.exemplar!.value,
236+
timestamp: toISOString(bucket.exemplar!.timestamp),
237+
attachments: _createAttachments(bucket.exemplar!)
238+
}))
239+
.filter((exemplar) => exemplar.attachments.length > 0);
240+
}
241+
242+
function _createAttachments(exemplar: OCExemplar): Any[] {
243+
return Object.keys(exemplar.attachments)
244+
.map((key) => {
245+
if (key === ATTACHMENT_KEY_SPAN_CONTEXT) {
246+
// TODO: add support for SpanContext
247+
// attachment.
248+
return null;
249+
} else {
250+
// Everything else will be treated as plain
251+
// strings for now.
252+
return {
253+
'@type': EXEMPLAR_ATTACHMENT_TYPE_STRING,
254+
value: exemplar.attachments[key]
255+
};
256+
}
257+
})
258+
.filter(attachment => !!attachment) as Any[];
259+
}
260+
219261
/** Returns a task label value in the format of 'nodejs-<pid>@<hostname>'. */
220262
function generateDefaultTaskValue(): string {
221263
const pid = process.pid;

packages/opencensus-exporter-stackdriver/src/types.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ export interface Distribution {
195195
sumOfSquaredDeviation: number;
196196
bucketOptions: {explicitBuckets: {bounds: Bucket[];}};
197197
bucketCounts: number[];
198+
exemplars?: Exemplar[];
198199
}
199200

200201
export interface Point {
@@ -224,3 +225,32 @@ export interface MonitoredResource {
224225
/** Set of labels that describe the resource. */
225226
labels: {[key: string]: string};
226227
}
228+
229+
/**
230+
* Exemplars are example points that may be used to annotate aggregated
231+
* Distribution values. They are metadata that gives information about a
232+
* particular value added to a Distribution bucket.
233+
*/
234+
export interface Exemplar {
235+
/** Value of the exemplar point. */
236+
value: number;
237+
/** The observation (sampling) time of the above value. */
238+
timestamp: string;
239+
/** Contextual information about the example value. */
240+
attachments: Any[];
241+
}
242+
243+
/**
244+
* `Any` contains an arbitrary serialized protocol buffer message along with a
245+
* URL that describes the type of the serialized message.
246+
*/
247+
export interface Any {
248+
/**
249+
* A URL/resource name that uniquely identifies the type of the serialized
250+
* protocol buffer message.
251+
*/
252+
'@type': string;
253+
254+
/** Must be a valid serialized protocol buffer of the above specified type. */
255+
value: string;
256+
}

packages/opencensus-exporter-stackdriver/test/test-stackdriver-monitoring-utils.ts

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,12 +157,35 @@ describe('Stackdriver Stats Exporter Utils', () => {
157157
});
158158

159159
describe('createDistribution()', () => {
160+
const attachments = {'k1': 'v1'};
161+
const spanContext = {
162+
traceId: '3ad17e665f514aabb896341f670179ed',
163+
spanId: '3aaeb440a89d9e82',
164+
options: 0x1
165+
};
160166
const distributionValue: DistributionValue = {
161167
count: 3,
162168
sum: 2,
163169
sumOfSquaredDeviation: 14,
164170
bucketOptions: {explicit: {bounds: [1.0, 3.0, 5.0]}},
165-
buckets: [{count: 3}, {count: 1}, {count: 2}, {count: 4}],
171+
buckets: [
172+
{
173+
count: 3,
174+
exemplar: {
175+
value: 5,
176+
timestamp: {seconds: 1450000000, nanos: 0},
177+
attachments
178+
}
179+
},
180+
{count: 1}, {count: 2}, {
181+
count: 4,
182+
exemplar: {
183+
value: 5,
184+
timestamp: {seconds: 1450000000, nanos: 0},
185+
attachments: {'SpanContext': `'${spanContext}'`}
186+
}
187+
}
188+
],
166189
};
167190
it('should return a Stackdriver Distribution', () => {
168191
const distribution: Distribution =
@@ -175,6 +198,15 @@ describe('Stackdriver Stats Exporter Utils', () => {
175198
distribution.bucketOptions,
176199
{explicitBuckets: {bounds: [0, 1, 3, 5]}});
177200
assert.deepStrictEqual(distribution.bucketCounts, [0, 3, 1, 2, 4]);
201+
assert.deepStrictEqual(
202+
distribution.exemplars, [{
203+
'attachments': [{
204+
'@type': 'type.googleapis.com/google.protobuf.StringValue',
205+
'value': 'v1'
206+
}],
207+
'timestamp': '2015-12-13T09:46:40.Z',
208+
'value': 5
209+
}]);
178210
});
179211
});
180212

@@ -290,7 +322,8 @@ describe('Stackdriver Stats Exporter Utils', () => {
290322
mean: 0.6666666666666666,
291323
sumOfSquaredDeviation: 14,
292324
bucketOptions: {explicitBuckets: {bounds: [0, 1.2, 3.2, 5.2]}},
293-
bucketCounts: [0, 3, 1, 2, 4]
325+
bucketCounts: [0, 3, 1, 2, 4],
326+
exemplars: []
294327
}
295328
},
296329
interval: {

0 commit comments

Comments
 (0)