<PackageReference Include="System.ClientModel" Version="1.8.0" />

MessageLoggingPolicy

A PipelinePolicy used by a ClientPipeline to log request and response information.
using System.ClientModel.Internal; using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; namespace System.ClientModel.Primitives { [System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(0)] public class MessageLoggingPolicy : PipelinePolicy { [System.Runtime.CompilerServices.Nullable(0)] private class MaxLengthStream : MemoryStream { private int _bytesLeft; public MaxLengthStream(int maxLength) { _bytesLeft = maxLength; } public override void Write(byte[] buffer, int offset, int count) { DecrementLength(ref count); if (count > 0) base.Write(buffer, offset, count); } public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { if (count <= 0) return Task.CompletedTask; return base.WriteAsync(buffer, offset, count, cancellationToken); } private void DecrementLength(ref int count) { int num = count = Math.Min(count, _bytesLeft); _bytesLeft -= count; } } [System.Runtime.CompilerServices.Nullable(0)] private class LoggingStream : Stream { private readonly string _requestId; private int _remainingBytesToLog; private readonly Stream _originalStream; private readonly bool _error; [System.Runtime.CompilerServices.Nullable(2)] private readonly Encoding _textEncoding; private int _blockNumber; private readonly PipelineMessageLogger _messageLogger; public override bool CanRead => _originalStream.CanRead; public override bool CanSeek => _originalStream.CanSeek; public override long Length => _originalStream.Length; public override long Position { get { return _originalStream.Position; } set { _originalStream.Position = value; } } public override bool CanWrite => false; public LoggingStream(PipelineMessageLogger messageLogger, string requestId, int maxLoggedBytes, Stream originalStream, bool error, [System.Runtime.CompilerServices.Nullable(2)] Encoding textEncoding) { _requestId = requestId; _remainingBytesToLog = maxLoggedBytes; _originalStream = originalStream; _error = error; _textEncoding = textEncoding; _messageLogger = messageLogger; } public override int Read(byte[] buffer, int offset, int count) { int num = _originalStream.Read(buffer, offset, count); LogBuffer(buffer, offset, num); return num; } [AsyncStateMachine(typeof(<ReadAsync>d__9))] public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { <ReadAsync>d__9 stateMachine = default(<ReadAsync>d__9); stateMachine.<>t__builder = AsyncTaskMethodBuilder<int>.Create(); stateMachine.<>4__this = this; stateMachine.buffer = buffer; stateMachine.offset = offset; stateMachine.count = count; stateMachine.cancellationToken = cancellationToken; stateMachine.<>1__state = -1; stateMachine.<>t__builder.Start(ref stateMachine); return stateMachine.<>t__builder.Task; } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException("This stream does not support seek operations."); } public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException("This stream is read-only."); } public override void SetLength(long value) { throw new NotSupportedException("This stream is read-only."); } public override void Flush() { _originalStream.Flush(); } public override void Close() { _originalStream.Close(); } protected override void Dispose(bool disposing) { base.Dispose(disposing); _originalStream.Dispose(); } [System.Runtime.CompilerServices.NullableContext(0)] private void LogMemory(Memory<byte> memory, int numBytesReadIntoMemory) { int num = Math.Min(numBytesReadIntoMemory, _remainingBytesToLog); _remainingBytesToLog -= num; if (num != 0) { byte[] array = new byte[num]; memory.Slice(0, num).Span.CopyTo(array); if (_error) _messageLogger.LogErrorResponseContentBlock(_requestId, _blockNumber, array, _textEncoding); else _messageLogger.LogResponseContentBlock(_requestId, _blockNumber, array, _textEncoding); _blockNumber++; } } private void LogBuffer(byte[] buffer, int offset, int numBytesReadIntoBuffer) { int num = Math.Min(numBytesReadIntoBuffer, _remainingBytesToLog); _remainingBytesToLog -= num; if (num != 0 && buffer != null) { byte[] array; if (num == numBytesReadIntoBuffer && offset == 0) array = buffer; else { array = new byte[num]; Buffer.BlockCopy(buffer, offset, array, 0, num); } if (_error) _messageLogger.LogErrorResponseContentBlock(_requestId, _blockNumber, array, _textEncoding); else _messageLogger.LogResponseContentBlock(_requestId, _blockNumber, array, _textEncoding); _blockNumber++; } } } private readonly ClientLoggingOptions _loggingOptions; [System.Runtime.CompilerServices.Nullable(2)] private PipelineMessageLogger _messageLogger; private readonly string _clientAssembly = typeof(MessageLoggingPolicy).Assembly.GetName().Name; public static MessageLoggingPolicy Default { get; } = new MessageLoggingPolicy(null); private bool _enableMessageContentLogging => _loggingOptions.EnableMessageContentLogging.GetValueOrDefault(); private int _maxLength => _loggingOptions.MessageContentSizeLimit.GetValueOrDefault(4096); [System.Runtime.CompilerServices.NullableContext(2)] public MessageLoggingPolicy(ClientLoggingOptions options = null) { _loggingOptions = (options ?? new ClientLoggingOptions()); } public sealed override void Process(PipelineMessage message, IReadOnlyList<PipelinePolicy> pipeline, int currentIndex) { ProcessSyncOrAsync(message, pipeline, currentIndex, false).EnsureCompleted(); } [AsyncStateMachine(typeof(<ProcessAsync>d__12))] public sealed override ValueTask ProcessAsync(PipelineMessage message, IReadOnlyList<PipelinePolicy> pipeline, int currentIndex) { <ProcessAsync>d__12 stateMachine = default(<ProcessAsync>d__12); stateMachine.<>t__builder = AsyncValueTaskMethodBuilder.Create(); stateMachine.<>4__this = this; stateMachine.message = message; stateMachine.pipeline = pipeline; stateMachine.currentIndex = currentIndex; stateMachine.<>1__state = -1; stateMachine.<>t__builder.Start(ref stateMachine); return stateMachine.<>t__builder.Task; } [AsyncStateMachine(typeof(<ProcessSyncOrAsync>d__13))] private ValueTask ProcessSyncOrAsync(PipelineMessage message, IReadOnlyList<PipelinePolicy> pipeline, int currentIndex, bool async) { <ProcessSyncOrAsync>d__13 stateMachine = default(<ProcessSyncOrAsync>d__13); stateMachine.<>t__builder = AsyncValueTaskMethodBuilder.Create(); stateMachine.<>4__this = this; stateMachine.message = message; stateMachine.pipeline = pipeline; stateMachine.currentIndex = currentIndex; stateMachine.async = async; stateMachine.<>1__state = -1; stateMachine.<>t__builder.Start(ref stateMachine); return stateMachine.<>t__builder.Task; } } }