Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
ea8459b
Baggage context part 1.
CodeBlanch Aug 20, 2020
804746a
A little cleanup.
CodeBlanch Aug 20, 2020
d26ec72
Merge branch 'master' into baggage-context
cijothomas Aug 20, 2020
cfef67a
Return strings instead of objects. Removed default value in ctor beca…
CodeBlanch Aug 20, 2020
e9e82ba
Merge branch 'baggage-context' of https://github.com/CodeBlanch/opent…
CodeBlanch Aug 20, 2020
6b6598a
Updated SDK & API projects for BaggageContext.
CodeBlanch Aug 21, 2020
b9a3b31
Fixed broken areas, except for CorrelationContext tests.
CodeBlanch Aug 21, 2020
06e0a2e
First round of tests and bug fixes.
CodeBlanch Aug 21, 2020
cea26fb
Merging latest from master.
CodeBlanch Aug 22, 2020
666655f
FIxed up HTTP instrumentation tests.
CodeBlanch Aug 22, 2020
b584536
Fixed up shim tests.
CodeBlanch Aug 22, 2020
9c532c0
More tests and improvements.
CodeBlanch Aug 22, 2020
be923f2
Merging from master.
CodeBlanch Aug 25, 2020
4f1758a
Fixed broken test.
CodeBlanch Aug 25, 2020
3e6d3bd
Test coverage and bug fixes.
CodeBlanch Aug 25, 2020
6955142
Deterministic GetHashCode + tests.
CodeBlanch Aug 26, 2020
144093f
Merging latest from master.
CodeBlanch Aug 26, 2020
6ced696
Added a link to the baggage api.
CodeBlanch Aug 26, 2020
abe67ae
Updated CHANGELOG.
CodeBlanch Aug 26, 2020
f7a1528
Renamed BaggageContext -> Baggage.
CodeBlanch Aug 26, 2020
32ccef4
CHANGELOG update.
CodeBlanch Aug 26, 2020
3c89146
Merge branch 'master' into baggage-context
CodeBlanch Aug 27, 2020
d2bf842
Merge branch 'master' into baggage-context
cijothomas Aug 27, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using System.Diagnostics;
using System.Text;
using Microsoft.Extensions.Logging;
using OpenTelemetry.Context;
using OpenTelemetry.Context.Propagation;
using RabbitMQ.Client;

Expand Down Expand Up @@ -61,7 +62,7 @@ public string SendMessage()
if (activity != null)
{
// Inject the ActivityContext into the message headers to propagate trace context to the receiving service.
TextFormat.Inject(new PropagationContext(activity.Context, activity.Baggage), props, this.InjectTraceContextIntoBasicProperties);
TextFormat.Inject(new PropagationContext(activity.Context, BaggageContext.Current), props, this.InjectTraceContextIntoBasicProperties);

// The OpenTelemetry messaging specification defines a number of attributes. These attributes are added here.
RabbitMqHelper.AddMessagingTags(activity);
Expand Down
241 changes: 241 additions & 0 deletions src/OpenTelemetry.Api/Context/BaggageContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
// <copyright file="BaggageContext.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;

namespace OpenTelemetry.Context
{
/// <summary>
/// Baggage context.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Add a link to OTel spec here.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. It's a dead link right now, but should work once the rename PR is merged.

/// </summary>
public readonly struct BaggageContext : IEquatable<BaggageContext>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should name it just Baggage.
https://w3c.github.io/baggage/

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a different opinion on this. This is similar to the fact that we have SpanContext while W3C has TraceContext.
The W3C spec is describing the wire format. The in process representation and class name don't have to (or even should not) follow a name mentioned in the wire format spec.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can call it whatever OpenTelemetry spec decide to call it. It looked to me like the plan is to replace CorrelationContext to Baggage.
open-telemetry/opentelemetry-specification#536
If its called BaggageContext, then we are good here.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, totally agree. We should follow the OpenTelemetry spec (unless the name is already taken by .NET - such like Span 😆).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I was doing this work, I had it called "Baggage" initially. But for some reason, I felt like the spec would stick with keeping "Context" in the name and it would end up being "BaggageContext" instead. It's really just a guess, we can always rename when it settles?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, lets keep BaggageContext for now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed name to Baggage

{
private static readonly RuntimeContextSlot<BaggageContext> RuntimeContextSlot = RuntimeContext.RegisterSlot<BaggageContext>("otel.baggage_context");
private static readonly Dictionary<string, string> EmptyBaggage = new Dictionary<string, string>();
Comment thread
CodeBlanch marked this conversation as resolved.
Outdated

private readonly Dictionary<string, string> baggage;

/// <summary>
/// Initializes a new instance of the <see cref="BaggageContext"/> struct.
/// </summary>
/// <param name="baggage">Baggage key/value pairs.</param>
public BaggageContext(Dictionary<string, string> baggage = null)
{
this.baggage = baggage ?? EmptyBaggage;
}

/// <summary>
/// Gets or sets the current <see cref="BaggageContext"/>.
/// </summary>
public static BaggageContext Current
Comment thread
CodeBlanch marked this conversation as resolved.
Outdated
{
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;

/// <summary>
/// Compare two entries of <see cref="BaggageContext"/> for equality.
/// </summary>
/// <param name="left">First Entry to compare.</param>
/// <param name="right">Second Entry to compare.</param>
public static bool operator ==(BaggageContext left, BaggageContext right) => left.Equals(right);

/// <summary>
/// Compare two entries of <see cref="BaggageContext"/> for not equality.
/// </summary>
/// <param name="left">First Entry to compare.</param>
/// <param name="right">Second Entry to compare.</param>
public static bool operator !=(BaggageContext left, BaggageContext right) => !(left == right);

/// <summary>
/// Returns the name/value pairs in the <see cref="BaggageContext"/>.
/// </summary>
/// <param name="baggageContext">Optional <see cref="BaggageContext"/>. <see cref="Current"/> is used if not specified.</param>
/// <returns>Baggage key/value pairs.</returns>
public static IReadOnlyDictionary<string, string> GetBaggage(BaggageContext baggageContext = default)
=> baggageContext == default ? Current.GetBaggage() : baggageContext.GetBaggage();

/// <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="baggageContext">Optional <see cref="BaggageContext"/>. <see cref="Current"/> is used if not specified.</param>
/// <returns>Baggage item or <see langword="null"/> if nothing was found.</returns>
public static object GetBaggage(string name, BaggageContext baggageContext = default)
=> baggageContext == default ? Current.GetBaggage(name) : baggageContext.GetBaggage(name);

/// <summary>
/// Returns a new <see cref="BaggageContext"/> which contains the new key/value pair.
/// </summary>
/// <param name="name">Baggage item name.</param>
/// <param name="value">Baggage item value.</param>
/// <param name="baggageContext">Optional <see cref="BaggageContext"/>. <see cref="Current"/> is used if not specified.</param>
/// <returns>New <see cref="BaggageContext"/> containing the key/value pair.</returns>
public static BaggageContext SetBaggage(string name, string value, BaggageContext baggageContext = default)
=> baggageContext == default ? Current.SetBaggage(name, value) : baggageContext.SetBaggage(name, value);

/// <summary>
/// Returns a new <see cref="BaggageContext"/> which contains the new key/value pair.
/// </summary>
/// <param name="baggageContext">Optional <see cref="BaggageContext"/>. <see cref="Current"/> is used if not specified.</param>
/// <param name="baggage">Baggage key/value pairs.</param>
/// <returns>New <see cref="BaggageContext"/> containing the key/value pair.</returns>
public static BaggageContext SetBaggage(BaggageContext baggageContext = default, params KeyValuePair<string, string>[] baggage)
=> baggageContext == default ? Current.SetBaggage(baggage) : baggageContext.SetBaggage(baggage);

/// <summary>
/// Returns a new <see cref="BaggageContext"/> which contains the new key/value pair.
/// </summary>
/// <param name="baggage">Baggage key/value pairs.</param>
/// <param name="baggageContext">Optional <see cref="BaggageContext"/>. <see cref="Current"/> is used if not specified.</param>
/// <returns>New <see cref="BaggageContext"/> containing the key/value pair.</returns>
public static BaggageContext SetBaggage(IEnumerable<KeyValuePair<string, string>> baggage, BaggageContext baggageContext = default)
=> baggageContext == default ? Current.SetBaggage(baggage) : baggageContext.SetBaggage(baggage);

/// <summary>
/// Returns a new <see cref="BaggageContext"/> with the key/value pair removed.
/// </summary>
/// <param name="name">Baggage item name.</param>
/// <param name="baggageContext">Optional <see cref="BaggageContext"/>. <see cref="Current"/> is used if not specified.</param>
/// <returns>New <see cref="BaggageContext"/> containing the key/value pair.</returns>
public static BaggageContext RemoveBaggage(string name, BaggageContext baggageContext = default)
=> baggageContext == default ? Current.RemoveBaggage(name) : baggageContext.RemoveBaggage(name);

/// <summary>
/// Returns a new <see cref="BaggageContext"/> with all the key/value pairs removed.
/// </summary>
/// <param name="baggageContext">Optional <see cref="BaggageContext"/>. <see cref="Current"/> is used if not specified.</param>
/// <returns>New <see cref="BaggageContext"/> containing the key/value pair.</returns>
public static BaggageContext ClearBaggage(BaggageContext baggageContext = default)
=> baggageContext == default ? Current.ClearBaggage() : baggageContext.ClearBaggage();

/// <summary>
/// Returns the name/value pairs in the <see cref="BaggageContext"/>.
/// </summary>
/// <returns>Baggage key/value pairs.</returns>
public IReadOnlyDictionary<string, string> GetBaggage()
=> this.baggage;

/// <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 object GetBaggage(string name)
{
return this.baggage.TryGetValue(name, out string value)
? value
: null;
}

/// <summary>
/// Returns a new <see cref="BaggageContext"/> 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="BaggageContext"/> containing the key/value pair.</returns>
public BaggageContext SetBaggage(string name, string value)
{
var baggageContext = new BaggageContext(
new Dictionary<string, string>(this.baggage, StringComparer.OrdinalIgnoreCase)
{
[name] = value,
});

Current = baggageContext;

return baggageContext;
}

/// <summary>
/// Returns a new <see cref="BaggageContext"/> which contains the new key/value pair.
/// </summary>
/// <param name="baggage">Baggage key/value pairs.</param>
/// <returns>New <see cref="BaggageContext"/> containing the key/value pair.</returns>
public BaggageContext SetBaggage(params KeyValuePair<string, string>[] baggage)
=> this.SetBaggage((IEnumerable<KeyValuePair<string, string>>)baggage);

/// <summary>
/// Returns a new <see cref="BaggageContext"/> which contains the new key/value pair.
/// </summary>
/// <param name="baggage">Baggage key/value pairs.</param>
/// <returns>New <see cref="BaggageContext"/> containing the key/value pair.</returns>
public BaggageContext SetBaggage(IEnumerable<KeyValuePair<string, string>> baggage)
{
var newBaggage = new Dictionary<string, string>(this.baggage, StringComparer.OrdinalIgnoreCase);

foreach (var item in baggage)
{
newBaggage[item.Key] = item.Value;
}

var baggageContext = new BaggageContext(newBaggage);
Current = baggageContext;
return baggageContext;
}

/// <summary>
/// Returns a new <see cref="BaggageContext"/> with the key/value pair removed.
/// </summary>
/// <param name="name">Baggage item name.</param>
/// <returns>New <see cref="BaggageContext"/> containing the key/value pair.</returns>
public BaggageContext RemoveBaggage(string name)
{
var baggage = new Dictionary<string, string>(this.baggage, StringComparer.OrdinalIgnoreCase);
baggage.Remove(name);
Comment thread
CodeBlanch marked this conversation as resolved.
Outdated
var baggageContext = new BaggageContext(baggage);
Current = baggageContext;
return baggageContext;
}

/// <summary>
/// Returns a new <see cref="BaggageContext"/> with all the key/value pairs removed.
/// </summary>
/// <returns>New <see cref="BaggageContext"/> containing the key/value pair.</returns>
public BaggageContext ClearBaggage()
{
var baggageContext = new BaggageContext(null);
Current = baggageContext;
return baggageContext;
}

/// <summary>
/// Returns an enumerator that iterates through the <see cref="BaggageContext"/>.
/// </summary>
/// <returns><see cref="Dictionary{TKey, TValue}.Enumerator"/>.</returns>
public Dictionary<string, string>.Enumerator GetEnumerator()
=> this.baggage.GetEnumerator();

/// <inheritdoc/>
public bool Equals(BaggageContext other)
=> this.baggage.SequenceEqual(other.baggage);

/// <inheritdoc/>
public override bool Equals(object obj)
=> (obj is BaggageContext baggageContext) && this.Equals(baggageContext);

/// <inheritdoc/>
public override int GetHashCode()
=> this.baggage.GetHashCode();
}
}
Loading