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

Commit

Permalink
exporter/Zipkin: Add missing fields (Annotation,Status,MessageEvent …
Browse files Browse the repository at this point in the history
…etc) (#345)

* exporter/Zipkin: Add missing fields (Annotation, Status, MessageEvent etc)

* Add comments

* fix review comments

1. Rename messageEventTypeTranslation -> MESSAGE_EVENT_TYPE_TRANSLATION.
2. Add constant MICROS_PER_MILLI
3. Fix typo

* update changelog
  • Loading branch information
mayurkale22 authored Feb 18, 2019
1 parent 3638ca5 commit 9d592e6
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 23 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file.
## Unreleased

- Add optional `compressedSize` and `uncompressedSize` params to `Span.addMessageEvent`
- Add support for ```tags```, ```status``` and ```annotation``` in Zipkin exporter.

## 0.0.9 - 2019-02-12
- Add Metrics API.
Expand Down
11 changes: 7 additions & 4 deletions packages/opencensus-exporter-zipkin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,16 @@ Instance the exporter on your application and pass the options, it must contain
For javascript:

```javascript
var tracing = require('@opencensus/nodejs');
var zipkin = require('@opencensus/exporter-zipkin');
const tracing = require('@opencensus/nodejs');
const zipkin = require('@opencensus/exporter-zipkin');

// Add your zipkin url (ex http://localhost:9411/api/v2/spans)
// and application name to the Zipkin options
var options = {
const options = {
url: 'your-zipkin-url',
serviceName: 'your-application-name'
}
var exporter = new zipkin.ZipkinTraceExporter(options);
const exporter = new zipkin.ZipkinTraceExporter(options);
```

Similarly for Typescript:
Expand Down Expand Up @@ -65,10 +65,13 @@ or
```javascript
tracing.registerExporter(exporter).start();
```
## Viewing your traces:
Please visit the Zipkin UI endpoint http://localhost:9411

## Useful links
- For more information on OpenCensus, visit: <https://opencensus.io/>
- To checkout the OpenCensus for Node.js, visit: <https://github.com/census-instrumentation/opencensus-node>
- For Zipkin project at https://zipkin.io/
- For help or feedback on this project, join us on [gitter](https://gitter.im/census-instrumentation/Lobby)

[gitter-image]: https://badges.gitter.im/census-instrumentation/lobby.svg
Expand Down
80 changes: 71 additions & 9 deletions packages/opencensus-exporter-zipkin/src/zipkin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,22 @@
* limitations under the License.
*/

import {Exporter, ExporterBuffer, ExporterConfig, RootSpan, Span} from '@opencensus/core';
import * as coreTypes from '@opencensus/core';
import {Exporter, ExporterBuffer, ExporterConfig, RootSpan, Span, SpanKind} from '@opencensus/core';
import {logger, Logger} from '@opencensus/core';
import {prototype} from 'events';
import * as http from 'http';
import * as url from 'url';

const STATUS_CODE = 'census.status_code';
const STATUS_DESCRIPTION = 'census.status_description';

const MESSAGE_EVENT_TYPE_TRANSLATION: {[k: number]: string} = {
0: 'UNSPECIFIED',
1: 'SENT',
2: 'RECEIVED'
};
export const MICROS_PER_MILLI = 1000;

export interface ZipkinExporterOptions extends ExporterConfig {
url?: string;
serviceName: string;
Expand All @@ -31,11 +41,18 @@ interface TranslatedSpan {
id: string;
parentId?: string;
kind: string;
timestamp: number;
timestamp: number; // in microseconds
duration: number;
debug: boolean;
shared: boolean;
localEndpoint: {serviceName: string};
annotations: Annotation[];
tags: {[key: string]: string};
}

interface Annotation {
timestamp?: number; // in microseconds
value?: string;
}

/** Zipkin Exporter manager class */
Expand Down Expand Up @@ -138,23 +155,68 @@ export class ZipkinTraceExporter implements Exporter {
* @param span Span to be translated
* @param rootSpan Only necessary if the span has rootSpan
*/
private translateSpan(span: Span|RootSpan): TranslatedSpan {
translateSpan(span: Span|RootSpan): TranslatedSpan {
const spanTraslated = {
traceId: span.traceId,
name: span.name,
id: span.id,
parentId: span.parentSpanId,
kind: 'SERVER',
timestamp: span.startTime.getTime() * 1000,
duration: Math.round(span.duration * 1000),
// Zipkin API for span kind only accept
// (CLIENT|SERVER|PRODUCER|CONSUMER)
kind: span.kind === SpanKind.CLIENT ? 'CLIENT' : 'SERVER',
timestamp: span.startTime.getTime() * MICROS_PER_MILLI,
duration: Math.round(span.duration * MICROS_PER_MILLI),
debug: true,
shared: true,
localEndpoint: {serviceName: this.serviceName}
localEndpoint: {serviceName: this.serviceName},
tags: this.createTags(span.attributes, span.status),
annotations: this.createAnnotations(span.annotations, span.messageEvents)
} as TranslatedSpan;

if (span.parentSpanId) {
spanTraslated.parentId = span.parentSpanId;
}
return spanTraslated;
}

/** Converts OpenCensus Attributes ans Status to Zipkin Tags format. */
private createTags(
attributes: coreTypes.Attributes, status: coreTypes.Status) {
const tags: {[key: string]: string} = {};
for (const key of Object.keys(attributes)) {
tags[key] = String(attributes[key]);
}
tags[STATUS_CODE] = String(status.code);
if (status.message) {
tags[STATUS_DESCRIPTION] = status.message;
}
return tags;
}

/**
* Converts OpenCensus Annotation and MessageEvent to Zipkin Annotations
* format.
*/
private createAnnotations(
annotationTimedEvents: coreTypes.Annotation[],
messageEventTimedEvents: coreTypes.MessageEvent[]) {
let annotations: Annotation[] = [];
if (annotationTimedEvents) {
annotations = annotationTimedEvents.map(
(annotation) => ({
timestamp: annotation.timestamp * MICROS_PER_MILLI,
value: annotation.description
}));
}
if (messageEventTimedEvents) {
annotations.push(...messageEventTimedEvents.map(
(messageEvent) => ({
timestamp: messageEvent.timestamp * MICROS_PER_MILLI,
value: MESSAGE_EVENT_TYPE_TRANSLATION[messageEvent.type]
})));
}
return annotations;
}

// TODO: review return of method publish from exporter interface - today is
// returning void
/**
Expand Down
79 changes: 69 additions & 10 deletions packages/opencensus-exporter-zipkin/test/test-zipkin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,11 @@
* limitations under the License.
*/

import {CoreTracer, RootSpan, SpanKind, TracerConfig} from '@opencensus/core';
import {CanonicalCode, CoreTracer, MessageEventType, RootSpan, SpanKind, TracerConfig} from '@opencensus/core';
import * as assert from 'assert';
import * as http from 'http';
import * as mocha from 'mocha';
import * as nock from 'nock';

import {ZipkinExporterOptions, ZipkinTraceExporter} from '../src/zipkin';

/** Interface with request response model */
interface RequestResponse {
statusCode: number;
statusMessage: string;
}
import {MICROS_PER_MILLI, ZipkinExporterOptions, ZipkinTraceExporter} from '../src/zipkin';

/** Zipkin host url */
const zipkinHost = 'http://localhost:9411';
Expand Down Expand Up @@ -109,6 +101,73 @@ describe('Zipkin Exporter', function() {
});
});

describe('translateSpan()', () => {
it('should translate traces to Zipkin format', () => {
const exporter = new ZipkinTraceExporter(zipkinOptions);
const tracer = new CoreTracer();
tracer.start(defaultConfig);

return tracer.startRootSpan({name: 'root-test'}, (rootSpan: RootSpan) => {
const span = rootSpan.startChildSpan('spanTest', SpanKind.CLIENT);
span.addAttribute('my-int-attribute', 100);
span.addAttribute('my-str-attribute', 'value');
span.addAttribute('my-bool-attribute', true);
span.setStatus(CanonicalCode.RESOURCE_EXHAUSTED, 'RESOURCE_EXHAUSTED');

span.addAnnotation('processing', {}, 1550213104708);
span.addMessageEvent(MessageEventType.SENT, '1', 1550213104708);
span.addMessageEvent(MessageEventType.RECEIVED, '2', 1550213104708);
span.addMessageEvent(MessageEventType.UNSPECIFIED, '3', 1550213104708);
span.addAnnotation('done', {}, 1550213104708);
span.end();
rootSpan.end();

const rootSpanTranslated = exporter.translateSpan(rootSpan);
assert.deepEqual(rootSpanTranslated, {
'annotations': [],
'debug': true,
'duration': Math.round(rootSpan.duration * MICROS_PER_MILLI),
'id': rootSpan.id,
'kind': 'SERVER',
'localEndpoint': {'serviceName': 'opencensus-tests'},
'name': 'root-test',
'shared': true,
'tags': {'census.status_code': '0'},
'timestamp': rootSpan.startTime.getTime() * MICROS_PER_MILLI,
'traceId': rootSpan.traceId
});

const chilsSpanTranslated = exporter.translateSpan(span);
assert.deepEqual(chilsSpanTranslated, {
'annotations': [
{'timestamp': 1550213104708000, 'value': 'processing'},
{'timestamp': 1550213104708000, 'value': 'done'},
{'timestamp': 1550213104708000, 'value': 'SENT'},
{'timestamp': 1550213104708000, 'value': 'RECEIVED'},
{'timestamp': 1550213104708000, 'value': 'UNSPECIFIED'}
],
'debug': true,
'duration': Math.round(span.duration * MICROS_PER_MILLI),
'id': span.id,
'kind': 'CLIENT',
'localEndpoint': {'serviceName': 'opencensus-tests'},
'name': 'spanTest',
'parentId': rootSpan.id,
'shared': true,
'tags': {
'census.status_code': '8',
'census.status_description': 'RESOURCE_EXHAUSTED',
'my-int-attribute': '100',
'my-str-attribute': 'value',
'my-bool-attribute': 'true'
},
'timestamp': span.startTime.getTime() * MICROS_PER_MILLI,
'traceId': span.traceId
});
});
});
});

describe('publish() with a wrong Zipkin url', () => {
it('shouldn\'t send traces to Zipkin service and return an 404 error',
() => {
Expand Down

0 comments on commit 9d592e6

Please sign in to comment.