diff --git a/README.md b/README.md
index 05869143..b7a2ae36 100644
--- a/README.md
+++ b/README.md
@@ -211,7 +211,7 @@ You can optionally configure the `RecyclableStreamManager.ThrowExceptionOnToArra
| -----|-------|-------------|
| MemoryStreamCreated | Verbose | Logged every time a stream object is allocated. Fields: `guid`, `tag`, `requestedSize`, `actualSize`. |
| MemoryStreamDisposed | Verbose | Logged every time a stream object is disposed. Fields: `guid`, `tag`, `allocationStack`, `disposeStack`. |
-| MemoryStreamDoubleDispose | Critical | Logged if a stream is disposed more than once. This indicates a logic error by the user of the stream. Dispose should happen exactly once per stream to avoid resource usage bugs. Fields: `guid`, `tag`, `allocationStack`, `disposeStack1`, `disposeStack2`. |
+| MemoryStreamDoubleDispose | Verbose | Logged if a stream is disposed more than once. This indicates a logic error by the user of the stream. Dispose should happen exactly once per stream to avoid resource usage bugs. Fields: `guid`, `tag`, `allocationStack`, `disposeStack1`, `disposeStack2`. |
| MemoryStreamFinalized | Error | Logged if a stream has gone out of scope without being disposed. This indicates a resource leak. Fields: `guid`, `tag`, `allocationStack`.|
| MemoryStreamToArray | Verbose | Logged whenever `ToArray` is called. This indicates a potential problem, as calling `ToArray` goes against the concepts of good memory practice which `RecyclableMemoryStream` is trying to solve. Fields: `guid`, `tag`, `stack`, `size`.|
| MemoryStreamManagerInitialized| Informational | Logged when the `RecyclableMemoryStreamManager` is initialized. Fields: `blockSize`, `largeBufferMultiple`, `maximumBufferSize`.|
diff --git a/src/Events.cs b/src/Events.cs
index 076685bf..3a4d8799 100644
--- a/src/Events.cs
+++ b/src/Events.cs
@@ -110,7 +110,7 @@ public void MemoryStreamDisposed(Guid guid, string? tag, long lifetimeMs, string
/// Call stack of the first dispose.
/// Call stack of the second dispose.
/// Note: Stacks will only be populated if RecyclableMemoryStreamManager.GenerateCallStacks is true.
- [Event(3, Level = EventLevel.Critical)]
+ [Event(3, Level = EventLevel.Verbose)]
public void MemoryStreamDoubleDispose(Guid guid, string? tag, string? allocationStack, string? disposeStack1,
string? disposeStack2)
{
diff --git a/src/RecyclableMemoryStream.cs b/src/RecyclableMemoryStream.cs
index 42f16431..27a2064f 100644
--- a/src/RecyclableMemoryStream.cs
+++ b/src/RecyclableMemoryStream.cs
@@ -280,7 +280,7 @@ protected override void Dispose(bool disposing)
if (this.disposed)
{
string? doubleDisposeStack = null;
- if (this.memoryManager.options.GenerateCallStacks)
+ if (this.memoryManager.GenerateDoubleDisposedStackTrace)
{
doubleDisposeStack = Environment.StackTrace;
}
diff --git a/src/RecyclableMemoryStreamManager.cs b/src/RecyclableMemoryStreamManager.cs
index 985309b7..5f8f85f9 100644
--- a/src/RecyclableMemoryStreamManager.cs
+++ b/src/RecyclableMemoryStreamManager.cs
@@ -25,6 +25,7 @@ namespace Microsoft.IO
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+ using System.Diagnostics.Tracing;
using System.Runtime.CompilerServices;
using System.Threading;
@@ -82,6 +83,13 @@ public partial class RecyclableMemoryStreamManager
internal readonly Options options;
+ internal bool GenerateDoubleDisposedStackTrace =>
+ this.options.GenerateCallStacks &&
+ (
+ this.StreamDoubleDisposed != null ||
+ Events.Writer.IsEnabled(EventLevel.Verbose, EventKeywords.None)
+ );
+
///
/// Settings for controlling the behavior of RecyclableMemoryStream
///