Skip to content

Commit

Permalink
Merge branch 'main' into postprocessor-add-scopes
Browse files Browse the repository at this point in the history
  • Loading branch information
noahdietz authored May 16, 2024
2 parents ee6a90e + c1cffb6 commit bc1d753
Show file tree
Hide file tree
Showing 11 changed files with 274 additions and 96 deletions.
39 changes: 36 additions & 3 deletions bigquery/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,21 @@ it as well, and call its Run method.
To upload, first define a type that implements the ValueSaver interface, which has a single method named Save.
Then create an Inserter, and call its Put method with a slice of values.
type Item struct {
Name string
Size float64
Count int
}
// Save implements the ValueSaver interface.
func (i *Item) Save() (map[string]bigquery.Value, string, error) {
return map[string]bigquery.Value{
"Name": i.Name,
"Size": i.Size,
"Count": i.Count,
}, "", nil
}
u := table.Inserter()
// Item implements the ValueSaver interface.
items := []*Item{
Expand All @@ -272,15 +287,33 @@ Then create an Inserter, and call its Put method with a slice of values.
}
You can also upload a struct that doesn't implement ValueSaver. Use the StructSaver type
to specify the schema and insert ID by hand, or just supply the struct or struct pointer
directly and the schema will be inferred:
to specify the schema and insert ID by hand:
type item struct {
Name string
Num int
}
// Assume schema holds the table's schema.
savers := []*bigquery.StructSaver{
{Struct: score{Name: "n1", Num: 12}, Schema: schema, InsertID: "id1"},
{Struct: score{Name: "n2", Num: 31}, Schema: schema, InsertID: "id2"},
{Struct: score{Name: "n3", Num: 7}, Schema: schema, InsertID: "id3"},
}
if err := u.Put(ctx, savers); err != nil {
// TODO: Handle error.
}
Lastly, but not least, you can just supply the struct or struct pointer directly and the schema will be inferred:
type Item2 struct {
Name string
Size float64
Count int
}
// Item implements the ValueSaver interface.
// Item2 doesn't implement ValueSaver interface, so schema will be inferred.
items2 := []*Item2{
{Name: "n1", Size: 32.6, Count: 7},
{Name: "n2", Size: 4, Count: 2},
Expand Down
4 changes: 2 additions & 2 deletions logging/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ require (
github.com/google/go-cmp v0.6.0
github.com/googleapis/gax-go/v2 v2.12.4
go.opencensus.io v0.24.0
go.opentelemetry.io/otel/sdk v1.24.0
go.opentelemetry.io/otel/trace v1.24.0
golang.org/x/oauth2 v0.20.0
google.golang.org/api v0.180.0
google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda
Expand All @@ -35,8 +37,6 @@ require (
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/sdk v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sync v0.7.0 // indirect
Expand Down
9 changes: 9 additions & 0 deletions logging/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ import (
"time"
"unicode/utf8"

"go.opentelemetry.io/otel/trace"

vkit "cloud.google.com/go/logging/apiv2"
logpb "cloud.google.com/go/logging/apiv2/loggingpb"
"cloud.google.com/go/logging/internal"
Expand Down Expand Up @@ -813,6 +815,13 @@ func populateTraceInfo(e *Entry, req *http.Request) bool {
return false
}
}
otelSpanContext := trace.SpanContextFromContext(req.Context())
if otelSpanContext.IsValid() {
e.Trace = otelSpanContext.TraceID().String()
e.SpanID = otelSpanContext.SpanID().String()
e.TraceSampled = otelSpanContext.IsSampled()
return true
}
header := req.Header.Get("Traceparent")
if header != "" {
// do not use traceSampled flag defined by traceparent because
Expand Down
129 changes: 129 additions & 0 deletions logging/logging_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
gax "github.com/googleapis/gax-go/v2"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/trace"
"go.opentelemetry.io/otel/trace/noop"
"golang.org/x/oauth2"
"google.golang.org/api/iterator"
"google.golang.org/api/option"
Expand Down Expand Up @@ -609,6 +612,132 @@ func TestToLogEntry(t *testing.T) {
}
}

func TestToLogEntryOTelIntegration(t *testing.T) {
// Some slight modifications need to be done for testing ToLogEntry
// for the OpenTelemetry integration, so they are in a separate function.
u := &url.URL{Scheme: "http"}
tests := []struct {
name string
in logging.Entry
want *logpb.LogEntry // if want is nil, pull wants from spanContext
}{
{
name: "Using OpenTelemetry with a valid span",
in: logging.Entry{
HTTPRequest: &logging.HTTPRequest{
Request: &http.Request{
URL: u,
},
},
},
},
{
name: "Using OpenTelemetry only with a valid span + valid traceparent headers (precedence test)",
in: logging.Entry{
HTTPRequest: &logging.HTTPRequest{
Request: &http.Request{
URL: u,
Header: http.Header{
"Traceparent": {"00-105445aa7843bc8bf206b12000100012-000000000000004a-01"},
},
},
},
},
},
{
name: "Using OpenTelemetry only with a valid span + valid XCTC headers (precedence test)",
in: logging.Entry{
HTTPRequest: &logging.HTTPRequest{
Request: &http.Request{
URL: u,
Header: http.Header{
"X-Cloud-Trace-Context": {"105445aa7843bc8bf206b120000000/0000000000000bbb;o=1"},
},
},
},
},
},
{
name: "Using OpenTelemetry with a valid span + trace info set in Entry object",
in: logging.Entry{
HTTPRequest: &logging.HTTPRequest{
Request: &http.Request{
URL: u,
},
},
Trace: "abc",
SpanID: "def",
TraceSampled: false,
},
want: &logpb.LogEntry{
Trace: "abc",
SpanId: "def",
TraceSampled: false,
},
},
{
name: "Using OpenTelemetry without a request",
in: logging.Entry{},
want: &logpb.LogEntry{},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
var span trace.Span
ctx := context.Background()

// Set up an OTel SDK tracer if integration test, mock noop tracer if not.
if integrationTest {
tracerProvider := sdktrace.NewTracerProvider()
defer tracerProvider.Shutdown(ctx)

ctx, span = tracerProvider.Tracer("integration-test-tracer").Start(ctx, "test span")
defer span.End()
} else {
otelTraceID, _ := trace.TraceIDFromHex(strings.Repeat("a", 32))
otelSpanID, _ := trace.SpanIDFromHex(strings.Repeat("f", 16))
otelTraceFlags := trace.FlagsSampled // tracesampled = true
mockSpanContext := trace.NewSpanContext(trace.SpanContextConfig{
TraceID: otelTraceID,
SpanID: otelSpanID,
TraceFlags: otelTraceFlags,
})
ctx = trace.ContextWithSpanContext(ctx, mockSpanContext)
ctx, span = noop.NewTracerProvider().Tracer("test tracer").Start(ctx, "test span")
defer span.End()
}

if test.in.HTTPRequest != nil && test.in.HTTPRequest.Request != nil {
test.in.HTTPRequest.Request = test.in.HTTPRequest.Request.WithContext(ctx)
}
spanContext := trace.SpanContextFromContext(ctx)

// if want is nil, pull wants from spanContext
if test.want == nil {
test.want = &logpb.LogEntry{
Trace: "projects/P/traces/" + spanContext.TraceID().String(),
SpanId: spanContext.SpanID().String(),
TraceSampled: spanContext.TraceFlags().IsSampled(),
}
}

e, err := logging.ToLogEntry(test.in, "projects/P")
if err != nil {
t.Fatalf("Unexpected error: %+v: %v", test.in, err)
}
if got := e.Trace; got != test.want.Trace {
t.Errorf("TraceId: %+v: SpanContext: %+v: got %q, want %q", test.in, spanContext, got, test.want.Trace)
}
if got := e.SpanId; got != test.want.SpanId {
t.Errorf("SpanId: %+v: SpanContext: %+v: got %q, want %q", test.in, spanContext, got, test.want.SpanId)
}
if got := e.TraceSampled; got != test.want.TraceSampled {
t.Errorf("TraceSampled: %+v: SpanContext: %+v: got %t, want %t", test.in, spanContext, got, test.want.TraceSampled)
}
})
}
}

// compareEntries compares most fields list of Entries against expected. compareEntries does not compare:
// - HTTPRequest
// - Operation
Expand Down
32 changes: 16 additions & 16 deletions spanner/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2271,19 +2271,19 @@ func TestIntegration_BasicTypes_ProtoColumns(t *testing.T) {
defer cancel()
stmts := []string{
`CREATE PROTO BUNDLE (
spanner.examples.music.SingerInfo,
spanner.examples.music.Genre,
examples.spanner.music.SingerInfo,
examples.spanner.music.Genre,
)`,
`CREATE TABLE Types (
RowID INT64 NOT NULL,
Int64a INT64,
Bytes BYTES(MAX),
Int64Array ARRAY<INT64>,
BytesArray ARRAY<BYTES(MAX)>,
ProtoMessage spanner.examples.music.SingerInfo,
ProtoEnum spanner.examples.music.Genre,
ProtoMessageArray ARRAY<spanner.examples.music.SingerInfo>,
ProtoEnumArray ARRAY<spanner.examples.music.Genre>,
ProtoMessage examples.spanner.music.SingerInfo,
ProtoEnum examples.spanner.music.Genre,
ProtoMessageArray ARRAY<examples.spanner.music.SingerInfo>,
ProtoEnumArray ARRAY<examples.spanner.music.Genre>,
) PRIMARY KEY (RowID)`,
}

Expand Down Expand Up @@ -2512,19 +2512,19 @@ func TestIntegration_BasicTypes_ProtoColumns_Errors(t *testing.T) {
defer cancel()
stmts := []string{
`CREATE PROTO BUNDLE (
spanner.examples.music.SingerInfo,
spanner.examples.music.Genre,
examples.spanner.music.SingerInfo,
examples.spanner.music.Genre,
)`,
`CREATE TABLE Types (
RowID INT64 NOT NULL,
Int64a INT64,
Bytes BYTES(MAX),
Int64Array ARRAY<INT64>,
BytesArray ARRAY<BYTES(MAX)>,
ProtoMessage spanner.examples.music.SingerInfo,
ProtoEnum spanner.examples.music.Genre,
ProtoMessageArray ARRAY<spanner.examples.music.SingerInfo>,
ProtoEnumArray ARRAY<spanner.examples.music.Genre>,
ProtoMessage examples.spanner.music.SingerInfo,
ProtoEnum examples.spanner.music.Genre,
ProtoMessageArray ARRAY<examples.spanner.music.SingerInfo>,
ProtoEnumArray ARRAY<examples.spanner.music.Genre>,
) PRIMARY KEY (RowID)`,
}
protoDescriptor := readProtoDescriptorFile()
Expand Down Expand Up @@ -2607,15 +2607,15 @@ func TestIntegration_ProtoColumns_DML_ParameterizedQueries_Pk_Indexes(t *testing
defer cancel()
stmts := []string{
`CREATE PROTO BUNDLE (
spanner.examples.music.SingerInfo,
spanner.examples.music.Genre,
examples.spanner.music.SingerInfo,
examples.spanner.music.Genre,
)`,
`CREATE TABLE Singers (
SingerId INT64 NOT NULL,
FirstName STRING(1024),
LastName STRING(1024),
SingerInfo spanner.examples.music.SingerInfo,
SingerGenre spanner.examples.music.Genre,
SingerInfo examples.spanner.music.SingerInfo,
SingerGenre examples.spanner.music.Genre,
SingerNationality STRING(1024) AS (SingerInfo.nationality) STORED,
) PRIMARY KEY (SingerNationality, SingerGenre)`,
`CREATE INDEX SingerByNationalityAndGenre ON Singers(SingerNationality, SingerGenre) STORING (SingerId, FirstName, LastName)`,
Expand Down
5 changes: 5 additions & 0 deletions spanner/testdata/protos/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#### To generate singer.pb.go and descriptors.pb file from singer.proto using `protoc`
```shell
cd spanner/testdata
protoc --proto_path=protos/ --include_imports --descriptor_set_out=protos/descriptors.pb --go_out=protos/ protos/singer.proto
```
Binary file modified spanner/testdata/protos/descriptors.pb
Binary file not shown.
Loading

0 comments on commit bc1d753

Please sign in to comment.