-
Notifications
You must be signed in to change notification settings - Fork 898
CorrelationContext -> Baggage #1106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
cijothomas
merged 23 commits into
open-telemetry:master
from
CodeBlanch:baggage-context
Aug 27, 2020
Merged
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
ea8459b
Baggage context part 1.
CodeBlanch 804746a
A little cleanup.
CodeBlanch d26ec72
Merge branch 'master' into baggage-context
cijothomas cfef67a
Return strings instead of objects. Removed default value in ctor beca…
CodeBlanch e9e82ba
Merge branch 'baggage-context' of https://github.com/CodeBlanch/opent…
CodeBlanch 6b6598a
Updated SDK & API projects for BaggageContext.
CodeBlanch b9a3b31
Fixed broken areas, except for CorrelationContext tests.
CodeBlanch 06e0a2e
First round of tests and bug fixes.
CodeBlanch cea26fb
Merging latest from master.
CodeBlanch 666655f
FIxed up HTTP instrumentation tests.
CodeBlanch b584536
Fixed up shim tests.
CodeBlanch 9c532c0
More tests and improvements.
CodeBlanch be923f2
Merging from master.
CodeBlanch 4f1758a
Fixed broken test.
CodeBlanch 3e6d3bd
Test coverage and bug fixes.
CodeBlanch 6955142
Deterministic GetHashCode + tests.
CodeBlanch 144093f
Merging latest from master.
CodeBlanch 6ced696
Added a link to the baggage api.
CodeBlanch abe67ae
Updated CHANGELOG.
CodeBlanch f7a1528
Renamed BaggageContext -> Baggage.
CodeBlanch 32ccef4
CHANGELOG update.
CodeBlanch 3c89146
Merge branch 'master' into baggage-context
CodeBlanch d2bf842
Merge branch 'master' into baggage-context
cijothomas File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,305 @@ | ||
| // <copyright file="Baggage.cs" company="OpenTelemetry Authors"> | ||
| // Copyright The OpenTelemetry 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. | ||
| // </copyright> | ||
|
|
||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
| using OpenTelemetry.Context; | ||
|
|
||
| namespace OpenTelemetry | ||
| { | ||
| /// <summary> | ||
| /// Baggage implementation. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// Spec reference: <a href="https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/baggage/api.md">Baggage API</a>. | ||
| /// </remarks> | ||
| public readonly struct Baggage : IEquatable<Baggage> | ||
| { | ||
| private static readonly RuntimeContextSlot<Baggage> RuntimeContextSlot = RuntimeContext.RegisterSlot<Baggage>("otel.baggage"); | ||
| private static readonly Dictionary<string, string> EmptyBaggage = new Dictionary<string, string>(); | ||
|
|
||
| private readonly Dictionary<string, string> baggage; | ||
|
|
||
| /// <summary> | ||
| /// Initializes a new instance of the <see cref="Baggage"/> struct. | ||
| /// </summary> | ||
| /// <param name="baggage">Baggage key/value pairs.</param> | ||
| internal Baggage(Dictionary<string, string> baggage) | ||
| { | ||
| this.baggage = baggage; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Gets or sets the current <see cref="Baggage"/>. | ||
| /// </summary> | ||
| public static Baggage Current | ||
| { | ||
| get => RuntimeContextSlot.Get(); | ||
| set => RuntimeContextSlot.Set(value); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Gets the number of key/value pairs in the baggage. | ||
| /// </summary> | ||
| public int Count => this.baggage?.Count ?? 0; | ||
|
|
||
| /// <summary> | ||
| /// Compare two entries of <see cref="Baggage"/> for equality. | ||
| /// </summary> | ||
| /// <param name="left">First Entry to compare.</param> | ||
| /// <param name="right">Second Entry to compare.</param> | ||
| public static bool operator ==(Baggage left, Baggage right) => left.Equals(right); | ||
|
|
||
| /// <summary> | ||
| /// Compare two entries of <see cref="Baggage"/> for not equality. | ||
| /// </summary> | ||
| /// <param name="left">First Entry to compare.</param> | ||
| /// <param name="right">Second Entry to compare.</param> | ||
| public static bool operator !=(Baggage left, Baggage right) => !(left == right); | ||
|
|
||
| /// <summary> | ||
| /// Create a <see cref="Baggage"/> instance from dictionary of baggage key/value pairs. | ||
| /// </summary> | ||
| /// <param name="baggageItems">Baggage key/value pairs.</param> | ||
| /// <returns><see cref="Baggage"/>.</returns> | ||
| public static Baggage Create(Dictionary<string, string> baggageItems = null) | ||
| { | ||
| if (baggageItems == null) | ||
| { | ||
| return default; | ||
| } | ||
|
|
||
| Dictionary<string, string> baggageCopy = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); | ||
| foreach (KeyValuePair<string, string> baggageItem in baggageItems) | ||
| { | ||
| if (string.IsNullOrEmpty(baggageItem.Value)) | ||
| { | ||
| baggageCopy.Remove(baggageItem.Key); | ||
| continue; | ||
| } | ||
|
|
||
| baggageCopy[baggageItem.Key] = baggageItem.Value; | ||
| } | ||
|
|
||
| return new Baggage(baggageCopy); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Returns the name/value pairs in the <see cref="Baggage"/>. | ||
| /// </summary> | ||
| /// <param name="baggage">Optional <see cref="Baggage"/>. <see cref="Current"/> is used if not specified.</param> | ||
| /// <returns>Baggage key/value pairs.</returns> | ||
| public static IReadOnlyDictionary<string, string> GetBaggage(Baggage baggage = default) | ||
| => baggage == default ? Current.GetBaggage() : baggage.GetBaggage(); | ||
|
|
||
| /// <summary> | ||
| /// Returns an enumerator that iterates through the <see cref="Baggage"/>. | ||
| /// </summary> | ||
| /// <param name="baggage">Optional <see cref="Baggage"/>. <see cref="Current"/> is used if not specified.</param> | ||
| /// <returns><see cref="Dictionary{TKey, TValue}.Enumerator"/>.</returns> | ||
| public static Dictionary<string, string>.Enumerator GetEnumerator(Baggage baggage = default) | ||
| => baggage == default ? Current.GetEnumerator() : baggage.GetEnumerator(); | ||
|
|
||
| /// <summary> | ||
| /// Returns the value associated with the given name, or <see langword="null"/> if the given name is not present. | ||
| /// </summary> | ||
| /// <param name="name">Baggage item name.</param> | ||
| /// <param name="baggage">Optional <see cref="Baggage"/>. <see cref="Current"/> is used if not specified.</param> | ||
| /// <returns>Baggage item or <see langword="null"/> if nothing was found.</returns> | ||
| public static string GetBaggage(string name, Baggage baggage = default) | ||
| => baggage == default ? Current.GetBaggage(name) : baggage.GetBaggage(name); | ||
|
|
||
| /// <summary> | ||
| /// Returns a new <see cref="Baggage"/> which contains the new key/value pair. | ||
| /// </summary> | ||
| /// <param name="name">Baggage item name.</param> | ||
| /// <param name="value">Baggage item value.</param> | ||
| /// <param name="baggage">Optional <see cref="Baggage"/>. <see cref="Current"/> is used if not specified.</param> | ||
| /// <returns>New <see cref="Baggage"/> containing the key/value pair.</returns> | ||
| public static Baggage SetBaggage(string name, string value, Baggage baggage = default) | ||
| => baggage == default ? Current.SetBaggage(name, value) : baggage.SetBaggage(name, value); | ||
|
|
||
| /// <summary> | ||
| /// Returns a new <see cref="Baggage"/> which contains the new key/value pair. | ||
| /// </summary> | ||
| /// <param name="baggageItems">Baggage key/value pairs.</param> | ||
| /// <param name="baggage">Optional <see cref="Baggage"/>. <see cref="Current"/> is used if not specified.</param> | ||
| /// <returns>New <see cref="Baggage"/> containing the key/value pair.</returns> | ||
| public static Baggage SetBaggage(IEnumerable<KeyValuePair<string, string>> baggageItems, Baggage baggage = default) | ||
| => baggage == default ? Current.SetBaggage(baggageItems) : baggage.SetBaggage(baggageItems); | ||
|
|
||
| /// <summary> | ||
| /// Returns a new <see cref="Baggage"/> with the key/value pair removed. | ||
| /// </summary> | ||
| /// <param name="name">Baggage item name.</param> | ||
| /// <param name="baggage">Optional <see cref="Baggage"/>. <see cref="Current"/> is used if not specified.</param> | ||
| /// <returns>New <see cref="Baggage"/> containing the key/value pair.</returns> | ||
| public static Baggage RemoveBaggage(string name, Baggage baggage = default) | ||
| => baggage == default ? Current.RemoveBaggage(name) : baggage.RemoveBaggage(name); | ||
|
|
||
| /// <summary> | ||
| /// Returns a new <see cref="Baggage"/> with all the key/value pairs removed. | ||
| /// </summary> | ||
| /// <param name="baggage">Optional <see cref="Baggage"/>. <see cref="Current"/> is used if not specified.</param> | ||
| /// <returns>New <see cref="Baggage"/> containing the key/value pair.</returns> | ||
| public static Baggage ClearBaggage(Baggage baggage = default) | ||
| => baggage == default ? Current.ClearBaggage() : baggage.ClearBaggage(); | ||
|
|
||
| /// <summary> | ||
| /// Returns the name/value pairs in the <see cref="Baggage"/>. | ||
| /// </summary> | ||
| /// <returns>Baggage key/value pairs.</returns> | ||
| public IReadOnlyDictionary<string, string> GetBaggage() | ||
| => this.baggage ?? EmptyBaggage; | ||
|
|
||
| /// <summary> | ||
| /// Returns the value associated with the given name, or <see langword="null"/> if the given name is not present. | ||
| /// </summary> | ||
| /// <param name="name">Baggage item name.</param> | ||
| /// <returns>Baggage item or <see langword="null"/> if nothing was found.</returns> | ||
| public string GetBaggage(string name) | ||
| { | ||
| if (string.IsNullOrEmpty(name)) | ||
| { | ||
| throw new ArgumentNullException(nameof(name)); | ||
| } | ||
|
|
||
| return this.baggage != null && this.baggage.TryGetValue(name, out string value) | ||
| ? value | ||
| : null; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Returns a new <see cref="Baggage"/> which contains the new key/value pair. | ||
| /// </summary> | ||
| /// <param name="name">Baggage item name.</param> | ||
| /// <param name="value">Baggage item value.</param> | ||
| /// <returns>New <see cref="Baggage"/> containing the key/value pair.</returns> | ||
| public Baggage SetBaggage(string name, string value) | ||
| { | ||
| if (string.IsNullOrEmpty(value)) | ||
| { | ||
| return this.RemoveBaggage(name); | ||
| } | ||
|
|
||
| return Current = new Baggage( | ||
| new Dictionary<string, string>(this.baggage ?? EmptyBaggage, StringComparer.OrdinalIgnoreCase) | ||
| { | ||
| [name] = value, | ||
| }); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Returns a new <see cref="Baggage"/> which contains the new key/value pair. | ||
| /// </summary> | ||
| /// <param name="baggageItems">Baggage key/value pairs.</param> | ||
| /// <returns>New <see cref="Baggage"/> containing the key/value pair.</returns> | ||
| public Baggage SetBaggage(params KeyValuePair<string, string>[] baggageItems) | ||
| => this.SetBaggage((IEnumerable<KeyValuePair<string, string>>)baggageItems); | ||
|
|
||
| /// <summary> | ||
| /// Returns a new <see cref="Baggage"/> which contains the new key/value pair. | ||
| /// </summary> | ||
| /// <param name="baggageItems">Baggage key/value pairs.</param> | ||
| /// <returns>New <see cref="Baggage"/> containing the key/value pair.</returns> | ||
| public Baggage SetBaggage(IEnumerable<KeyValuePair<string, string>> baggageItems) | ||
| { | ||
| if ((baggageItems?.Count() ?? 0) <= 0) | ||
| { | ||
| return this; | ||
| } | ||
|
|
||
| var newBaggage = new Dictionary<string, string>(this.baggage ?? EmptyBaggage, StringComparer.OrdinalIgnoreCase); | ||
|
|
||
| foreach (var item in baggageItems) | ||
| { | ||
| if (string.IsNullOrEmpty(item.Value)) | ||
| { | ||
| newBaggage.Remove(item.Key); | ||
| } | ||
| else | ||
| { | ||
| newBaggage[item.Key] = item.Value; | ||
| } | ||
| } | ||
|
|
||
| return Current = new Baggage(newBaggage); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Returns a new <see cref="Baggage"/> with the key/value pair removed. | ||
| /// </summary> | ||
| /// <param name="name">Baggage item name.</param> | ||
| /// <returns>New <see cref="Baggage"/> containing the key/value pair.</returns> | ||
| public Baggage RemoveBaggage(string name) | ||
| { | ||
| var baggage = new Dictionary<string, string>(this.baggage ?? EmptyBaggage, StringComparer.OrdinalIgnoreCase); | ||
| baggage.Remove(name); | ||
|
|
||
| return Current = new Baggage(baggage); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Returns a new <see cref="Baggage"/> with all the key/value pairs removed. | ||
| /// </summary> | ||
| /// <returns>New <see cref="Baggage"/> containing the key/value pair.</returns> | ||
| public Baggage ClearBaggage() | ||
| => Current = default; | ||
|
|
||
| /// <summary> | ||
| /// Returns an enumerator that iterates through the <see cref="Baggage"/>. | ||
| /// </summary> | ||
| /// <returns><see cref="Dictionary{TKey, TValue}.Enumerator"/>.</returns> | ||
| public Dictionary<string, string>.Enumerator GetEnumerator() | ||
| => (this.baggage ?? EmptyBaggage).GetEnumerator(); | ||
|
|
||
| /// <inheritdoc/> | ||
| public bool Equals(Baggage other) | ||
| { | ||
| bool baggageIsNullOrEmpty = this.baggage == null || this.baggage.Count <= 0; | ||
|
|
||
| if (baggageIsNullOrEmpty != (other.baggage == null || other.baggage.Count <= 0)) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| return baggageIsNullOrEmpty || this.baggage.SequenceEqual(other.baggage); | ||
| } | ||
|
|
||
| /// <inheritdoc/> | ||
| public override bool Equals(object obj) | ||
| => (obj is Baggage baggage) && this.Equals(baggage); | ||
|
|
||
| /// <inheritdoc/> | ||
| public override int GetHashCode() | ||
| { | ||
| var baggage = this.baggage ?? EmptyBaggage; | ||
|
|
||
| unchecked | ||
| { | ||
| int res = 17; | ||
| foreach (var item in baggage) | ||
| { | ||
| res = (res * 23) + baggage.Comparer.GetHashCode(item.Key); | ||
| res = (res * 23) + item.Value.GetHashCode(); | ||
| } | ||
|
|
||
| return res; | ||
| } | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
minor: if the key does not exist, we might be able to return the same baggage?
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.
I guess it is not important at this stage, and we probably will replace dictionary with a better data structure before GA anyways.
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.
OK I'll leave as is. I did consider that case. I figured if user is calling RemoveBaggage, they probably know it exists. So I didn't want to waste perf doing a hash + lookup where in most cases it would be wasteful? My thinking could be off tho.