-
Notifications
You must be signed in to change notification settings - Fork 327
add initial version of W3C tracestate #887
Changes from all commits
581cd79
163de2f
4e23146
9329855
56ff1e2
727300c
e3bec5b
f87c2a7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
// Copyright 2018, OpenCensus Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package trace | ||
|
||
import ( | ||
"fmt" | ||
"regexp" | ||
) | ||
|
||
const ( | ||
keyWithoutVendorFormat = `[a-z][_0-9a-z\-\*\/]{0,255}` | ||
keyWithVendorFormat = `[a-z][_0-9a-z\-\*\/]{0,240}@[a-z][_0-9a-z\-\*\/]{0,13}` | ||
keyFormat = `(` + keyWithoutVendorFormat + `)|(` + keyWithVendorFormat + `)` | ||
valueFormat = `[\x20-\x2b\x2d-\x3c\x3e-\x7e]{0,255}[\x21-\x2b\x2d-\x3c\x3e-\x7e]` | ||
) | ||
|
||
var keyValidationRegExp = regexp.MustCompile(`^(` + keyFormat + `)$`) | ||
var valueValidationRegExp = regexp.MustCompile(`^(` + valueFormat + `)$`) | ||
|
||
type TracestateEntry struct { | ||
key string | ||
value string | ||
} | ||
|
||
func (ts *TracestateEntry) IsValid() bool { | ||
return keyValidationRegExp.MatchString(ts.key) && | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is an empty key valid? Is an empty value? It seems from the pattern that it is. Should it be? Ideally we would have a test for this. |
||
valueValidationRegExp.MatchString(ts.value) | ||
} | ||
|
||
// Tracestate is a tracing-system specific context in a list of key-value pairs. | ||
// Tracestate allows different vendors propagate additional information and | ||
// inter-operate with their legacy Id formats. | ||
type Tracestate struct { | ||
entries []TracestateEntry | ||
} | ||
|
||
func (ts *Tracestate) IsValid() bool { | ||
if len(ts.entries) == 0 || len(ts.entries) > 32 { | ||
return false | ||
} | ||
for _, entry := range ts.entries { | ||
if !entry.IsValid() { | ||
return false | ||
} | ||
} | ||
return true | ||
} | ||
|
||
func (ts *Tracestate) Fork() *Tracestate { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should remove this method as well. It only makes sense if Tracestate is mutable. |
||
retval := Tracestate{entries: ts.entries} | ||
return &retval | ||
} | ||
|
||
func (ts *Tracestate) Get(key string) string { | ||
for _, entry := range ts.entries { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To make the zero value of
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this method distinguish between an empty string value and the absence of a key? If so, perhaps it should return There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Empty string means the key doesn't exist, as the W3C spec wouldn't allow empty string as the value. |
||
if entry.key == key { | ||
return entry.value | ||
} | ||
} | ||
return "" | ||
} | ||
|
||
/* | ||
TODO: we're making Tracestate immutable for now, ramonza and reyang to figure | ||
out how to change it. | ||
https://github.com/census-instrumentation/opencensus-go/pull/887 | ||
|
||
func (ts *Tracestate) Remove(key string) string { | ||
return ts.Set(key, "") | ||
} | ||
|
||
func (ts *Tracestate) Set(key string, value string) string { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we should make any part of SpanContext mutable. Can we make Tracestate immutable for now? I think we can figure out how to make it possible to change the Tracestate in a subsequent PR - I think the focus of this initial work should just be on correct propagation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, we can take the step-by-step approach. To provide more context, census-instrumentation/opencensus-specs#70 (comment) and census-instrumentation/opencensus-specs#131. Also adding @wu-sheng for awareness. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Ramonza, I've commented out the Tracestate.Remove and Tracestate.Set for now. Regarding SpanContext, I'm putting a pointer to Tracestate rather than a hardy copy for Tracestate as we would want to have COW (copy-on-write) Tracestate in the future for performance, taking a hard copy is too expensive. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would you mind removing them entirely for now? We in general never keep around commented code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, I'll remove it. |
||
retval := "" | ||
newEntry := TracestateEntry{key: key, value: value} | ||
if !newEntry.IsValid() && value != "" { | ||
return retval | ||
} | ||
for index, entry := range ts.entries { | ||
if entry.key == key { | ||
ts.entries = append(ts.entries[:index], ts.entries[index+1:]...) | ||
retval = entry.value | ||
break | ||
} | ||
} | ||
if value != "" { | ||
ts.entries = append([]TracestateEntry{newEntry}, ts.entries...) | ||
} | ||
return retval | ||
} | ||
*/ | ||
|
||
func (ts *Tracestate) String() string { | ||
return fmt.Sprintf("tracestate%s", ts.entries) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this will be a useful output for String() - I would recommend just removing the method There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alternatively, I think it would be reasonable for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please refer to census-instrumentation/opencensus-python#238 (comment) where we agreed to separate the in-process representation and the actual HTTP header format. |
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The zero value of
*Tracestate
(nil
) should be a valid empty Tracestate in the spirit of making the zero value useful. So it should not be necessary to set it here.