< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Channels.Framing.LoggingStream
Assembly: CoreWCF.NetNamedPipe
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.NetNamedPipe/src/CoreWCF/Channels/Framing/LoggingDuplexPipe.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 67
Coverable lines: 67
Total lines: 262
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 20
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%110%
Flush()100%110%
FlushAsync(...)100%110%
Read(...)100%110%
ReadAsync()100%110%
Seek(...)100%110%
SetLength(...)100%110%
Write(...)100%110%
WriteAsync(...)100%110%
Log(...)0%20200%
BeginRead(...)100%110%
EndRead(...)100%110%
BeginWrite(...)100%110%
EndWrite(...)100%110%
Dispose(...)100%110%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.NetNamedPipe/src/CoreWCF/Channels/Framing/LoggingDuplexPipe.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System;
 5using System.Globalization;
 6using System.IO;
 7using System.IO.Pipelines;
 8using System.Text;
 9using System.Threading;
 10using System.Threading.Tasks;
 11using CoreWCF.Runtime;
 12using Microsoft.Extensions.Logging;
 13
 14namespace CoreWCF.Channels.Framing
 15{
 16    internal class LoggingDuplexPipe : DuplexPipeStreamAdapter<LoggingStream>
 17    {
 18        public LoggingDuplexPipe(IDuplexPipe transport, NetNamedPipeTrace logger) :
 19            base(transport, stream => new LoggingStream(stream, logger))
 20        {
 21        }
 22
 23        public bool LoggingEnabled
 24        {
 25            get => Stream.LoggingEnabled;
 26            internal set => Stream.LoggingEnabled = value;
 27        }
 28    }
 29
 30    internal class DuplexPipeStreamAdapter<TStream> : DuplexPipeStream, IDuplexPipe where TStream : Stream
 31    {
 32        public DuplexPipeStreamAdapter(IDuplexPipe duplexPipe, Func<Stream, TStream> createStream) :
 33            this(duplexPipe, new StreamPipeReaderOptions(leaveOpen: false), new StreamPipeWriterOptions(leaveOpen: false
 34        {
 35        }
 36
 37        public DuplexPipeStreamAdapter(IDuplexPipe duplexPipe, StreamPipeReaderOptions readerOptions, StreamPipeWriterOp
 38        {
 39            Stream = createStream(this);
 40            Input = PipeReader.Create(Stream, readerOptions);
 41            Output = PipeWriter.Create(Stream, writerOptions);
 42        }
 43
 44        public TStream Stream { get; }
 45
 46        public PipeReader Input { get; }
 47
 48        public PipeWriter Output { get; }
 49
 50        protected override void Dispose(bool disposing)
 51        {
 52            Input.Complete();
 53            Output.Complete();
 54            base.Dispose(disposing);
 55        }
 56
 57        //public override ValueTask DisposeAsync()
 58        //{
 59        //    Input.Complete();
 60        //    Output.Complete();
 61        //    return base.DisposeAsync();
 62        //}
 63    }
 64
 65    internal sealed class LoggingStream : Stream
 66    {
 67        private readonly Stream _inner;
 68        private readonly NetNamedPipeTrace _logger;
 69
 070        public LoggingStream(Stream inner, NetNamedPipeTrace logger)
 71        {
 072            _inner = inner;
 073            _logger = logger;
 074        }
 75
 076        public override bool CanRead => _inner.CanRead;
 77
 078        public override bool CanSeek => _inner.CanSeek;
 79
 080        public override bool CanWrite => _inner.CanWrite;
 81
 082        public override long Length => _inner.Length;
 83
 84        public override long Position
 85        {
 086            get => _inner.Position;
 087            set => _inner.Position = value;
 88        }
 89
 090        public bool LoggingEnabled { get; internal set; }
 91
 092        public override void Flush() => _inner.Flush();
 93
 094        public override Task FlushAsync(CancellationToken cancellationToken) => _inner.FlushAsync(cancellationToken);
 95
 96        public override int Read(byte[] buffer, int offset, int count)
 97        {
 098            int read = _inner.Read(buffer, offset, count);
 099            Log("Read", new ReadOnlySpan<byte>(buffer, offset, read));
 0100            return read;
 101        }
 102
 103        // TODO: Enable code when moving to .NET 5
 104        //public override int Read(Span<byte> destination)
 105        //{
 106        //    int read = _inner.Read(destination);
 107        //    Log("Read", destination.Slice(0, read));
 108        //    return read;
 109        //}
 110
 111        public async override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationTo
 112        {
 0113            int read = await _inner.ReadAsync(buffer, offset, count, cancellationToken);
 0114            Log("ReadAsync", new ReadOnlySpan<byte>(buffer, offset, read));
 0115            return read;
 0116        }
 117
 118        // TODO: Enable code when moving to .NET 5
 119        //public override async ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken =
 120        //{
 121        //    int read = await _inner.ReadAsync(destination, cancellationToken);
 122        //    Log("ReadAsync", destination.Span.Slice(0, read));
 123        //    return read;
 124        //}
 125
 126        public override long Seek(long offset, SeekOrigin origin)
 127        {
 0128            return _inner.Seek(offset, origin);
 129        }
 130
 131        public override void SetLength(long value)
 132        {
 0133            _inner.SetLength(value);
 0134        }
 135
 136        public override void Write(byte[] buffer, int offset, int count)
 137        {
 0138            Log("Write", new ReadOnlySpan<byte>(buffer, offset, count));
 0139            _inner.Write(buffer, offset, count);
 0140        }
 141
 142        // TODO: Enable code when moving to .NET 5
 143        //public override void Write(ReadOnlySpan<byte> source)
 144        //{
 145        //    Log("Write", source);
 146        //    _inner.Write(source);
 147        //}
 148
 149        public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
 150        {
 0151            Log("WriteAsync", new ReadOnlySpan<byte>(buffer, offset, count));
 0152            return _inner.WriteAsync(buffer, offset, count, cancellationToken);
 153        }
 154
 155        // TODO: Enable code when moving to .NET 5
 156        //public override ValueTask WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken = defaul
 157        //{
 158        //    Log("WriteAsync", source.Span);
 159        //    return _inner.WriteAsync(source, cancellationToken);
 160        //}
 161
 162        private void Log(string method, ReadOnlySpan<byte> buffer)
 163        {
 0164            if (!LoggingEnabled || !_logger.IsEnabled(LogLevel.Debug))
 165            {
 0166                return;
 167            }
 168
 0169            var builder = new StringBuilder();
 170            //builder.Append(method);
 171            //builder.Append('[');
 172            //builder.Append(buffer.Length);
 173            //builder.Append(']');
 174
 0175            if (buffer.Length > 0)
 176            {
 0177                builder.AppendLine();
 178            }
 179
 0180            var charBuilder = new StringBuilder();
 181
 182            // Write the hex
 0183            for (int i = 0; i < buffer.Length; i++)
 184            {
 0185                builder.Append(buffer[i].ToString("X2", CultureInfo.InvariantCulture));
 0186                builder.Append(' ');
 187
 0188                var bufferChar = (char)buffer[i];
 0189                if (char.IsControl(bufferChar))
 190                {
 0191                    charBuilder.Append('.');
 192                }
 193                else
 194                {
 0195                    charBuilder.Append(bufferChar);
 196                }
 197
 0198                if ((i + 1) % 16 == 0)
 199                {
 0200                    builder.Append("  ");
 0201                    builder.Append(charBuilder);
 0202                    if (i != buffer.Length - 1)
 203                    {
 0204                        builder.AppendLine();
 205                    }
 0206                    charBuilder.Clear();
 207                }
 0208                else if ((i + 1) % 8 == 0)
 209                {
 0210                    builder.Append(' ');
 0211                    charBuilder.Append(' ');
 212                }
 213            }
 214
 215            // Different than charBuffer.Length since charBuffer contains an extra " " after the 8th byte.
 0216            var numBytesInLastLine = buffer.Length % 16;
 217
 0218            if (numBytesInLastLine > 0)
 219            {
 220                // 2 (between hex and char blocks) + num bytes left (3 per byte)
 0221                var padLength = 2 + (3 * (16 - numBytesInLastLine));
 222                // extra for space after 8th byte
 0223                if (numBytesInLastLine < 8)
 224                {
 0225                    padLength++;
 226                }
 227
 0228                builder.Append(new string(' ', padLength));
 0229                builder.Append(charBuilder);
 230            }
 231
 0232            _logger.LogBytes(method, buffer.Length, builder.ToString());
 0233        }
 234
 235        // The below APM methods call the underlying Read/WriteAsync methods which will still be logged.
 236        public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object stat
 237        {
 0238            return ReadAsync(buffer, offset, count, default(CancellationToken)).ToApm(callback, state);
 239        }
 240
 241        public override int EndRead(IAsyncResult asyncResult)
 242        {
 0243            return asyncResult.ToApmEnd<int>();
 244        }
 245
 246        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object sta
 247        {
 0248            return WriteAsync(buffer, offset, count, default).ToApm(callback, state);
 249        }
 250
 251        public override void EndWrite(IAsyncResult asyncResult)
 252        {
 0253            asyncResult.ToApmEnd();
 0254        }
 255
 256        protected override void Dispose(bool disposing)
 257        {
 0258            base.Dispose(disposing);
 0259            _inner.Dispose();
 0260        }
 261    }
 262}