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  }