Repository: GoogleCloudPlatform/opentelemetry-operations-go
Pull request #440 (2022-06-22 18:49:25)

Parse logs traceID to correct format
Fixes https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/11436


Patch:
diff --git a/exporter/collector/logs.go b/exporter/collector/logs.go
index 7ff4084..035759e 100644
--- a/exporter/collector/logs.go
+++ b/exporter/collector/logs.go
@@ -27,7 +27,6 @@ import (
 	"cloud.google.com/go/logging"
 	loggingv2 "cloud.google.com/go/logging/apiv2"
 	"google.golang.org/genproto/googleapis/api/monitoredres"
-	monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres"
 	logpb "google.golang.org/genproto/googleapis/logging/v2"
 	"google.golang.org/protobuf/proto"
 
@@ -239,7 +238,7 @@ func (l logMapper) logEntryToInternal(
 	entry logging.Entry,
 	logName string,
 	projectID string,
-	mr *monitoredrespb.MonitoredResource,
+	mr *monitoredres.MonitoredResource,
 	splits int,
 	splitIndex int,
 ) (*logpb.LogEntry, error) {
@@ -324,7 +323,7 @@ func (l logMapper) logToSplitEntries(
 
 	// parse TraceID and SpanID, if present
 	if !log.TraceID().IsEmpty() {
-		entry.Trace = log.TraceID().HexString()
+		entry.Trace = fmt.Sprintf("projects/%s/traces/%s", projectID, log.TraceID().HexString())
 	}
 	if !log.SpanID().IsEmpty() {
 		entry.SpanID = log.SpanID().HexString()
diff --git a/exporter/collector/metrics.go b/exporter/collector/metrics.go
index 1cb00eb..7e24466 100644
--- a/exporter/collector/metrics.go
+++ b/exporter/collector/metrics.go
@@ -1159,6 +1159,3 @@ func mapMetricPointKind(m pmetric.Metric) (metricpb.MetricDescriptor_MetricKind,
 	}
 	return kind, typ
 }
-
-func (me *MetricsExporter) processItem(ts *monitoringpb.TimeSeries) {
-}
diff --git a/exporter/collector/observability.go b/exporter/collector/observability.go
index e8af359..74b9ed0 100644
--- a/exporter/collector/observability.go
+++ b/exporter/collector/observability.go
@@ -44,21 +44,6 @@ func MetricViews() []*view.View {
 	return []*view.View{viewPointCount}
 }
 
-func recordPointCount(ctx context.Context, success, dropped int, grpcErr error) {
-	if success > 0 {
-		recordPointCountDataPoint(ctx, success, "OK")
-	}
-
-	if dropped > 0 {
-		st := "UNKNOWN"
-		s, ok := status.FromError(grpcErr)
-		if ok {
-			st = statusCodeToString(s)
-		}
-		recordPointCountDataPoint(ctx, dropped, st)
-	}
-}
-
 func recordExemplarFailure(ctx context.Context, point int) {
 	stats.Record(ctx, exemplarAttachmentDropCount.M(int64(point)))
 }
diff --git a/exporter/metric/metric.go b/exporter/metric/metric.go
index eb49905..7476f21 100644
--- a/exporter/metric/metric.go
+++ b/exporter/metric/metric.go
@@ -35,7 +35,6 @@ import (
 
 	monitoring "cloud.google.com/go/monitoring/apiv3/v2"
 	"google.golang.org/api/option"
-	apioption "google.golang.org/api/option"
 	"google.golang.org/genproto/googleapis/api/distribution"
 	googlemetricpb "google.golang.org/genproto/googleapis/api/metric"
 	monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres"
@@ -129,7 +128,7 @@ func newMetricExporter(o *options) (*metricExporter, error) {
 		return nil, errBlankProjectID
 	}
 
-	clientOpts := append([]apioption.ClientOption{option.WithUserAgent(userAgent)}, o.monitoringClientOptions...)
+	clientOpts := append([]option.ClientOption{option.WithUserAgent(userAgent)}, o.monitoringClientOptions...)
 	ctx := o.context
 	if ctx == nil {
 		ctx = context.Background()
diff --git a/golangci.yml b/golangci.yml
index afb36c2..6ece05e 100644
--- a/golangci.yml
+++ b/golangci.yml
@@ -106,6 +106,9 @@ linters-settings:
     - metres
     - kilometre
     - kilometres
+  revive:
+    rules:
+      - name: duplicated-imports
 
 linters:
   disable-all: true
@@ -117,10 +120,17 @@ linters:
     - staticcheck
     - misspell
     - exportloopref
+    - unused
 
 issues:
   # Excluding configuration per-path, per-linter, per-text and per-source
   exclude-rules:
+    # integrationtests defines constants that are used by _test.go files which
+    # aren't detected as being used (for some reason)
+    - path: testcase.go
+      linters:
+        - unused
+      text: "secondProjectEnv"
     # Exclude some linters from running on tests files.
     - path: _test\.go
       linters:


Test patch:
diff --git a/exporter/collector/integrationtest/testcases.go b/exporter/collector/integrationtest/testcases.go
index b8fb101..b991090 100644
--- a/exporter/collector/integrationtest/testcases.go
+++ b/exporter/collector/integrationtest/testcases.go
@@ -41,6 +41,11 @@ var (
 			OTLPInputFixturePath: "testdata/fixtures/logs_apache_error_scope.json",
 			ExpectFixturePath:    "testdata/fixtures/logs_apache_error_scope_expected.json",
 		},
+		{
+			Name:                 "Logs with trace/span info",
+			OTLPInputFixturePath: "testdata/fixtures/logs_span_trace_id.json",
+			ExpectFixturePath:    "testdata/fixtures/logs_span_trace_id_expected.json",
+		},
 	}
 
 	MetricsTestCases = []TestCase{
diff --git a/exporter/collector/integrationtest/testdata/fixtures/logs_span_trace_id.json b/exporter/collector/integrationtest/testdata/fixtures/logs_span_trace_id.json
new file mode 100644
index 0000000..74ff0a1
--- /dev/null
+++ b/exporter/collector/integrationtest/testdata/fixtures/logs_span_trace_id.json
@@ -0,0 +1,274 @@
+{
+  "resourceLogs": [
+    {
+      "resource": {},
+      "scopeLogs": [
+        {
+          "scope": {},
+          "logRecords": [
+            {
+              "timeUnixNano": "1655923556339005014",
+              "body": {
+                "kvlistValue": {
+                  "values": [
+                    {
+                      "key": "body",
+                      "value": {
+                        "kvlistValue": {
+                          "values": [
+                            {
+                              "key": "time",
+                              "value": {
+                                "stringValue": "2022-06-22T16:13:19Z"
+                              }
+                            },
+                            {
+                              "key": "level",
+                              "value": {
+                                "stringValue": "info"
+                              }
+                            },
+                            {
+                              "key": "msg",
+                              "value": {
+                                "stringValue": "hello world 0"
+                              }
+                            }
+                          ]
+                        }
+                      }
+                    }
+                  ]
+                }
+              },
+              "attributes": [
+                {
+                  "key": "file.name",
+                  "value": {
+                    "stringValue": "apache.log"
+                  }
+                },
+                {
+                  "key": "gcp.log_name",
+                  "value": {
+                    "stringValue": "my-log-name-foo"
+                  }
+                }
+              ],
+              "traceId": "ad57e7b40d6f172d04f8a0e1b80cafe4",
+              "spanId": "d39ba683befbd246"
+            },
+            {
+              "timeUnixNano": "1655923556339179012",
+              "body": {
+                "kvlistValue": {
+                  "values": [
+                    {
+                      "key": "body",
+                      "value": {
+                        "kvlistValue": {
+                          "values": [
+                            {
+                              "key": "time",
+                              "value": {
+                                "stringValue": "2022-06-22T16:13:19Z"
+                              }
+                            },
+                            {
+                              "key": "level",
+                              "value": {
+                                "stringValue": "info"
+                              }
+                            },
+                            {
+                              "key": "msg",
+                              "value": {
+                                "stringValue": "hello world 1"
+                              }
+                            }
+                          ]
+                        }
+                      }
+                    }
+                  ]
+                }
+              },
+              "attributes": [
+                {
+                  "key": "file.name",
+                  "value": {
+                    "stringValue": "apache.log"
+                  }
+                },
+                {
+                  "key": "gcp.log_name",
+                  "value": {
+                    "stringValue": "my-log-name-foo"
+                  }
+                }
+              ],
+              "traceId": "ad57e7b40d6f172d04f8a0e1b80cafe4",
+              "spanId": "97c0f2f642dd1306"
+            },
+            {
+              "timeUnixNano": "1655923556339195932",
+              "body": {
+                "kvlistValue": {
+                  "values": [
+                    {
+                      "key": "body",
+                      "value": {
+                        "kvlistValue": {
+                          "values": [
+                            {
+                              "key": "level",
+                              "value": {
+                                "stringValue": "info"
+                              }
+                            },
+                            {
+                              "key": "msg",
+                              "value": {
+                                "stringValue": "hello world 2"
+                              }
+                            },
+                            {
+                              "key": "time",
+                              "value": {
+                                "stringValue": "2022-06-22T16:13:19Z"
+                              }
+                            }
+                          ]
+                        }
+                      }
+                    }
+                  ]
+                }
+              },
+              "attributes": [
+                {
+                  "key": "file.name",
+                  "value": {
+                    "stringValue": "apache.log"
+                  }
+                },
+                {
+                  "key": "gcp.log_name",
+                  "value": {
+                    "stringValue": "my-log-name-foo"
+                  }
+                }
+              ],
+              "traceId": "ad57e7b40d6f172d04f8a0e1b80cafe4",
+              "spanId": "fded437fb39abed9"
+            },
+            {
+              "timeUnixNano": "1655923556339234508",
+              "body": {
+                "kvlistValue": {
+                  "values": [
+                    {
+                      "key": "body",
+                      "value": {
+                        "kvlistValue": {
+                          "values": [
+                            {
+                              "key": "time",
+                              "value": {
+                                "stringValue": "2022-06-22T16:13:19Z"
+                              }
+                            },
+                            {
+                              "key": "level",
+                              "value": {
+                                "stringValue": "info"
+                              }
+                            },
+                            {
+                              "key": "msg",
+                              "value": {
+                                "stringValue": "hello world 3"
+                              }
+                            }
+                          ]
+                        }
+                      }
+                    }
+                  ]
+                }
+              },
+              "attributes": [
+                {
+                  "key": "file.name",
+                  "value": {
+                    "stringValue": "apache.log"
+                  }
+                },
+                {
+                  "key": "gcp.log_name",
+                  "value": {
+                    "stringValue": "my-log-name-foo"
+                  }
+                }
+              ],
+              "traceId": "ad57e7b40d6f172d04f8a0e1b80cafe4",
+              "spanId": "6acb5055846322e7"
+            },
+            {
+              "timeUnixNano": "1655923556339240397",
+              "body": {
+                "kvlistValue": {
+                  "values": [
+                    {
+                      "key": "body",
+                      "value": {
+                        "kvlistValue": {
+                          "values": [
+                            {
+                              "key": "time",
+                              "value": {
+                                "stringValue": "2022-06-22T16:13:19Z"
+                              }
+                            },
+                            {
+                              "key": "level",
+                              "value": {
+                                "stringValue": "info"
+                              }
+                            },
+                            {
+                              "key": "msg",
+                              "value": {
+                                "stringValue": "hello world 4"
+                              }
+                            }
+                          ]
+                        }
+                      }
+                    }
+                  ]
+                }
+              },
+              "attributes": [
+                {
+                  "key": "file.name",
+                  "value": {
+                    "stringValue": "apache.log"
+                  }
+                },
+                {
+                  "key": "gcp.log_name",
+                  "value": {
+                    "stringValue": "my-log-name-foo"
+                  }
+                }
+              ],
+              "traceId": "ad57e7b40d6f172d04f8a0e1b80cafe4",
+              "spanId": "d9ae3a7b26ef239f"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/exporter/collector/integrationtest/testdata/fixtures/logs_span_trace_id_expected.json b/exporter/collector/integrationtest/testdata/fixtures/logs_span_trace_id_expected.json
new file mode 100644
index 0000000..934096e
--- /dev/null
+++ b/exporter/collector/integrationtest/testdata/fixtures/logs_span_trace_id_expected.json
@@ -0,0 +1,129 @@
+{
+  "writeLogEntriesRequests": [
+    {
+      "entries": [
+        {
+          "logName": "projects/fakeprojectid/logs/my-log-name-foo",
+          "resource": {
+            "type": "generic_node",
+            "labels": {
+              "location": "global",
+              "namespace": "",
+              "node_id": ""
+            }
+          },
+          "jsonPayload": {
+            "body": {
+              "level": "info",
+              "msg": "hello world 0",
+              "time": "2022-06-22T16:13:19Z"
+            }
+          },
+          "timestamp": "1970-01-01T00:00:00Z",
+          "labels": {
+            "file.name": "apache.log"
+          },
+          "trace": "projects/fakeprojectid/traces/ad57e7b40d6f172d04f8a0e1b80cafe4",
+          "spanId": "d39ba683befbd246"
+        },
+        {
+          "logName": "projects/fakeprojectid/logs/my-log-name-foo",
+          "resource": {
+            "type": "generic_node",
+            "labels": {
+              "location": "global",
+              "namespace": "",
+              "node_id": ""
+            }
+          },
+          "jsonPayload": {
+            "body": {
+              "level": "info",
+              "msg": "hello world 1",
+              "time": "2022-06-22T16:13:19Z"
+            }
+          },
+          "timestamp": "1970-01-01T00:00:00Z",
+          "labels": {
+            "file.name": "apache.log"
+          },
+          "trace": "projects/fakeprojectid/traces/ad57e7b40d6f172d04f8a0e1b80cafe4",
+          "spanId": "97c0f2f642dd1306"
+        },
+        {
+          "logName": "projects/fakeprojectid/logs/my-log-name-foo",
+          "resource": {
+            "type": "generic_node",
+            "labels": {
+              "location": "global",
+              "namespace": "",
+              "node_id": ""
+            }
+          },
+          "jsonPayload": {
+            "body": {
+              "level": "info",
+              "msg": "hello world 2",
+              "time": "2022-06-22T16:13:19Z"
+            }
+          },
+          "timestamp": "1970-01-01T00:00:00Z",
+          "labels": {
+            "file.name": "apache.log"
+          },
+          "trace": "projects/fakeprojectid/traces/ad57e7b40d6f172d04f8a0e1b80cafe4",
+          "spanId": "fded437fb39abed9"
+        },
+        {
+          "logName": "projects/fakeprojectid/logs/my-log-name-foo",
+          "resource": {
+            "type": "generic_node",
+            "labels": {
+              "location": "global",
+              "namespace": "",
+              "node_id": ""
+            }
+          },
+          "jsonPayload": {
+            "body": {
+              "level": "info",
+              "msg": "hello world 3",
+              "time": "2022-06-22T16:13:19Z"
+            }
+          },
+          "timestamp": "1970-01-01T00:00:00Z",
+          "labels": {
+            "file.name": "apache.log"
+          },
+          "trace": "projects/fakeprojectid/traces/ad57e7b40d6f172d04f8a0e1b80cafe4",
+          "spanId": "6acb5055846322e7"
+        },
+        {
+          "logName": "projects/fakeprojectid/logs/my-log-name-foo",
+          "resource": {
+            "type": "generic_node",
+            "labels": {
+              "location": "global",
+              "namespace": "",
+              "node_id": ""
+            }
+          },
+          "jsonPayload": {
+            "body": {
+              "level": "info",
+              "msg": "hello world 4",
+              "time": "2022-06-22T16:13:19Z"
+            }
+          },
+          "timestamp": "1970-01-01T00:00:00Z",
+          "labels": {
+            "file.name": "apache.log"
+          },
+          "trace": "projects/fakeprojectid/traces/ad57e7b40d6f172d04f8a0e1b80cafe4",
+          "spanId": "d9ae3a7b26ef239f"
+        }
+      ],
+      "partialSuccess": true
+    }
+  ]
+}
diff --git a/exporter/collector/logs_test.go b/exporter/collector/logs_test.go
index 7cf27f8..b11b2a3 100644
--- a/exporter/collector/logs_test.go
+++ b/exporter/collector/logs_test.go
@@ -15,6 +15,7 @@
 package collector
 
 import (
+	"fmt"
 	"io"
 	"net/http"
 	"testing"
@@ -60,7 +61,7 @@ func TestLogMapping(t *testing.T) {
 	}{
 		{
 			name:         "split entry size",
-			maxEntrySize: 3 + 38, // 3 bytes for payload + 38 for overhead
+			maxEntrySize: 3 + 51, // 3 bytes for payload + 51 for overhead
 			log: func() plog.LogRecord {
 				log := plog.NewLogRecord()
 				log.Body().SetStringVal("abcxyz")
@@ -230,7 +231,7 @@ func TestLogMapping(t *testing.T) {
 			},
 			expectedEntries: []logging.Entry{
 				{
-					Trace:     testTraceID.HexString(),
+					Trace:     fmt.Sprintf("projects/fakeprojectid/traces/%s", testTraceID.HexString()),
 					SpanID:    testSpanID.HexString(),
 					Timestamp: testObservedTime,
 				},
@@ -283,7 +284,7 @@ func TestLogMapping(t *testing.T) {
 				"",
 				testObservedTime,
 				logName,
-				"",
+				"fakeprojectid",
 			)
 
 			if testCase.expectError {
diff --git a/exporter/metric/metric_test.go b/exporter/metric/metric_test.go
index 7b1c6b1..416274b 100644
--- a/exporter/metric/metric_test.go
+++ b/exporter/metric/metric_test.go
@@ -24,7 +24,6 @@ import (
 
 	"go.opentelemetry.io/otel/attribute"
 	"go.opentelemetry.io/otel/sdk/instrumentation"
-	"go.opentelemetry.io/otel/sdk/metric/controller/basic"
 	controller "go.opentelemetry.io/otel/sdk/metric/controller/basic"
 	"go.opentelemetry.io/otel/sdk/metric/export"
 	"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
@@ -94,7 +93,7 @@ func TestExportCounter(t *testing.T) {
 
 	clientOpt := option.WithGRPCConn(cloudMock.ClientConn())
 
-	resOpt := basic.WithResource(
+	resOpt := controller.WithResource(
 		resource.NewWithAttributes(
 			semconv.SchemaURL,
 			attribute.String("test_id", "abc123"),
@@ -130,7 +129,7 @@ func TestExportHistogram(t *testing.T) {
 
 	clientOpt := option.WithGRPCConn(cloudMock.ClientConn())
 
-	resOpt := basic.WithResource(
+	resOpt := controller.WithResource(
 		resource.NewWithAttributes(
 			semconv.SchemaURL,
 			attribute.String("test_id", "abc123"),
@@ -199,7 +198,7 @@ func TestRecordToMpb(t *testing.T) {
 
 	clientOpt := option.WithGRPCConn(cloudMock.ClientConn())
 
-	resOpt := basic.WithResource(
+	resOpt := controller.WithResource(
 		resource.NewWithAttributes(
 			semconv.SchemaURL,
 			attribute.String("test_id", "abc123"),