diff --git a/src/OpenTracing/Util/ThreadLocalScope.cs b/src/OpenTracing/Util/ThreadLocalScope.cs
new file mode 100644
index 0000000..680c5f7
--- /dev/null
+++ b/src/OpenTracing/Util/ThreadLocalScope.cs
@@ -0,0 +1,42 @@
+namespace OpenTracing.Util
+{
+ ///
+ ///
+ /// A primitive that relies on thread local storage for
+ /// managing active scopes. Intended to be used in systems where multiple logical,
+ /// related operations are all executed in the same thread albeit at different times.
+ ///
+ public class ThreadLocalScope : IScope
+ {
+ private readonly ThreadLocalScopeManager _scopeManager;
+ private readonly bool _finishOnDispose;
+ private readonly IScope _scopeToRestore;
+
+ public ThreadLocalScope(ThreadLocalScopeManager scopeManager, ISpan wrappedSpan, bool finishOnDispose)
+ {
+ _scopeManager = scopeManager;
+ Span = wrappedSpan;
+ _finishOnDispose = finishOnDispose;
+ _scopeToRestore = scopeManager.Active;
+ scopeManager.Active = this;
+ }
+
+ public void Dispose()
+ {
+ if (_scopeManager.Active != this)
+ {
+ // This shouldn't happen if users call methods in the expected order. Bail out.
+ return;
+ }
+
+ if (_finishOnDispose)
+ {
+ Span.Finish();
+ }
+
+ _scopeManager.Active = _scopeToRestore;
+ }
+
+ public ISpan Span { get; }
+ }
+}
diff --git a/src/OpenTracing/Util/ThreadLocalScopeManager.cs b/src/OpenTracing/Util/ThreadLocalScopeManager.cs
new file mode 100644
index 0000000..4124098
--- /dev/null
+++ b/src/OpenTracing/Util/ThreadLocalScopeManager.cs
@@ -0,0 +1,30 @@
+using System;
+
+namespace OpenTracing.Util
+{
+ ///
+ /// An implementation that relies on thread local storage for
+ /// managing active scopes. Intended to be used in systems where multiple logical,
+ /// related operations are all executed in the same thread albeit at different times.
+ ///
+ public class ThreadLocalScopeManager : IScopeManager
+ {
+ /*
+ * Went with ThreadStatic over ThreadLocal because we don't
+ * want scopes to be initialized upon thread initialization by default
+ * and we want ThreadStatic's mutability for restoring / replacing scopes.
+ */
+ [ThreadStatic]
+ private static IScope _active;
+
+ public IScope Active
+ {
+ get => _active;
+ set => _active = value;
+ }
+ public IScope Activate(ISpan span, bool finishSpanOnDispose)
+ {
+ return new ThreadLocalScope(this, span, finishSpanOnDispose);
+ }
+ }
+}