1414 * limitations under the License.
1515 */
1616
17- import { Exporter , ExporterBuffer , RootSpan , Span , SpanContext } from '@opencensus/core' ;
17+ import { Exporter , ExporterBuffer , RootSpan , Span as OCSpan , SpanContext } from '@opencensus/core' ;
1818import { logger , Logger } from '@opencensus/core' ;
1919import { auth , JWT } from 'google-auth-library' ;
2020import { google } from 'googleapis' ;
21- // TODO change to use import when types for hex2dec will be available
22- const { hexToDec } : { [ key : string ] : ( input : string ) => string } =
23- require ( 'hex2dec' ) ;
24- import { StackdriverExporterOptions , TracesWithCredentials , TranslatedSpan , TranslatedTrace } from './types' ;
21+
22+ import { getDefaultResource } from './common-utils' ;
23+ import { createAttributes , createLinks , createTimeEvents , getResourceLabels , stringToTruncatableString } from './stackdriver-cloudtrace-utils' ;
24+ import { AttributeValue , Span , SpansWithCredentials , StackdriverExporterOptions } from './types' ;
2525
2626google . options ( { headers : { 'x-opencensus-outgoing-request' : 0x1 } } ) ;
27- const cloudTrace = google . cloudtrace ( 'v1 ' ) ;
27+ const cloudTrace = google . cloudtrace ( 'v2 ' ) ;
2828
2929/** Format and sends span information to Stackdriver */
3030export class StackdriverTraceExporter implements Exporter {
3131 projectId : string ;
3232 exporterBuffer : ExporterBuffer ;
3333 logger : Logger ;
3434 failBuffer : SpanContext [ ] = [ ] ;
35+ private RESOURCE_LABELS : Promise < Record < string , AttributeValue > > ;
3536
3637 constructor ( options : StackdriverExporterOptions ) {
3738 this . projectId = options . projectId ;
3839 this . logger = options . logger || logger . logger ( ) ;
3940 this . exporterBuffer = new ExporterBuffer ( this , options ) ;
41+ this . RESOURCE_LABELS =
42+ getResourceLabels ( getDefaultResource ( this . projectId ) ) ;
4043 }
4144
4245 /**
@@ -54,13 +57,12 @@ export class StackdriverTraceExporter implements Exporter {
5457 * Publishes a list of root spans to Stackdriver.
5558 * @param rootSpans
5659 */
57- publish ( rootSpans : RootSpan [ ] ) {
58- const stackdriverTraces =
59- rootSpans . map ( trace => this . translateTrace ( trace ) ) ;
60+ async publish ( rootSpans : RootSpan [ ] ) {
61+ const spanList = await this . translateSpan ( rootSpans ) ;
6062
61- return this . authorize ( stackdriverTraces )
62- . then ( ( traces : TracesWithCredentials ) => {
63- return this . sendTrace ( traces ) ;
63+ return this . authorize ( spanList )
64+ . then ( ( spans : SpansWithCredentials ) => {
65+ return this . batchWriteSpans ( spans ) ;
6466 } )
6567 . catch ( err => {
6668 for ( const root of rootSpans ) {
@@ -70,51 +72,70 @@ export class StackdriverTraceExporter implements Exporter {
7072 } ) ;
7173 }
7274
73- /**
74- * Translates root span data to Stackdriver's trace format.
75- * @param root
76- */
77- private translateTrace ( root : RootSpan ) : TranslatedTrace {
78- const spanList = root . spans . map ( ( span : Span ) => this . translateSpan ( span ) ) ;
79- spanList . push ( this . translateSpan ( root ) ) ;
80-
81- return { projectId : this . projectId , traceId : root . traceId , spans : spanList } ;
75+ async translateSpan ( rootSpans : RootSpan [ ] ) {
76+ const resourceLabel = await this . RESOURCE_LABELS ;
77+ const spanList : Span [ ] = [ ] ;
78+ rootSpans . forEach ( rootSpan => {
79+ // RootSpan data
80+ spanList . push ( this . createSpan ( rootSpan , resourceLabel ) ) ;
81+ rootSpan . spans . forEach ( span => {
82+ // Builds spans data
83+ spanList . push ( this . createSpan ( span , resourceLabel ) ) ;
84+ } ) ;
85+ } ) ;
86+ return spanList ;
8287 }
8388
84- /**
85- * Translates span data to Stackdriver's span format.
86- * @param span
87- */
88- private translateSpan ( span : Span ) : TranslatedSpan {
89- return {
90- name : span . name ,
91- kind : 'SPAN_KIND_UNSPECIFIED' ,
92- spanId : hexToDec ( span . id ) ,
93- startTime : span . startTime ,
94- endTime : span . endTime ,
95- labels : Object . keys ( span . attributes )
96- . reduce (
97- ( acc , k ) => {
98- acc [ k ] = String ( span . attributes [ k ] ) ;
99- return acc ;
100- } ,
101- { } as Record < string , string > )
89+ private createSpan (
90+ span : OCSpan , resourceLabels : Record < string , AttributeValue > ) : Span {
91+ const spanName =
92+ `projects/${ this . projectId } /traces/${ span . traceId } /spans/${ span . id } ` ;
93+
94+ const spanBuilder : Span = {
95+ name : spanName ,
96+ spanId : span . id ,
97+ displayName : stringToTruncatableString ( span . name ) ,
98+ startTime : span . startTime . toISOString ( ) ,
99+ endTime : span . endTime . toISOString ( ) ,
100+ attributes : createAttributes (
101+ span . attributes , resourceLabels , span . droppedAttributesCount ) ,
102+ timeEvents : createTimeEvents (
103+ span . annotations , span . messageEvents , span . droppedAnnotationsCount ,
104+ span . droppedMessageEventsCount ) ,
105+ links : createLinks ( span . links , span . droppedLinksCount ) ,
106+ status : { code : span . status . code } ,
107+ sameProcessAsParentSpan : ! span . remoteParent ,
108+ childSpanCount : null , // TODO: Consider to add count after pull/332
109+ stackTrace : null , // Unsupported by nodejs
102110 } ;
111+ if ( span . parentSpanId ) {
112+ spanBuilder . parentSpanId = span . parentSpanId ;
113+ }
114+ if ( span . status . message ) {
115+ spanBuilder . status . message = span . status . message ;
116+ }
117+
118+ return spanBuilder ;
103119 }
104120
105121 /**
106- * Sends traces in the Stackdriver format to the service.
107- * @param traces
122+ * Sends new spans to new or existing traces in the Stackdriver format to the
123+ * service.
124+ * @param spans
108125 */
109- private sendTrace ( traces : TracesWithCredentials ) {
126+ private batchWriteSpans ( spans : SpansWithCredentials ) {
110127 return new Promise ( ( resolve , reject ) => {
111- cloudTrace . projects . patchTraces ( traces , ( err : Error ) => {
128+ // TODO: Consider to use gRPC call (BatchWriteSpansRequest) for sending
129+ // data to backend :
130+ // https://cloud.google.com/trace/docs/reference/v2/rpc/google.devtools.
131+ // cloudtrace.v2#google.devtools.cloudtrace.v2.TraceService
132+ cloudTrace . projects . traces . batchWrite ( spans , ( err : Error ) => {
112133 if ( err ) {
113- err . message = `sendTrace error: ${ err . message } ` ;
134+ err . message = `batchWriteSpans error: ${ err . message } ` ;
114135 this . logger . error ( err . message ) ;
115136 reject ( err ) ;
116137 } else {
117- const successMsg = 'sendTrace sucessfully' ;
138+ const successMsg = 'batchWriteSpans sucessfully' ;
118139 this . logger . debug ( successMsg ) ;
119140 resolve ( successMsg ) ;
120141 }
@@ -124,10 +145,10 @@ export class StackdriverTraceExporter implements Exporter {
124145
125146 /**
126147 * Gets the Google Application Credentials from the environment variables,
127- * authenticates the client and calls a method to send the traces data.
148+ * authenticates the client and calls a method to send the spans data.
128149 * @param stackdriverTraces
129150 */
130- private authorize ( stackdriverTraces : TranslatedTrace [ ] ) {
151+ private authorize ( stackdriverSpans : Span [ ] ) {
131152 return auth . getApplicationDefault ( )
132153 . then ( ( client ) => {
133154 let authClient = client . credential as JWT ;
@@ -138,12 +159,12 @@ export class StackdriverTraceExporter implements Exporter {
138159 authClient = authClient . createScoped ( scopes ) ;
139160 }
140161
141- const traces : TracesWithCredentials = {
142- projectId : client . projectId ,
143- resource : { traces : stackdriverTraces } ,
162+ const spans : SpansWithCredentials = {
163+ name : `projects/ ${ this . projectId } ` ,
164+ resource : { spans : stackdriverSpans } ,
144165 auth : authClient
145166 } ;
146- return traces ;
167+ return spans ;
147168 } )
148169 . catch ( ( err ) => {
149170 err . message = `authorize error: ${ err . message } ` ;
0 commit comments