static void ReadMulticastFooter( int streamVersion, CKBinaryReader r, StreamLogType t, out Guid mId, out int depth, out LogEntryType prevType, out DateTimeStamp prevTime ) { Debug.Assert( Guid.Empty.ToByteArray().Length == 16 ); mId = new Guid( r.ReadBytes( 16 ) ); depth = streamVersion < 6 ? r.ReadInt32() : r.ReadNonNegativeSmallInt32(); if( depth < 0 ) throw new InvalidDataException(); prevType = LogEntryType.None; prevTime = DateTimeStamp.Unknown; if( (t & StreamLogType.IsPreviousKnown) != 0 ) { prevTime = new DateTimeStamp( DateTime.FromBinary( r.ReadInt64() ), (t & StreamLogType.IsPreviousKnownHasUniquifier) != 0 ? r.ReadByte() : (Byte)0 ); prevType = (LogEntryType)r.ReadByte(); } }
static ILogEntry ReadGroupClosed( int streamVersion, CKBinaryReader r, StreamLogType t, LogLevel logLevel ) { DateTimeStamp time = new DateTimeStamp( DateTime.FromBinary( r.ReadInt64() ), (t & StreamLogType.HasUniquifier) != 0 ? r.ReadByte() : (Byte)0 ); ActivityLogGroupConclusion[] conclusions = Util.Array.Empty<ActivityLogGroupConclusion>(); if( (t & StreamLogType.HasConclusions) != 0 ) { int conclusionsCount = streamVersion < 6 ? r.ReadInt32() : r.ReadNonNegativeSmallInt32(); conclusions = new ActivityLogGroupConclusion[conclusionsCount]; for( int i = 0; i < conclusionsCount; i++ ) { CKTrait cTags = ActivityMonitor.Tags.Register( r.ReadString() ); string cText = r.ReadString(); conclusions[i] = new ActivityLogGroupConclusion( cText, cTags ); } } if( (t & StreamLogType.IsMultiCast) == 0 ) { return new LECloseGroup( time, logLevel, conclusions ); } Guid mId; int depth; LogEntryType prevType; DateTimeStamp prevTime; ReadMulticastFooter( streamVersion, r, t, out mId, out depth, out prevType, out prevTime ); return new LEMCCloseGroup( mId, depth, prevTime, prevType, time, logLevel, conclusions ); }
/// <summary> /// Reads a <see cref="ILogEntry"/> from the binary reader that can be a <see cref="IMulticastLogEntry"/>. /// If the first read byte is 0, read stops and null is returned. /// The 0 byte is the "end marker" that <see cref="CKMonWriterClient.Close()"/> write, but this /// method can read non zero-terminated streams (it catches an EndOfStreamException when reading the first byte and handles it silently). /// This method can throw any type of exception (<see cref="System.IO.EndOfStreamException"/> or <see cref="InvalidDataException"/> for instance) that /// must be handled by the caller. /// </summary> /// <param name="r">The binary reader.</param> /// <param name="streamVersion">The version of the stream.</param> /// <param name="badEndOfFile">True whenever the end of file is the result of an <see cref="EndOfStreamException"/>.</param> /// <returns>The log entry or null if a zero byte (end marker) has been found.</returns> static public ILogEntry Read( CKBinaryReader r, int streamVersion, out bool badEndOfFile ) { if( r == null ) throw new ArgumentNullException( "r" ); badEndOfFile = false; StreamLogType t = StreamLogType.EndOfStream; LogLevel logLevel = LogLevel.None; try { ReadLogTypeAndLevel( r, out t, out logLevel ); } catch( EndOfStreamException ) { badEndOfFile = true; // Silently ignores here reading beyond the stream: this // kindly handles the lack of terminating 0 byte. } if( t == StreamLogType.EndOfStream ) return null; if( (t & StreamLogType.TypeMask) == StreamLogType.TypeGroupClosed ) { return ReadGroupClosed( streamVersion, r, t, logLevel ); } DateTimeStamp time = new DateTimeStamp( DateTime.FromBinary( r.ReadInt64() ), (t & StreamLogType.HasUniquifier) != 0 ? r.ReadByte() : (Byte)0 ); if( time.TimeUtc.Year < 2014 || time.TimeUtc.Year > 3000 ) throw new InvalidDataException( "Date year before 2014 or after 3000 are considered invalid." ); CKTrait tags = ActivityMonitor.Tags.Empty; string fileName = null; int lineNumber = 0; CKExceptionData ex = null; string text = null; if( (t & StreamLogType.HasTags) != 0 ) tags = ActivityMonitor.Tags.Register( r.ReadString() ); if( (t & StreamLogType.HasFileName) != 0 ) { fileName = r.ReadString(); lineNumber = streamVersion < 6 ? r.ReadInt32() : r.ReadNonNegativeSmallInt32(); if( lineNumber > 100*1000 ) throw new InvalidDataException( "LineNumber greater than 100K is considered invalid." ); } if( (t & StreamLogType.HasException) != 0 ) { ex = new CKExceptionData( r, (t & StreamLogType.IsLFOnly) == 0 ); if( (t & StreamLogType.IsTextTheExceptionMessage) != 0 ) text = ex.Message; } if( text == null ) text = r.ReadString( (t & StreamLogType.IsLFOnly) == 0 ); Guid mId; int depth; LogEntryType prevType; DateTimeStamp prevTime; if( (t & StreamLogType.TypeMask) == StreamLogType.TypeLine ) { if( (t & StreamLogType.IsMultiCast) == 0 ) { return new LELog( text, time, fileName, lineNumber, logLevel, tags, ex ); } ReadMulticastFooter( streamVersion, r, t, out mId, out depth, out prevType, out prevTime ); return new LEMCLog( mId, depth, prevTime, prevType, text, time, fileName, lineNumber, logLevel, tags, ex ); } if( (t & StreamLogType.TypeMask) != StreamLogType.TypeOpenGroup ) throw new InvalidDataException(); if( (t & StreamLogType.IsMultiCast) == 0 ) { return new LEOpenGroup( text, time, fileName, lineNumber, logLevel, tags, ex ); } ReadMulticastFooter( streamVersion, r, t, out mId, out depth, out prevType, out prevTime ); return new LEMCOpenGroup( mId, depth, prevTime, prevType, text, time, fileName, lineNumber, logLevel, tags, ex ); }