diff --git a/gcp/observability/logging.go b/gcp/observability/logging.go index dee2656f7b8..dcd7bf848fd 100644 --- a/gcp/observability/logging.go +++ b/gcp/observability/logging.go @@ -338,6 +338,11 @@ type binaryLogger struct { } func (bl *binaryLogger) GetMethodLogger(methodName string) iblog.MethodLogger { + // Prevent logging from logging, traces, and metrics API calls. + if strings.HasPrefix(methodName, "/google.logging.v2.LoggingServiceV2/") || strings.HasPrefix(methodName, "/google.monitoring.v3.MetricService/") || + strings.HasPrefix(methodName, "/google.devtools.cloudtrace.v2.TraceService/") { + return nil + } s, _, err := grpcutil.ParseMethod(methodName) if err != nil { logger.Infof("binarylogging: failed to parse %q: %v", methodName, err) diff --git a/gcp/observability/logging_test.go b/gcp/observability/logging_test.go index 03638a9b49d..91c10967881 100644 --- a/gcp/observability/logging_test.go +++ b/gcp/observability/logging_test.go @@ -166,6 +166,7 @@ func (s) TestClientRPCEventsLogAll(t *testing.T) { if _, err := ss.Client.UnaryCall(ctx, &grpc_testing.SimpleRequest{}); err != nil { t.Fatalf("Unexpected error from UnaryCall: %v", err) } + grpcLogEntriesWant := []*grpcLogEntry{ { Type: eventTypeClientHeader, @@ -1056,6 +1057,65 @@ func (s) TestTranslateMetadata(t *testing.T) { } } +// TestCloudLoggingAPICallsFiltered tests that the observability plugin does not +// emit logs for cloud logging API calls. +func (s) TestCloudLoggingAPICallsFiltered(t *testing.T) { + fle := &fakeLoggingExporter{ + t: t, + } + + defer func(ne func(ctx context.Context, config *config) (loggingExporter, error)) { + newLoggingExporter = ne + }(newLoggingExporter) + + newLoggingExporter = func(ctx context.Context, config *config) (loggingExporter, error) { + return fle, nil + } + configLogAll := &config{ + ProjectID: "fake", + CloudLogging: &cloudLogging{ + ClientRPCEvents: []clientRPCEvents{ + { + Methods: []string{"*"}, + MaxMetadataBytes: 30, + MaxMessageBytes: 30, + }, + }, + }, + } + cleanup, err := setupObservabilitySystemWithConfig(configLogAll) + if err != nil { + t.Fatalf("error setting up observability %v", err) + } + defer cleanup() + + ss := &stubserver.StubServer{} + if err := ss.Start(nil); err != nil { + t.Fatalf("Error starting endpoint server: %v", err) + } + defer ss.Stop() + + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + + // Any of the three cloud logging API calls should not cause any logs to be + // emitted, even though the configuration specifies to log any rpc + // regardless of method. + req := &grpc_testing.SimpleRequest{} + resp := &grpc_testing.SimpleResponse{} + + ss.CC.Invoke(ctx, "/google.logging.v2.LoggingServiceV2/some-method", req, resp) + ss.CC.Invoke(ctx, "/google.monitoring.v3.MetricService/some-method", req, resp) + ss.CC.Invoke(ctx, "/google.devtools.cloudtrace.v2.TraceService/some-method", req, resp) + // The exporter should have received no new log entries due to these three + // calls, as they should be filtered out. + fle.mu.Lock() + defer fle.mu.Unlock() + if len(fle.entries) != 0 { + t.Fatalf("Unexpected length of entries %v, want 0", len(fle.entries)) + } +} + func (s) TestMarshalJSON(t *testing.T) { logEntry := &grpcLogEntry{ CallID: "300-300-300",