//
// 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.
//
using System;
using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
namespace OpenTelemetry.Context
{
///
/// Generic runtime context management API.
///
public sealed class RuntimeContext
{
private static readonly ConcurrentDictionary Slots = new ConcurrentDictionary();
///
/// Gets or sets the actual context carrier implementation.
///
#if !NET452
public static Type ContextSlotType { get; set; } = typeof(AsyncLocalRuntimeContextSlot<>);
#else
public static Type ContextSlotType { get; set; } = typeof(RemotingRuntimeContextSlot<>);
#endif
///
/// Register a named context slot.
///
/// The name of the context slot.
/// The type of the underlying value.
/// The slot registered.
public static RuntimeContextSlot RegisterSlot(string name)
{
lock (Slots)
{
if (Slots.ContainsKey(name))
{
throw new InvalidOperationException($"The context slot {name} is already registered.");
}
var type = ContextSlotType.MakeGenericType(typeof(T));
var ctor = type.GetConstructor(new Type[] { typeof(string) });
var slot = (RuntimeContextSlot)ctor.Invoke(new object[] { name });
Slots[name] = slot;
return slot;
}
}
///
/// Get a registered slot from a given name.
///
/// The name of the context slot.
/// The type of the underlying value.
/// The slot previously registered.
public static RuntimeContextSlot GetSlot(string name)
{
return (RuntimeContextSlot)Slots[name];
}
/*
public static void Apply(IDictionary snapshot)
{
foreach (var entry in snapshot)
{
// TODO: revisit this part if we want Snapshot() to be used on critical paths
dynamic value = entry.Value;
SetValue(entry.Key, value);
}
}
public static IDictionary Snapshot()
{
var retval = new Dictionary();
foreach (var entry in Slots)
{
// TODO: revisit this part if we want Snapshot() to be used on critical paths
dynamic slot = entry.Value;
retval[entry.Key] = slot.Get();
}
return retval;
}
*/
///
/// Sets the value to a registered slot.
///
/// The name of the context slot.
/// The value to be set.
/// The type of the value.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void SetValue(string name, T value)
{
var slot = (RuntimeContextSlot)Slots[name];
slot.Set(value);
}
///
/// Gets the value from a registered slot.
///
/// The name of the context slot.
/// The type of the value.
/// The value retrieved from the context slot.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T GetValue(string name)
{
var slot = (RuntimeContextSlot)Slots[name];
return slot.Get();
}
// For testing purpose
// private static Clear
}
}