fix(logging): allow X-Cloud-Trace-Context fields to be optional (#3062)
* docs(logging): update doc link explaining x-cloud-trace-context
* fix(logging): X-Cloud-Trace-Context fields can be optional (traceSample defaults to false)
* style: go fmt logging.go
* style(logging): updated inline comments to be clearer
* refactor(logging): reCloudTraceContext regex is more readable
diff --git a/logging/logging.go b/logging/logging.go
index 7543bb0..66fe7b2 100644
--- a/logging/logging.go
+++ b/logging/logging.go
@@ -873,33 +873,31 @@
// (for example by calling SetFlags or SetPrefix).
func (l *Logger) StandardLogger(s Severity) *log.Logger { return l.stdLoggers[s] }
-var reCloudTraceContext = regexp.MustCompile(`([a-f\d]+)/([a-f\d]+);o=(\d)`)
+var reCloudTraceContext = regexp.MustCompile(
+ // Matches on "TRACE_ID"
+ `([a-f\d]+)?` +
+ // Matches on "/SPAN_ID"
+ `(?:/([a-f\d]+))?` +
+ // Matches on ";0=TRACE_TRUE"
+ `(?:;o=(\d))?`)
func deconstructXCloudTraceContext(s string) (traceID, spanID string, traceSampled bool) {
- // As per the format described at https://cloud.google.com/trace/docs/troubleshooting#force-trace
+ // As per the format described at https://cloud.google.com/trace/docs/setup#force-trace
// "X-Cloud-Trace-Context: TRACE_ID/SPAN_ID;o=TRACE_TRUE"
// for example:
- // "X-Cloud-Trace-Context: 105445aa7843bc8bf206b120001000/0;o=1"
+ // "X-Cloud-Trace-Context: 105445aa7843bc8bf206b120001000/1;o=1"
//
// We expect:
- // * traceID: "105445aa7843bc8bf206b120001000"
- // * spanID: ""
- // * traceSampled: true
- matches := reCloudTraceContext.FindAllStringSubmatch(s, -1)
- if len(matches) != 1 {
- return
- }
+ // * traceID (optional): "105445aa7843bc8bf206b120001000"
+ // * spanID (optional): "1"
+ // * traceSampled (optional): true
+ matches := reCloudTraceContext.FindStringSubmatch(s)
- sub := matches[0]
- if len(sub) != 4 {
- return
- }
+ traceID, spanID, traceSampled = matches[1], matches[2], matches[3] == "1"
- traceID, spanID = sub[1], sub[2]
if spanID == "0" {
spanID = ""
}
- traceSampled = sub[3] == "1"
return
}
diff --git a/logging/logging_unexported_test.go b/logging/logging_unexported_test.go
index b764688..2a42625 100644
--- a/logging/logging_unexported_test.go
+++ b/logging/logging_unexported_test.go
@@ -289,18 +289,54 @@
logging.LogEntry{Trace: "projects/P/traces/105445aa7843bc8bf206b120001000", SpanId: "000000000000004a", TraceSampled: true},
},
{
+ "X-Trace-Context header with blank trace",
+ Entry{
+ HTTPRequest: &HTTPRequest{
+ Request: &http.Request{
+ URL: u,
+ Header: http.Header{"X-Cloud-Trace-Context": {"/0;o=1"}},
+ },
+ },
+ },
+ logging.LogEntry{TraceSampled: true},
+ },
+ {
"X-Trace-Context header with blank span",
Entry{
HTTPRequest: &HTTPRequest{
Request: &http.Request{
URL: u,
- Header: http.Header{"X-Cloud-Trace-Context": {"105445aa7843bc8bf206b120001000/0;o=0"}},
+ Header: http.Header{"X-Cloud-Trace-Context": {"105445aa7843bc8bf206b120001000/;o=0"}},
},
},
},
logging.LogEntry{Trace: "projects/P/traces/105445aa7843bc8bf206b120001000"},
},
{
+ "X-Trace-Context header with missing traceSampled aka ?o=*",
+ Entry{
+ HTTPRequest: &HTTPRequest{
+ Request: &http.Request{
+ URL: u,
+ Header: http.Header{"X-Cloud-Trace-Context": {"105445aa7843bc8bf206b120001000/0"}},
+ },
+ },
+ },
+ logging.LogEntry{Trace: "projects/P/traces/105445aa7843bc8bf206b120001000"},
+ },
+ {
+ "X-Trace-Context header with all blank fields",
+ Entry{
+ HTTPRequest: &HTTPRequest{
+ Request: &http.Request{
+ URL: u,
+ Header: http.Header{"X-Cloud-Trace-Context": {""}},
+ },
+ },
+ },
+ logging.LogEntry{},
+ },
+ {
"Invalid X-Trace-Context header but already set TraceID",
Entry{
HTTPRequest: &HTTPRequest{