github.com/mier85/go-sensor@v1.30.1-0.20220920111756-9bf41b3bc7e0/registered_span.go (about) 1 // (c) Copyright IBM Corp. 2021 2 // (c) Copyright Instana Inc. 2021 3 4 package instana 5 6 import ( 7 "strings" 8 9 "github.com/opentracing/opentracing-go/ext" 10 ) 11 12 // Registered types supported by Instana. The span type is determined based on 13 // the operation name passed to the `StartSpan()` call of a tracer. 14 // 15 // It is NOT RECOMMENDED to use operation names that match any of these constants in your 16 // custom instrumentation code unless you explicitly wish to send data as a registered span. 17 // The list of supported tags can be found in the godoc of the respective span tags type below. 18 const ( 19 // SDK span, a generic span containing arbitrary data. Spans with operation name 20 // not listed in the subsequent list will be sent as an SDK spans forwarding all 21 // attached tags to the agent 22 SDKSpanType = RegisteredSpanType("sdk") 23 // HTTP server and client spans 24 HTTPServerSpanType = RegisteredSpanType("g.http") 25 HTTPClientSpanType = RegisteredSpanType("http") 26 // RPC server and client spans 27 RPCServerSpanType = RegisteredSpanType("rpc-server") 28 RPCClientSpanType = RegisteredSpanType("rpc-client") 29 // Kafka consumer/producer span 30 KafkaSpanType = RegisteredSpanType("kafka") 31 // Google Cloud Storage client span 32 GCPStorageSpanType = RegisteredSpanType("gcs") 33 // Google Cloud PubSub client span 34 GCPPubSubSpanType = RegisteredSpanType("gcps") 35 // AWS Lambda entry span 36 AWSLambdaEntrySpanType = RegisteredSpanType("aws.lambda.entry") 37 // AWS S3 client span 38 AWSS3SpanType = RegisteredSpanType("s3") 39 // AWS SQS client span 40 AWSSQSSpanType = RegisteredSpanType("sqs") 41 // AWS SNS client span 42 AWSSNSSpanType = RegisteredSpanType("sns") 43 // AWS DynamoDB client span 44 AWSDynamoDBSpanType = RegisteredSpanType("dynamodb") 45 // AWS Lambda invoke span 46 AWSLambdaInvokeSpanType = RegisteredSpanType("aws.lambda.invoke") 47 // Logging span 48 LogSpanType = RegisteredSpanType("log.go") 49 // MongoDB client span 50 MongoDBSpanType = RegisteredSpanType("mongo") 51 // PostgreSQL client span 52 PostgreSQLSpanType = RegisteredSpanType("postgres") 53 // Redis client span 54 RedisSpanType = RegisteredSpanType("redis") 55 // RabbitMQ client span 56 RabbitMQSpanType = RegisteredSpanType("rabbitmq") 57 ) 58 59 // RegisteredSpanType represents the span type supported by Instana 60 type RegisteredSpanType string 61 62 // extractData is a factory method to create the `data` section for a typed span 63 func (st RegisteredSpanType) extractData(span *spanS) typedSpanData { 64 switch st { 65 case HTTPServerSpanType, HTTPClientSpanType: 66 return newHTTPSpanData(span) 67 case RPCServerSpanType, RPCClientSpanType: 68 return newRPCSpanData(span) 69 case KafkaSpanType: 70 return newKafkaSpanData(span) 71 case GCPStorageSpanType: 72 return newGCPStorageSpanData(span) 73 case GCPPubSubSpanType: 74 return newGCPPubSubSpanData(span) 75 case AWSLambdaEntrySpanType: 76 return newAWSLambdaSpanData(span) 77 case AWSS3SpanType: 78 return newAWSS3SpanData(span) 79 case AWSSQSSpanType: 80 return newAWSSQSSpanData(span) 81 case AWSSNSSpanType: 82 return newAWSSNSSpanData(span) 83 case AWSDynamoDBSpanType: 84 return newAWSDynamoDBSpanData(span) 85 case AWSLambdaInvokeSpanType: 86 return newAWSLambdaInvokeSpanData(span) 87 case LogSpanType: 88 return newLogSpanData(span) 89 case MongoDBSpanType: 90 return newMongoDBSpanData(span) 91 case PostgreSQLSpanType: 92 return newPostgreSQLSpanData(span) 93 case RedisSpanType: 94 return newRedisSpanData(span) 95 case RabbitMQSpanType: 96 return newRabbitMQSpanData(span) 97 default: 98 return newSDKSpanData(span) 99 } 100 } 101 102 // TagsNames returns a set of tag names known to the registered span type 103 func (st RegisteredSpanType) TagsNames() map[string]struct{} { 104 var yes struct{} 105 106 switch st { 107 case HTTPServerSpanType, HTTPClientSpanType: 108 return map[string]struct{}{ 109 "http.url": yes, string(ext.HTTPUrl): yes, 110 "http.status": yes, "http.status_code": yes, 111 "http.method": yes, string(ext.HTTPMethod): yes, 112 "http.path": yes, 113 "http.params": yes, 114 "http.header": yes, 115 "http.path_tpl": yes, 116 "http.route_id": yes, 117 "http.host": yes, 118 "http.protocol": yes, 119 "http.error": yes, 120 } 121 case RPCServerSpanType, RPCClientSpanType: 122 return map[string]struct{}{ 123 "rpc.host": yes, 124 "rpc.port": yes, 125 "rpc.call": yes, 126 "rpc.call_type": yes, 127 "rpc.flavor": yes, 128 "rpc.error": yes, 129 } 130 case KafkaSpanType: 131 return map[string]struct{}{ 132 "kafka.service": yes, 133 "kafka.access": yes, 134 } 135 case GCPStorageSpanType: 136 return map[string]struct{}{ 137 "gcs.op": yes, 138 "gcs.bucket": yes, 139 "gcs.object": yes, 140 "gcs.entity": yes, 141 "gcs.range": yes, 142 "gcs.sourceBucket": yes, 143 "gcs.sourceObject": yes, 144 "gcs.destinationBucket": yes, 145 "gcs.destinationObject": yes, 146 "gcs.numberOfOperations": yes, 147 "gcs.projectId": yes, 148 "gcs.accessId": yes, 149 } 150 case GCPPubSubSpanType: 151 return map[string]struct{}{ 152 "gcps.projid": yes, 153 "gcps.op": yes, 154 "gcps.top": yes, 155 "gcps.sub": yes, 156 "gcps.msgid": yes, 157 } 158 case AWSLambdaEntrySpanType: 159 return map[string]struct{}{ 160 "lambda.arn": yes, 161 "lambda.name": yes, 162 "lambda.version": yes, 163 "lambda.trigger": yes, 164 "lambda.coldStart": yes, 165 "lambda.msleft": yes, 166 "lambda.error": yes, 167 "cloudwatch.events.id": yes, 168 "cloudwatch.events.resources": yes, 169 "cloudwatch.logs.group": yes, 170 "cloudwatch.logs.stream": yes, 171 "cloudwatch.logs.decodingError": yes, 172 "cloudwatch.logs.events": yes, 173 "s3.events": yes, 174 "sqs.messages": yes, 175 } 176 case AWSS3SpanType: 177 return map[string]struct{}{ 178 "s3.region": yes, 179 "s3.op": yes, 180 "s3.bucket": yes, 181 "s3.key": yes, 182 "s3.error": yes, 183 } 184 case AWSSQSSpanType: 185 return map[string]struct{}{ 186 "sqs.sort": yes, 187 "sqs.queue": yes, 188 "sqs.type": yes, 189 "sqs.group": yes, 190 "sqs.size": yes, 191 "sqs.error": yes, 192 } 193 case AWSSNSSpanType: 194 return map[string]struct{}{ 195 "sns.topic": yes, 196 "sns.target": yes, 197 "sns.phone": yes, 198 "sns.subject": yes, 199 "sns.error": yes, 200 } 201 case AWSDynamoDBSpanType: 202 return map[string]struct{}{ 203 "dynamodb.table": yes, 204 "dynamodb.op": yes, 205 "dynamodb.error": yes, 206 } 207 case AWSLambdaInvokeSpanType: 208 return map[string]struct{}{ 209 "function": yes, 210 "type": yes, 211 "error": yes, 212 } 213 case LogSpanType: 214 return map[string]struct{}{ 215 "log.message": yes, 216 "log.level": yes, 217 "log.parameters": yes, 218 "log.logger": yes, 219 } 220 case MongoDBSpanType: 221 return map[string]struct{}{ 222 "mongo.service": yes, 223 "mongo.namespace": yes, 224 "mongo.command": yes, 225 "mongo.query": yes, 226 "mongo.json": yes, 227 "mongo.filter": yes, 228 "mongo.error": yes, 229 } 230 case PostgreSQLSpanType: 231 return map[string]struct{}{ 232 "pg.db": yes, 233 "pg.user": yes, 234 "pg.stmt": yes, 235 "pg.host": yes, 236 "pg.port": yes, 237 "pg.error": yes, 238 } 239 case RedisSpanType: 240 return map[string]struct{}{ 241 "redis.connection": yes, 242 "redis.command": yes, 243 "redis.subCommands": yes, 244 "redis.error": yes, 245 } 246 case RabbitMQSpanType: 247 return map[string]struct{}{ 248 "rabbitmq.exchange": yes, 249 "rabbitmq.key": yes, 250 "rabbitmq.sort": yes, 251 "rabbitmq.address": yes, 252 "rabbitmq.error": yes, 253 } 254 default: 255 return nil 256 } 257 } 258 259 // HTTPSpanData represents the `data` section of an HTTP span sent within an OT span document 260 type HTTPSpanData struct { 261 SpanData 262 Tags HTTPSpanTags `json:"http"` 263 264 clientSpan bool 265 } 266 267 // newHTTPSpanData initializes a new HTTP span data from tracer span 268 func newHTTPSpanData(span *spanS) HTTPSpanData { 269 data := HTTPSpanData{ 270 SpanData: NewSpanData(span, RegisteredSpanType(span.Operation)), 271 Tags: newHTTPSpanTags(span), 272 } 273 274 kindTag := span.Tags[string(ext.SpanKind)] 275 data.clientSpan = kindTag == ext.SpanKindRPCClientEnum || kindTag == string(ext.SpanKindRPCClientEnum) 276 277 return data 278 } 279 280 // Kind returns instana.EntrySpanKind for server spans and instana.ExitSpanKind otherwise 281 func (d HTTPSpanData) Kind() SpanKind { 282 if d.clientSpan { 283 return ExitSpanKind 284 } 285 286 return EntrySpanKind 287 } 288 289 // HTTPSpanTags contains fields within the `data.http` section of an OT span document 290 type HTTPSpanTags struct { 291 // Full request/response URL 292 URL string `json:"url,omitempty"` 293 // The HTTP status code returned with client/server response 294 Status int `json:"status,omitempty"` 295 // The HTTP method of the request 296 Method string `json:"method,omitempty"` 297 // Path is the path part of the request URL 298 Path string `json:"path,omitempty"` 299 // Params are the request query string parameters 300 Params string `json:"params,omitempty"` 301 // Headers are the captured request/response headers 302 Headers map[string]string `json:"header,omitempty"` 303 // PathTemplate is the raw template string used to route the request 304 PathTemplate string `json:"path_tpl,omitempty"` 305 // RouteID is an optional name/identifier for the matched route 306 RouteID string `json:"route_id,omitempty"` 307 // The name:port of the host to which the request had been sent 308 Host string `json:"host,omitempty"` 309 // The name of the protocol used for request ("http" or "https") 310 Protocol string `json:"protocol,omitempty"` 311 // The message describing an error occurred during the request handling 312 Error string `json:"error,omitempty"` 313 } 314 315 // newHTTPSpanTags extracts HTTP-specific span tags from a tracer span 316 func newHTTPSpanTags(span *spanS) HTTPSpanTags { 317 var tags HTTPSpanTags 318 for k, v := range span.Tags { 319 switch k { 320 case "http.url", string(ext.HTTPUrl): 321 readStringTag(&tags.URL, v) 322 case "http.status", "http.status_code": 323 readIntTag(&tags.Status, v) 324 case "http.method", string(ext.HTTPMethod): 325 readStringTag(&tags.Method, v) 326 case "http.path": 327 readStringTag(&tags.Path, v) 328 case "http.params": 329 readStringTag(&tags.Params, v) 330 case "http.header": 331 if m, ok := v.(map[string]string); ok { 332 tags.Headers = m 333 } 334 case "http.path_tpl": 335 readStringTag(&tags.PathTemplate, v) 336 case "http.route_id": 337 readStringTag(&tags.RouteID, v) 338 case "http.host": 339 readStringTag(&tags.Host, v) 340 case "http.protocol": 341 readStringTag(&tags.Protocol, v) 342 case "http.error": 343 readStringTag(&tags.Error, v) 344 } 345 } 346 347 return tags 348 } 349 350 // RPCSpanData represents the `data` section of an RPC span sent within an OT span document 351 type RPCSpanData struct { 352 SpanData 353 Tags RPCSpanTags `json:"rpc"` 354 355 clientSpan bool 356 } 357 358 // newRPCSpanData initializes a new RPC span data from tracer span 359 func newRPCSpanData(span *spanS) RPCSpanData { 360 data := RPCSpanData{ 361 SpanData: NewSpanData(span, RegisteredSpanType(span.Operation)), 362 Tags: newRPCSpanTags(span), 363 } 364 365 kindTag := span.Tags[string(ext.SpanKind)] 366 data.clientSpan = kindTag == ext.SpanKindRPCClientEnum || kindTag == (ext.SpanKindRPCClientEnum) 367 368 return data 369 } 370 371 // Kind returns instana.EntrySpanKind for server spans and instana.ExitSpanKind otherwise 372 func (d RPCSpanData) Kind() SpanKind { 373 if d.clientSpan { 374 return ExitSpanKind 375 } 376 377 return EntrySpanKind 378 } 379 380 // RPCSpanTags contains fields within the `data.rpc` section of an OT span document 381 type RPCSpanTags struct { 382 // The name of the remote host for an RPC call 383 Host string `json:"host,omitempty"` 384 // The port of the remote host for an RPC call 385 Port string `json:"port,omitempty"` 386 // The name of the remote method to invoke 387 Call string `json:"call,omitempty"` 388 // The type of an RPC call, e.g. either "unary" or "stream" for GRPC requests 389 CallType string `json:"call_type,omitempty"` 390 // The RPC flavor used for this call, e.g. "grpc" for GRPC requests 391 Flavor string `json:"flavor,omitempty"` 392 // The message describing an error occurred during the request handling 393 Error string `json:"error,omitempty"` 394 } 395 396 // newRPCSpanTags extracts RPC-specific span tags from a tracer span 397 func newRPCSpanTags(span *spanS) RPCSpanTags { 398 var tags RPCSpanTags 399 for k, v := range span.Tags { 400 switch k { 401 case "rpc.host": 402 readStringTag(&tags.Host, v) 403 case "rpc.port": 404 readStringTag(&tags.Port, v) 405 case "rpc.call": 406 readStringTag(&tags.Call, v) 407 case "rpc.call_type": 408 readStringTag(&tags.CallType, v) 409 case "rpc.flavor": 410 readStringTag(&tags.Flavor, v) 411 case "rpc.error": 412 readStringTag(&tags.Error, v) 413 } 414 } 415 416 return tags 417 } 418 419 // KafkaSpanData represents the `data` section of an Kafka span sent within an OT span document 420 type KafkaSpanData struct { 421 SpanData 422 Tags KafkaSpanTags `json:"kafka"` 423 424 producerSpan bool 425 } 426 427 // newKafkaSpanData initializes a new Kafka span data from tracer span 428 func newKafkaSpanData(span *spanS) KafkaSpanData { 429 data := KafkaSpanData{ 430 SpanData: NewSpanData(span, RegisteredSpanType(span.Operation)), 431 Tags: newKafkaSpanTags(span), 432 } 433 434 kindTag := span.Tags[string(ext.SpanKind)] 435 data.producerSpan = kindTag == ext.SpanKindProducerEnum || kindTag == string(ext.SpanKindProducerEnum) 436 437 return data 438 } 439 440 // Kind returns instana.ExitSpanKind for producer spans and instana.EntrySpanKind otherwise 441 func (d KafkaSpanData) Kind() SpanKind { 442 if d.producerSpan { 443 return ExitSpanKind 444 } 445 446 return EntrySpanKind 447 } 448 449 // KafkaSpanTags contains fields within the `data.kafka` section of an OT span document 450 type KafkaSpanTags struct { 451 // Kafka topic 452 Service string `json:"service"` 453 // The access mode:, either "send" for publisher or "consume" for consumer 454 Access string `json:"access"` 455 } 456 457 // newKafkaSpanTags extracts Kafka-specific span tags from a tracer span 458 func newKafkaSpanTags(span *spanS) KafkaSpanTags { 459 var tags KafkaSpanTags 460 for k, v := range span.Tags { 461 switch k { 462 case "kafka.service": 463 readStringTag(&tags.Service, v) 464 case "kafka.access": 465 readStringTag(&tags.Access, v) 466 } 467 } 468 469 return tags 470 } 471 472 // RabbitMQSpanData represents the `data` section of an RabbitMQ span 473 type RabbitMQSpanData struct { 474 SpanData 475 Tags RabbitMQSpanTags `json:"rabbitmq"` 476 477 producerSpan bool 478 } 479 480 // newRabbitMQSpanData initializes a new RabbitMQ span data from tracer span 481 func newRabbitMQSpanData(span *spanS) RabbitMQSpanData { 482 data := RabbitMQSpanData{ 483 SpanData: NewSpanData(span, RegisteredSpanType(span.Operation)), 484 Tags: newRabbitMQSpanTags(span), 485 } 486 487 kindTag := span.Tags[string(ext.SpanKind)] 488 data.producerSpan = kindTag == ext.SpanKindProducerEnum || kindTag == string(ext.SpanKindProducerEnum) 489 490 return data 491 } 492 493 // Kind returns instana.ExitSpanKind for producer spans and instana.EntrySpanKind otherwise 494 func (d RabbitMQSpanData) Kind() SpanKind { 495 if d.producerSpan { 496 return ExitSpanKind 497 } 498 499 return EntrySpanKind 500 } 501 502 // RabbitMQSpanTags contains fields within the `data.rabbitmq` section 503 type RabbitMQSpanTags struct { 504 // The RabbitMQ exchange name 505 Exchange string `json:"exchange"` 506 // The routing key 507 Key string `json:"key"` 508 // Indicates wether the message is being produced or consumed 509 Sort string `json:"sort"` 510 // The AMQP URI used to establish a connection to RabbitMQ 511 Address string `json:"address"` 512 // Error is the optional error that can be thrown by RabbitMQ when executing a command 513 Error string `json:"error,omitempty"` 514 } 515 516 // newRabbitMQSpanTags extracts RabbitMQ-specific span tags from a tracer span 517 func newRabbitMQSpanTags(span *spanS) RabbitMQSpanTags { 518 var tags RabbitMQSpanTags 519 for k, v := range span.Tags { 520 switch k { 521 case "rabbitmq.exchange": 522 readStringTag(&tags.Exchange, v) 523 case "rabbitmq.key": 524 readStringTag(&tags.Key, v) 525 case "rabbitmq.sort": 526 readStringTag(&tags.Sort, v) 527 case "rabbitmq.address": 528 readStringTag(&tags.Address, v) 529 case "rabbitmq.error": 530 readStringTag(&tags.Error, v) 531 } 532 } 533 534 return tags 535 } 536 537 // GCPStorageSpanData represents the `data` section of a Google Cloud Storage span sent within an OT span document 538 type GCPStorageSpanData struct { 539 SpanData 540 Tags GCPStorageSpanTags `json:"gcs"` 541 } 542 543 // newGCPStorageSpanData initializes a new Google Cloud Storage span data from tracer span 544 func newGCPStorageSpanData(span *spanS) GCPStorageSpanData { 545 data := GCPStorageSpanData{ 546 SpanData: NewSpanData(span, GCPStorageSpanType), 547 Tags: newGCPStorageSpanTags(span), 548 } 549 550 return data 551 } 552 553 // Kind returns the span kind for a Google Cloud Storage span 554 func (d GCPStorageSpanData) Kind() SpanKind { 555 return ExitSpanKind 556 } 557 558 // GCPStorageSpanTags contains fields within the `data.gcs` section of an OT span document 559 type GCPStorageSpanTags struct { 560 Operation string `json:"op,omitempty"` 561 Bucket string `json:"bucket,omitempty"` 562 Object string `json:"object,omitempty"` 563 Entity string `json:"entity,omitempty"` 564 Range string `json:"range,omitempty"` 565 SourceBucket string `json:"sourceBucket,omitempty"` 566 SourceObject string `json:"sourceObject,omitempty"` 567 DestinationBucket string `json:"destinationBucket,omitempty"` 568 DestinationObject string `json:"destinationObject,omitempty"` 569 NumberOfOperations string `json:"numberOfOperations,omitempty"` 570 ProjectID string `json:"projectId,omitempty"` 571 AccessID string `json:"accessId,omitempty"` 572 } 573 574 // newGCPStorageSpanTags extracts Google Cloud Storage span tags from a tracer span 575 func newGCPStorageSpanTags(span *spanS) GCPStorageSpanTags { 576 var tags GCPStorageSpanTags 577 for k, v := range span.Tags { 578 switch k { 579 case "gcs.op": 580 readStringTag(&tags.Operation, v) 581 case "gcs.bucket": 582 readStringTag(&tags.Bucket, v) 583 case "gcs.object": 584 readStringTag(&tags.Object, v) 585 case "gcs.entity": 586 readStringTag(&tags.Entity, v) 587 case "gcs.range": 588 readStringTag(&tags.Range, v) 589 case "gcs.sourceBucket": 590 readStringTag(&tags.SourceBucket, v) 591 case "gcs.sourceObject": 592 readStringTag(&tags.SourceObject, v) 593 case "gcs.destinationBucket": 594 readStringTag(&tags.DestinationBucket, v) 595 case "gcs.destinationObject": 596 readStringTag(&tags.DestinationObject, v) 597 case "gcs.numberOfOperations": 598 readStringTag(&tags.NumberOfOperations, v) 599 case "gcs.projectId": 600 readStringTag(&tags.ProjectID, v) 601 case "gcs.accessId": 602 readStringTag(&tags.AccessID, v) 603 } 604 } 605 606 return tags 607 } 608 609 // GCPPubSubSpanData represents the `data` section of a Google Cloud Pub/Sub span sent within an OT span document 610 type GCPPubSubSpanData struct { 611 SpanData 612 Tags GCPPubSubSpanTags `json:"gcps"` 613 } 614 615 // newGCPPubSubSpanData initializes a new Google Cloud Pub/Span span data from tracer span 616 func newGCPPubSubSpanData(span *spanS) GCPPubSubSpanData { 617 data := GCPPubSubSpanData{ 618 SpanData: NewSpanData(span, GCPPubSubSpanType), 619 Tags: newGCPPubSubSpanTags(span), 620 } 621 622 return data 623 } 624 625 // Kind returns the span kind for a Google Cloud Pub/Sub span 626 func (d GCPPubSubSpanData) Kind() SpanKind { 627 switch strings.ToLower(d.Tags.Operation) { 628 case "consume": 629 return EntrySpanKind 630 default: 631 return ExitSpanKind 632 } 633 } 634 635 // GCPPubSubSpanTags contains fields within the `data.gcps` section of an OT span document 636 type GCPPubSubSpanTags struct { 637 ProjectID string `json:"projid"` 638 Operation string `json:"op"` 639 Topic string `json:"top,omitempty"` 640 Subscription string `json:"sub,omitempty"` 641 MessageID string `json:"msgid,omitempty"` 642 } 643 644 // newGCPPubSubSpanTags extracts Google Cloud Pub/Sub span tags from a tracer span 645 func newGCPPubSubSpanTags(span *spanS) GCPPubSubSpanTags { 646 var tags GCPPubSubSpanTags 647 for k, v := range span.Tags { 648 switch k { 649 case "gcps.projid": 650 readStringTag(&tags.ProjectID, v) 651 case "gcps.op": 652 readStringTag(&tags.Operation, v) 653 case "gcps.top": 654 readStringTag(&tags.Topic, v) 655 case "gcps.sub": 656 readStringTag(&tags.Subscription, v) 657 case "gcps.msgid": 658 readStringTag(&tags.MessageID, v) 659 } 660 } 661 662 return tags 663 } 664 665 // AWSLambdaCloudWatchSpanTags contains fields within the `data.lambda.cw` section of an OT span document 666 type AWSLambdaCloudWatchSpanTags struct { 667 Events *AWSLambdaCloudWatchEventTags `json:"events,omitempty"` 668 Logs *AWSLambdaCloudWatchLogsTags `json:"logs,omitempty"` 669 } 670 671 // newAWSLambdaCloudWatchSpanTags extracts CloudWatch tags for an AWS Lambda entry span 672 func newAWSLambdaCloudWatchSpanTags(span *spanS) AWSLambdaCloudWatchSpanTags { 673 var tags AWSLambdaCloudWatchSpanTags 674 675 if events := newAWSLambdaCloudWatchEventTags(span); !events.IsZero() { 676 tags.Events = &events 677 } 678 679 if logs := newAWSLambdaCloudWatchLogsTags(span); !logs.IsZero() { 680 tags.Logs = &logs 681 } 682 683 return tags 684 } 685 686 // IsZero returns true if an AWSLambdaCloudWatchSpanTags struct was populated with event data 687 func (tags AWSLambdaCloudWatchSpanTags) IsZero() bool { 688 return (tags.Events == nil || tags.Events.IsZero()) && (tags.Logs == nil || tags.Logs.IsZero()) 689 } 690 691 // AWSLambdaCloudWatchEventTags contains fields within the `data.lambda.cw.events` section of an OT span document 692 type AWSLambdaCloudWatchEventTags struct { 693 // ID is the ID of the event 694 ID string `json:"id"` 695 // Resources contains the event resources 696 Resources []string `json:"resources"` 697 // More is set to true if the event resources list was truncated 698 More bool `json:"more,omitempty"` 699 } 700 701 // newAWSLambdaCloudWatchEventTags extracts CloudWatch event tags for an AWS Lambda entry span. It truncates 702 // the resources list to the first 3 items, populating the `data.lambda.cw.events.more` tag and limits each 703 // resource string to the first 200 characters to reduce the payload. 704 func newAWSLambdaCloudWatchEventTags(span *spanS) AWSLambdaCloudWatchEventTags { 705 var tags AWSLambdaCloudWatchEventTags 706 707 if v, ok := span.Tags["cloudwatch.events.id"]; ok { 708 readStringTag(&tags.ID, v) 709 } 710 711 if v, ok := span.Tags["cloudwatch.events.resources"]; ok { 712 switch v := v.(type) { 713 case []string: 714 if len(v) > 3 { 715 v = v[:3] 716 tags.More = true 717 } 718 719 tags.Resources = v 720 case string: 721 tags.Resources = []string{v} 722 case []byte: 723 tags.Resources = []string{string(v)} 724 } 725 } 726 727 // truncate resources 728 if len(tags.Resources) > 3 { 729 tags.Resources, tags.More = tags.Resources[:3], true 730 } 731 732 for i := range tags.Resources { 733 if len(tags.Resources[i]) > 200 { 734 tags.Resources[i] = tags.Resources[i][:200] 735 } 736 } 737 738 return tags 739 } 740 741 // IsZero returns true if an AWSCloudWatchEventTags struct was populated with event data 742 func (tags AWSLambdaCloudWatchEventTags) IsZero() bool { 743 return tags.ID == "" 744 } 745 746 // AWSLambdaCloudWatchLogsTags contains fields within the `data.lambda.cw.logs` section of an OT span document 747 type AWSLambdaCloudWatchLogsTags struct { 748 Group string `json:"group"` 749 Stream string `json:"stream"` 750 Events []string `json:"events"` 751 More bool `json:"more,omitempty"` 752 DecodingError string `json:"decodingError,omitempty"` 753 } 754 755 // newAWSLambdaCloudWatchLogsTags extracts CloudWatch Logs tags for an AWS Lambda entry span. It truncates 756 // the log events list to the first 3 items, populating the `data.lambda.cw.logs.more` tag and limits each 757 // log string to the first 200 characters to reduce the payload. 758 func newAWSLambdaCloudWatchLogsTags(span *spanS) AWSLambdaCloudWatchLogsTags { 759 var tags AWSLambdaCloudWatchLogsTags 760 761 if v, ok := span.Tags["cloudwatch.logs.group"]; ok { 762 readStringTag(&tags.Group, v) 763 } 764 765 if v, ok := span.Tags["cloudwatch.logs.stream"]; ok { 766 readStringTag(&tags.Stream, v) 767 } 768 769 if v, ok := span.Tags["cloudwatch.logs.decodingError"]; ok { 770 switch v := v.(type) { 771 case error: 772 tags.DecodingError = v.Error() 773 case string: 774 tags.DecodingError = v 775 } 776 } 777 778 if v, ok := span.Tags["cloudwatch.logs.events"]; ok { 779 switch v := v.(type) { 780 case []string: 781 if len(v) > 3 { 782 v = v[:3] 783 tags.More = true 784 } 785 786 tags.Events = v 787 case string: 788 tags.Events = []string{v} 789 case []byte: 790 tags.Events = []string{string(v)} 791 } 792 } 793 794 // truncate events 795 if len(tags.Events) > 3 { 796 tags.Events, tags.More = tags.Events[:3], true 797 } 798 799 for i := range tags.Events { 800 if len(tags.Events[i]) > 200 { 801 tags.Events[i] = tags.Events[i][:200] 802 } 803 } 804 805 return tags 806 } 807 808 // IsZero returns true if an AWSLambdaCloudWatchLogsTags struct was populated with logs data 809 func (tags AWSLambdaCloudWatchLogsTags) IsZero() bool { 810 return tags.Group == "" && tags.Stream == "" && tags.DecodingError == "" 811 } 812 813 // AWSS3EventTags represens metadata for an S3 event 814 type AWSS3EventTags struct { 815 Name string `json:"event"` 816 Bucket string `json:"bucket"` 817 Object string `json:"object,omitempty"` 818 } 819 820 // AWSLambdaS3SpanTags contains fields within the `data.lambda.s3` section of an OT span document 821 type AWSLambdaS3SpanTags struct { 822 Events []AWSS3EventTags `json:"events,omitempty"` 823 } 824 825 // newAWSLambdaS3SpanTags extracts S3 Event tags for an AWS Lambda entry span. It truncates 826 // the events list to the first 3 items and limits each object names to the first 200 characters to reduce the payload. 827 func newAWSLambdaS3SpanTags(span *spanS) AWSLambdaS3SpanTags { 828 var tags AWSLambdaS3SpanTags 829 830 if events, ok := span.Tags["s3.events"]; ok { 831 events, ok := events.([]AWSS3EventTags) 832 if ok { 833 tags.Events = events 834 } 835 } 836 837 if len(tags.Events) > 3 { 838 tags.Events = tags.Events[:3] 839 } 840 841 for i := range tags.Events { 842 if len(tags.Events[i].Object) > 200 { 843 tags.Events[i].Object = tags.Events[i].Object[:200] 844 } 845 } 846 847 return tags 848 } 849 850 // IsZero returns true if an AWSLambdaS3SpanTags struct was populated with events data 851 func (tags AWSLambdaS3SpanTags) IsZero() bool { 852 return len(tags.Events) == 0 853 } 854 855 // AWSSQSMessageTags represents span tags for an SQS message delivery 856 type AWSSQSMessageTags struct { 857 Queue string `json:"queue"` 858 } 859 860 // AWSLambdaSQSSpanTags contains fields within the `data.lambda.sqs` section of an OT span document 861 type AWSLambdaSQSSpanTags struct { 862 // Messages are message tags for an SQS event 863 Messages []AWSSQSMessageTags `json:"messages"` 864 } 865 866 // newAWSLambdaSQSSpanTags extracts SQS event tags for an AWS Lambda entry span. It truncates 867 // the events list to the first 3 items to reduce the payload. 868 func newAWSLambdaSQSSpanTags(span *spanS) AWSLambdaSQSSpanTags { 869 var tags AWSLambdaSQSSpanTags 870 871 if msgs, ok := span.Tags["sqs.messages"]; ok { 872 msgs, ok := msgs.([]AWSSQSMessageTags) 873 if ok { 874 tags.Messages = msgs 875 } 876 } 877 878 if len(tags.Messages) > 3 { 879 tags.Messages = tags.Messages[:3] 880 } 881 882 return tags 883 } 884 885 // IsZero returns true if an AWSLambdaSQSSpanTags struct was populated with messages data 886 func (tags AWSLambdaSQSSpanTags) IsZero() bool { 887 return len(tags.Messages) == 0 888 } 889 890 // AWSLambdaSpanTags contains fields within the `data.lambda` section of an OT span document 891 type AWSLambdaSpanTags struct { 892 // ARN is the ARN of invoked AWS Lambda function with the version attached 893 ARN string `json:"arn"` 894 // Runtime is an Instana constant for this AWS lambda runtime (always "go") 895 Runtime string `json:"runtime"` 896 // Name is the name of invoked function 897 Name string `json:"functionName,omitempty"` 898 // Version is either the numeric version or $LATEST 899 Version string `json:"functionVersion,omitempty"` 900 // Trigger is the trigger event type (if any) 901 Trigger string `json:"trigger,omitempty"` 902 // ColdStart is true if this is the first time current instance of the function was invoked 903 ColdStart bool `json:"coldStart,omitempty"` 904 // MillisecondsLeft is a number of milliseconds until timeout 905 MillisecondsLeft int `json:"msleft,omitempty"` 906 // Error is an AWS Lambda specific error 907 Error string `json:"error,omitempty"` 908 // CloudWatch holds the details of a CloudWatch event associated with this lambda 909 CloudWatch *AWSLambdaCloudWatchSpanTags `json:"cw,omitempty"` 910 // S3 holds the details of a S3 events associated with this lambda 911 S3 *AWSLambdaS3SpanTags 912 // SQS holds the details of a SQS events associated with this lambda 913 SQS *AWSLambdaSQSSpanTags 914 } 915 916 // newAWSLambdaSpanTags extracts AWS Lambda entry span tags from a tracer span 917 func newAWSLambdaSpanTags(span *spanS) AWSLambdaSpanTags { 918 tags := AWSLambdaSpanTags{Runtime: "go"} 919 920 if v, ok := span.Tags["lambda.arn"]; ok { 921 readStringTag(&tags.ARN, v) 922 } 923 924 if v, ok := span.Tags["lambda.name"]; ok { 925 readStringTag(&tags.Name, v) 926 } 927 928 if v, ok := span.Tags["lambda.version"]; ok { 929 readStringTag(&tags.Version, v) 930 } 931 932 if v, ok := span.Tags["lambda.trigger"]; ok { 933 readStringTag(&tags.Trigger, v) 934 } 935 936 if v, ok := span.Tags["lambda.coldStart"]; ok { 937 readBoolTag(&tags.ColdStart, v) 938 } 939 940 if v, ok := span.Tags["lambda.msleft"]; ok { 941 readIntTag(&tags.MillisecondsLeft, v) 942 } 943 944 if v, ok := span.Tags["lambda.error"]; ok { 945 readStringTag(&tags.Error, v) 946 } 947 948 if cw := newAWSLambdaCloudWatchSpanTags(span); !cw.IsZero() { 949 tags.CloudWatch = &cw 950 } 951 952 if st := newAWSLambdaS3SpanTags(span); !st.IsZero() { 953 tags.S3 = &st 954 } 955 956 if sqs := newAWSLambdaSQSSpanTags(span); !sqs.IsZero() { 957 tags.SQS = &sqs 958 } 959 960 return tags 961 } 962 963 // AWSLambdaSpanData is the base span data type for AWS Lambda entry spans 964 type AWSLambdaSpanData struct { 965 Snapshot AWSLambdaSpanTags `json:"lambda"` 966 HTTP *HTTPSpanTags `json:"http,omitempty"` 967 } 968 969 // newAWSLambdaSpanData initializes a new AWSLambdaSpanData from span 970 func newAWSLambdaSpanData(span *spanS) AWSLambdaSpanData { 971 d := AWSLambdaSpanData{ 972 Snapshot: newAWSLambdaSpanTags(span), 973 } 974 975 switch span.Tags["lambda.trigger"] { 976 case "aws:api.gateway", "aws:application.load.balancer": 977 tags := newHTTPSpanTags(span) 978 d.HTTP = &tags 979 } 980 981 return d 982 } 983 984 // Type returns the span type for an AWS Lambda span 985 func (d AWSLambdaSpanData) Type() RegisteredSpanType { 986 return AWSLambdaEntrySpanType 987 } 988 989 // Kind returns the span kind for an AWS Lambda span 990 func (d AWSLambdaSpanData) Kind() SpanKind { 991 return EntrySpanKind 992 } 993 994 // AWSS3SpanData represents the `data` section of a AWS S3 span sent within an OT span document 995 type AWSS3SpanData struct { 996 SpanData 997 Tags AWSS3SpanTags `json:"s3"` 998 } 999 1000 // newAWSS3SpanData initializes a new AWS S3 span data from tracer span 1001 func newAWSS3SpanData(span *spanS) AWSS3SpanData { 1002 data := AWSS3SpanData{ 1003 SpanData: NewSpanData(span, AWSS3SpanType), 1004 Tags: newAWSS3SpanTags(span), 1005 } 1006 1007 return data 1008 } 1009 1010 // Kind returns the span kind for a AWS S3 span 1011 func (d AWSS3SpanData) Kind() SpanKind { 1012 return ExitSpanKind 1013 } 1014 1015 // AWSS3SpanTags contains fields within the `data.s3` section of an OT span document 1016 type AWSS3SpanTags struct { 1017 // Region is the AWS region used to access S3 1018 Region string `json:"region,omitempty"` 1019 // Operation is the operation name, as defined by AWS S3 API 1020 Operation string `json:"op,omitempty"` 1021 // Bucket is the bucket name 1022 Bucket string `json:"bucket,omitempty"` 1023 // Key is the object key 1024 Key string `json:"key,omitempty"` 1025 // Error is an optional error returned by AWS API 1026 Error string `json:"error,omitempty"` 1027 } 1028 1029 // newAWSS3SpanTags extracts AWS S3 span tags from a tracer span 1030 func newAWSS3SpanTags(span *spanS) AWSS3SpanTags { 1031 var tags AWSS3SpanTags 1032 for k, v := range span.Tags { 1033 switch k { 1034 case "s3.region": 1035 readStringTag(&tags.Region, v) 1036 case "s3.op": 1037 readStringTag(&tags.Operation, v) 1038 case "s3.bucket": 1039 readStringTag(&tags.Bucket, v) 1040 case "s3.key": 1041 readStringTag(&tags.Key, v) 1042 case "s3.error": 1043 readStringTag(&tags.Error, v) 1044 } 1045 } 1046 1047 return tags 1048 } 1049 1050 // AWSSQSSpanData represents the `data` section of a AWS SQS span sent within an OT span document 1051 type AWSSQSSpanData struct { 1052 SpanData 1053 Tags AWSSQSSpanTags `json:"sqs"` 1054 } 1055 1056 // newAWSSQSSpanData initializes a new AWS SQS span data from tracer span 1057 func newAWSSQSSpanData(span *spanS) AWSSQSSpanData { 1058 data := AWSSQSSpanData{ 1059 SpanData: NewSpanData(span, AWSSQSSpanType), 1060 Tags: newAWSSQSSpanTags(span), 1061 } 1062 1063 return data 1064 } 1065 1066 // Kind returns the span kind for a AWS SQS span 1067 func (d AWSSQSSpanData) Kind() SpanKind { 1068 switch d.Tags.Sort { 1069 case "entry": 1070 return EntrySpanKind 1071 case "exit": 1072 return ExitSpanKind 1073 default: 1074 return IntermediateSpanKind 1075 } 1076 } 1077 1078 // AWSSQSSpanTags contains fields within the `data.sqs` section of an OT span document 1079 type AWSSQSSpanTags struct { 1080 // Sort is the direction of the call, wither "entry" or "exit" 1081 Sort string `json:"sort,omitempty"` 1082 // Queue is the queue name 1083 Queue string `json:"queue,omitempty"` 1084 // Type is the operation name 1085 Type string `json:"type,omitempty"` 1086 // MessageGroupID is the message group ID specified while sending messages 1087 MessageGroupID string `json:"group,omitempty"` 1088 // Size is the optional batch size 1089 Size int `json:"size,omitempty"` 1090 // Error is an optional error returned by AWS API 1091 Error string `json:"error,omitempty"` 1092 } 1093 1094 // newAWSSQSSpanTags extracts AWS SQS span tags from a tracer span 1095 func newAWSSQSSpanTags(span *spanS) AWSSQSSpanTags { 1096 var tags AWSSQSSpanTags 1097 for k, v := range span.Tags { 1098 switch k { 1099 case "sqs.sort": 1100 readStringTag(&tags.Sort, v) 1101 case "sqs.queue": 1102 readStringTag(&tags.Queue, v) 1103 case "sqs.type": 1104 readStringTag(&tags.Type, v) 1105 case "sqs.group": 1106 readStringTag(&tags.MessageGroupID, v) 1107 case "sqs.size": 1108 readIntTag(&tags.Size, v) 1109 case "sqs.error": 1110 readStringTag(&tags.Error, v) 1111 } 1112 } 1113 1114 return tags 1115 } 1116 1117 // AWSSNSSpanData represents the `data` section of a AWS SNS span sent within an OT span document 1118 type AWSSNSSpanData struct { 1119 SpanData 1120 Tags AWSSNSSpanTags `json:"sns"` 1121 } 1122 1123 // newAWSSNSSpanData initializes a new AWS SNS span data from tracer span 1124 func newAWSSNSSpanData(span *spanS) AWSSNSSpanData { 1125 data := AWSSNSSpanData{ 1126 SpanData: NewSpanData(span, AWSSNSSpanType), 1127 Tags: newAWSSNSSpanTags(span), 1128 } 1129 1130 return data 1131 } 1132 1133 // Kind returns the span kind for a AWS SNS span 1134 func (d AWSSNSSpanData) Kind() SpanKind { 1135 return ExitSpanKind 1136 } 1137 1138 // AWSSNSSpanTags contains fields within the `data.sns` section of an OT span document 1139 type AWSSNSSpanTags struct { 1140 // TopicARN is the topic ARN of an SNS message 1141 TopicARN string `json:"topic,omitempty"` 1142 // TargetARN is the target ARN of an SNS message 1143 TargetARN string `json:"target,omitempty"` 1144 // Phone is the phone no. of an SNS message 1145 Phone string `json:"phone,omitempty"` 1146 // Subject is the subject of an SNS message 1147 Subject string `json:"subject,omitempty"` 1148 // Error is an optional error returned by AWS API 1149 Error string `json:"error,omitempty"` 1150 } 1151 1152 // newAWSSNSSpanTags extracts AWS SNS span tags from a tracer span 1153 func newAWSSNSSpanTags(span *spanS) AWSSNSSpanTags { 1154 var tags AWSSNSSpanTags 1155 for k, v := range span.Tags { 1156 switch k { 1157 case "sns.topic": 1158 readStringTag(&tags.TopicARN, v) 1159 case "sns.target": 1160 readStringTag(&tags.TargetARN, v) 1161 case "sns.phone": 1162 readStringTag(&tags.Phone, v) 1163 case "sns.subject": 1164 readStringTag(&tags.Subject, v) 1165 case "sns.error": 1166 readStringTag(&tags.Error, v) 1167 } 1168 } 1169 1170 return tags 1171 } 1172 1173 // AWSDynamoDBSpanData represents the `data` section of a AWS DynamoDB span sent within an OT span document 1174 type AWSDynamoDBSpanData struct { 1175 SpanData 1176 Tags AWSDynamoDBSpanTags `json:"sns"` 1177 } 1178 1179 // newAWSDynamoDBSpanData initializes a new AWS DynamoDB span data from tracer span 1180 func newAWSDynamoDBSpanData(span *spanS) AWSDynamoDBSpanData { 1181 data := AWSDynamoDBSpanData{ 1182 SpanData: NewSpanData(span, AWSDynamoDBSpanType), 1183 Tags: newAWSDynamoDBSpanTags(span), 1184 } 1185 1186 return data 1187 } 1188 1189 // Kind returns the span kind for a AWS DynamoDB span 1190 func (d AWSDynamoDBSpanData) Kind() SpanKind { 1191 return ExitSpanKind 1192 } 1193 1194 // AWSDynamoDBSpanTags contains fields within the `data.sns` section of an OT span document 1195 type AWSDynamoDBSpanTags struct { 1196 // Table is the name of DynamoDB table 1197 Table string `json:"table,omitempty"` 1198 // Operation is the operation name 1199 Operation string `json:"op,omitempty"` 1200 // Error is an optional name returned by AWS API 1201 Error string `json:"error,omitempty"` 1202 // Region is a region from the AWS session config 1203 Region string `json:"region,omitempty"` 1204 } 1205 1206 // newAWSDynamoDBSpanTags extracts AWS DynamoDB span tags from a tracer span 1207 func newAWSDynamoDBSpanTags(span *spanS) AWSDynamoDBSpanTags { 1208 var tags AWSDynamoDBSpanTags 1209 for k, v := range span.Tags { 1210 switch k { 1211 case "dynamodb.table": 1212 readStringTag(&tags.Table, v) 1213 case "dynamodb.op": 1214 readStringTag(&tags.Operation, v) 1215 case "dynamodb.error": 1216 readStringTag(&tags.Error, v) 1217 case "dynamodb.region": 1218 readStringTag(&tags.Region, v) 1219 } 1220 } 1221 1222 return tags 1223 } 1224 1225 // AWSInvokeSpanTags contains fields within the `aws.lambda.invoke` section of an OT span document 1226 type AWSInvokeSpanTags struct { 1227 // FunctionName is a name of the function which is invoked 1228 FunctionName string `json:"function"` 1229 // InvocationType if equal to `Event`, means it is an async invocation 1230 InvocationType string `json:"type"` 1231 // Error is an optional error returned by AWS API 1232 Error string `json:"error,omitempty"` 1233 } 1234 1235 func newAWSDInvokeSpanTags(span *spanS) AWSInvokeSpanTags { 1236 var tags AWSInvokeSpanTags 1237 for k, v := range span.Tags { 1238 switch k { 1239 case "function": 1240 readStringTag(&tags.FunctionName, v) 1241 case "type": 1242 readStringTag(&tags.InvocationType, v) 1243 case "error": 1244 readStringTag(&tags.Error, v) 1245 } 1246 } 1247 1248 return tags 1249 } 1250 1251 // AWSLambdaInvokeSpanData represents the `data` section of a AWS Invoke span sent within an OT span document 1252 type AWSLambdaInvokeSpanData struct { 1253 SpanData 1254 Tags AWSInvokeSpanTags `json:"aws.lambda.invoke"` 1255 } 1256 1257 // Kind returns the span kind for a AWS SDK Invoke span 1258 func (d AWSLambdaInvokeSpanData) Kind() SpanKind { 1259 return ExitSpanKind 1260 } 1261 1262 // Type returns the span type for an AWS SDK Invoke span 1263 func (d AWSLambdaInvokeSpanData) Type() RegisteredSpanType { 1264 return AWSLambdaInvokeSpanType 1265 } 1266 1267 // newAWSLambdaInvokeSpanData initializes a new AWS Invoke span data from tracer span 1268 func newAWSLambdaInvokeSpanData(span *spanS) AWSLambdaInvokeSpanData { 1269 data := AWSLambdaInvokeSpanData{ 1270 SpanData: NewSpanData(span, AWSLambdaInvokeSpanType), 1271 Tags: newAWSDInvokeSpanTags(span), 1272 } 1273 1274 return data 1275 } 1276 1277 // LogSpanData represents the `data` section of a logging span 1278 type LogSpanData struct { 1279 SpanData 1280 Tags LogSpanTags `json:"log"` 1281 } 1282 1283 // newLogSpanData initializes a new logging span data from tracer span 1284 func newLogSpanData(span *spanS) LogSpanData { 1285 return LogSpanData{ 1286 SpanData: NewSpanData(span, LogSpanType), 1287 Tags: newLogSpanTags(span), 1288 } 1289 } 1290 1291 // Kind returns the span kind for a logging span 1292 func (d LogSpanData) Kind() SpanKind { 1293 return ExitSpanKind 1294 } 1295 1296 // LogSpanTags contains fields within the `data.log` section of an OT span document 1297 type LogSpanTags struct { 1298 // Message is a string to log 1299 Message string `json:"message"` 1300 // Level is an optional log level for this record, e.g. INFO 1301 Level string `json:"level,omitempty"` 1302 // Logger is an optional logger name 1303 Logger string `json:"logger,omitempty"` 1304 // Error is an optional error string (if any) 1305 Error string `json:"parameters,omitempty"` 1306 } 1307 1308 func newLogSpanTags(span *spanS) LogSpanTags { 1309 var tags LogSpanTags 1310 for k, v := range span.Tags { 1311 switch k { 1312 case "log.message": 1313 readStringTag(&tags.Message, v) 1314 case "log.level": 1315 readStringTag(&tags.Level, v) 1316 case "log.parameters": 1317 readStringTag(&tags.Error, v) 1318 case "log.logger": 1319 readStringTag(&tags.Logger, v) 1320 } 1321 } 1322 1323 return tags 1324 } 1325 1326 // MongoDBSpanData represents the `data` section of a MongoDB client span 1327 type MongoDBSpanData struct { 1328 SpanData 1329 Tags MongoDBSpanTags `json:"mongo"` 1330 } 1331 1332 // newMongoDBSpanData initializes a new MongoDB clientspan data from tracer span 1333 func newMongoDBSpanData(span *spanS) MongoDBSpanData { 1334 return MongoDBSpanData{ 1335 SpanData: NewSpanData(span, MongoDBSpanType), 1336 Tags: newMongoDBSpanTags(span), 1337 } 1338 } 1339 1340 // RedisSpanData represents the `data` section of a Redis client span 1341 type RedisSpanData struct { 1342 SpanData 1343 Tags RedisSpanTags `json:"redis"` 1344 } 1345 1346 // newRedisSpanData initializes a new Redis clientspan data from tracer span 1347 func newRedisSpanData(span *spanS) RedisSpanData { 1348 return RedisSpanData{ 1349 SpanData: NewSpanData(span, RedisSpanType), 1350 Tags: newRedisSpanTags(span), 1351 } 1352 } 1353 1354 // Kind returns the span kind for a Redis client span 1355 func (d RedisSpanData) Kind() SpanKind { 1356 return ExitSpanKind 1357 } 1358 1359 // Kind returns the span kind for a MongoDB client span 1360 func (d MongoDBSpanData) Kind() SpanKind { 1361 return ExitSpanKind 1362 } 1363 1364 // MongoDBSpanTags contains fields within the `data.mongo` section of an OT span document 1365 type MongoDBSpanTags struct { 1366 // Service is the MongoDB server address in form of host:port 1367 Service string `json:"service"` 1368 // Namespace is the namespace name 1369 Namespace string `json:"namespace"` 1370 // Command is the name of the command initiated the span 1371 Command string `json:"command"` 1372 // Query is an optional query passed with command 1373 Query string `json:"query,omitempty"` 1374 // JSON is an optional JSON aggregation provided with command 1375 JSON string `json:"json,omitempty"` 1376 // Filter is an optional filter passed with command 1377 Filter string `json:"filter,omitempty"` 1378 // Error is an optional error message 1379 Error string `json:"error,omitempty"` 1380 } 1381 1382 func newMongoDBSpanTags(span *spanS) MongoDBSpanTags { 1383 var tags MongoDBSpanTags 1384 for k, v := range span.Tags { 1385 switch k { 1386 case "mongo.service": 1387 readStringTag(&tags.Service, v) 1388 case "mongo.namespace": 1389 readStringTag(&tags.Namespace, v) 1390 case "mongo.command": 1391 readStringTag(&tags.Command, v) 1392 case "mongo.query": 1393 readStringTag(&tags.Query, v) 1394 case "mongo.json": 1395 readStringTag(&tags.JSON, v) 1396 case "mongo.filter": 1397 readStringTag(&tags.Filter, v) 1398 case "mongo.error": 1399 readStringTag(&tags.Error, v) 1400 } 1401 } 1402 1403 return tags 1404 } 1405 1406 // PostgreSQLSpanData represents the `data` section of a PostgreSQL client span 1407 type PostgreSQLSpanData struct { 1408 SpanData 1409 Tags postgreSQLSpanTags `json:"pg"` 1410 } 1411 1412 // newPostgreSQLSpanData initializes a new PostgreSQL client span data from tracer span 1413 func newPostgreSQLSpanData(span *spanS) PostgreSQLSpanData { 1414 return PostgreSQLSpanData{ 1415 SpanData: NewSpanData(span, PostgreSQLSpanType), 1416 Tags: newPostgreSQLSpanTags(span), 1417 } 1418 } 1419 1420 // Kind returns the span kind for a PostgreSQL client span 1421 func (d PostgreSQLSpanData) Kind() SpanKind { 1422 return ExitSpanKind 1423 } 1424 1425 // postgreSQLSpanTags contains fields within the `data.pg` section of an OT span document 1426 type postgreSQLSpanTags struct { 1427 Host string `json:"host"` 1428 Port string `json:"port"` 1429 DB string `json:"db"` 1430 User string `json:"user"` 1431 Stmt string `json:"stmt"` 1432 1433 Error string `json:"error,omitempty"` 1434 } 1435 1436 func newPostgreSQLSpanTags(span *spanS) postgreSQLSpanTags { 1437 var tags postgreSQLSpanTags 1438 for k, v := range span.Tags { 1439 switch k { 1440 case "pg.host": 1441 readStringTag(&tags.Host, v) 1442 case "pg.port": 1443 readStringTag(&tags.Port, v) 1444 case "pg.db": 1445 readStringTag(&tags.DB, v) 1446 case "pg.stmt": 1447 readStringTag(&tags.Stmt, v) 1448 case "pg.user": 1449 readStringTag(&tags.User, v) 1450 case "pg.error": 1451 } 1452 } 1453 return tags 1454 } 1455 1456 // RedisSpanTags contains fields within the `data.redis` section of an OT span document 1457 type RedisSpanTags struct { 1458 // Connection is the host and port where the Redis server is running 1459 Connection string `json:"connection"` 1460 // Command is the Redis command being executed 1461 Command string `json:"command"` 1462 // Subcommands is the list of commands queued when a transaction starts, eg: by using the MULTI command 1463 Subcommands []string `json:"subCommands,omitempty"` 1464 // Error is the optional error that can be thrown by Redis when executing a command 1465 Error string `json:"error,omitempty"` 1466 } 1467 1468 func newRedisSpanTags(span *spanS) RedisSpanTags { 1469 var tags RedisSpanTags 1470 for k, v := range span.Tags { 1471 switch k { 1472 case "redis.connection": 1473 readStringTag(&tags.Connection, v) 1474 case "redis.command": 1475 readStringTag(&tags.Command, v) 1476 case "redis.subCommands": 1477 readArrayStringTag(&tags.Subcommands, v) 1478 case "redis.error": 1479 readStringTag(&tags.Error, v) 1480 } 1481 } 1482 1483 return tags 1484 }