チェンジセット 1479 (default)
- 日時:
- 2020/03/21 23:05:01 (5年前)
- 場所:
- TinyLogViewer/trunk
- ファイル:
-
- 1個の追加
- 5個の更新
凡例:
- 未変更
- 追加
- 削除
-
TinyLogViewer/trunk/TinyLogViewer/Sources/LogBlock.cs
r1476 r1479 59 59 60 60 /// <summary> 61 /// 最後の行の行末の種類。 62 /// </summary> 63 [DebuggerBrowsable(DebuggerBrowsableState.Never)] 64 private LineEndType lastLineEndType; 65 66 /// <summary> 61 67 /// 次のログブロック。 62 68 /// </summary> … … 72 78 /// <param name="bytesCount">データの長さを表すバイト数。</param> 73 79 /// <param name="lineNumber">行番号。</param> 74 internal LogBlock(LogFile logFile, long startPosition, int bytesCount, long lineNumber) 80 /// <param name="lineEndType">行末の種類。</param> 81 internal LogBlock( 82 LogFile logFile, 83 long startPosition, 84 int bytesCount, 85 long lineNumber, 86 LineEndType lineEndType) 75 87 { 76 88 this.logFile = logFile; … … 80 92 81 93 lineCount = 1; 94 lastLineEndType = lineEndType; 82 95 } 83 96 … … 122 135 { 123 136 return lineCount; 137 } 138 } 139 140 /// <summary> 141 /// 最後の行の行末の種類を取得します。 142 /// </summary> 143 /// <value> 144 /// 最後の行の行末の種類。 145 /// </value> 146 internal LineEndType LastLineEndType 147 { 148 get 149 { 150 return lastLineEndType; 124 151 } 125 152 } … … 148 175 /// <param name="newLineBytesCount">データの長さを表すバイト数。</param> 149 176 /// <param name="newLineLineNumber">行番号。</param> 177 /// <param name="newLineEndType">行末の種類。</param> 150 178 /// <returns> 151 179 /// 追加先のログブロック。 152 180 /// このインスタンスが対象としているログファイルと異なる場合は新しいログブロックが作成されて返されます。 153 181 /// </returns> 154 internal LogBlock AppendLine(LogFile newLineLogFile, long newLineStartPosition, int newLineBytesCount, long newLineLineNumber) 182 internal LogBlock AppendLine( 183 LogFile newLineLogFile, 184 long newLineStartPosition, 185 int newLineBytesCount, 186 long newLineLineNumber, 187 LineEndType newLineEndType) 155 188 { 156 189 Debug.Assert(nextBlock == null, "nextBlock is not null."); … … 160 193 { 161 194 Debug.Assert(startPosition + bytesCount == newLineStartPosition, "Invalid start position."); 162 //Debug.Assert(lineNumber + lineCount == newLineLineNumber, "Invalid line number."); 163 // FIXME 195 Debug.Assert(lineNumber + lineCount + (lastLineEndType == LineEndType.None ? -1 : 0) == newLineLineNumber, "Invalid line number."); 164 196 165 197 bytesCount += newLineBytesCount; 166 lineCount++; 198 199 // 直前が改行で終わっている場合 200 if (lastLineEndType != LineEndType.None) 201 { 202 lineCount++; 203 } 204 205 lastLineEndType = newLineEndType; 167 206 return this; 168 207 } 169 208 170 209 // 新しいログファイルの場合 171 return nextBlock = new LogBlock(newLineLogFile, newLineStartPosition, newLineBytesCount, newLineLineNumber );210 return nextBlock = new LogBlock(newLineLogFile, newLineStartPosition, newLineBytesCount, newLineLineNumber, newLineEndType); 172 211 } 173 212 } -
TinyLogViewer/trunk/TinyLogViewer/Sources/Parser/LogEntryParser.cs
r1474 r1479 23 23 { 24 24 using System; 25 using System.Diagnostics; 25 26 using System.Text; 26 27 using System.Text.RegularExpressions; … … 48 49 49 50 /// <summary> 51 /// 改行が見付かるまで現在の行の値を持つ文字列ビルダー。 52 /// </summary> 53 private readonly StringBuilder currentLineBuilder; 54 55 /// <summary> 50 56 /// 行を処理するデリゲート。 51 57 /// </summary> 52 58 private readonly ProcessAction process; 53 59 60 61 /// <summary> 62 /// 改行が見付かるまで現在の行を保持するインスタンス。 63 /// </summary> 64 private LogLine currentLine; 54 65 55 66 /// <summary> … … 93 104 /// <param name="startEntryRegex">ログエントリーの開始を検出する正規表現。</param> 94 105 /// <param name="endEntryRegex">ログエントリーの終了を検出する正規表現。</param> 106 /// <param name="maxLineLength">処理対象とする 1 行の最大文字数。</param> 95 107 /// <param name="logEntryDetected">検出したログエントリーを通知するデリゲート。</param> 96 108 /// <exception cref="ArgumentNullException"> 97 109 /// <paramref name="logEntryDetected"/> は <see langword="null"/> です。 98 110 /// </exception> 99 public LogEntryParser(Regex startEntryRegex, Regex endEntryRegex, LogEntryDelegate logEntryDetected) 111 /// <exception cref="ArgumentOutOfRangeException"> 112 /// <paramref name="maxLineLength"/> が 16 未満です。 113 /// </exception> 114 public LogEntryParser( 115 Regex startEntryRegex, 116 Regex endEntryRegex, 117 int maxLineLength, 118 LogEntryDelegate logEntryDetected) 100 119 { 101 120 // 引数をチェック … … 103 122 { 104 123 throw new ArgumentNullException("logEntryDetected"); 124 } 125 126 if (maxLineLength < 16) 127 { 128 // FIXME メッセージ 129 throw new ArgumentOutOfRangeException(); 105 130 } 106 131 … … 108 133 this.endEntryRegex = endEntryRegex; 109 134 this.logEntryDetected = logEntryDetected; 135 136 currentLineBuilder = new StringBuilder(maxLineLength); 110 137 111 138 // 処理するためのデリゲートを準備 … … 142 169 /// <param name="bytesCount">データの長さを表すバイト数。</param> 143 170 /// <param name="lineNumber">行番号。</param> 144 /// <param name="value">行を表す文字列。</param> 145 private delegate void ProcessAction(LogFile logFile, long startPosition, int bytesCount, long lineNumber, string value); 171 /// <param name="lineEndType">行末の種類。</param> 172 /// <param name="value"> 173 /// 行を表す文字列。 174 /// 前の行の続きの場合は <see langword="null"/>。 175 /// </param> 176 private delegate void ProcessAction( 177 LogFile logFile, 178 long startPosition, 179 int bytesCount, 180 long lineNumber, 181 LineEndType lineEndType, 182 string value); 146 183 147 184 … … 157 194 /// <param name="charsIndex"><paramref name="chars"/> の開始位置。</param> 158 195 /// <param name="charsLength"><paramref name="chars"/> の <paramref name="charsIndex"/> からの有効な長さ。</param> 159 public void FeedLine(LogFile logFile, long startPosition, int bytesCount, long lineNumber, LineEndType lineEndType, char[] chars, int charsIndex, int charsLength) 160 { 196 public void FeedLine( 197 LogFile logFile, 198 long startPosition, 199 int bytesCount, 200 long lineNumber, 201 LineEndType lineEndType, 202 char[] chars, 203 int charsIndex, 204 int charsLength) 205 { 206 if (currentLine != null) 207 { 208 // ログファイルが同じで、または1行の長さが 2G 未満の場合は、末尾に追加 209 if (currentLine.LogFile == logFile 210 && currentLine.BytesCount + (long)bytesCount <= int.MaxValue) 211 { 212 Debug.Assert(currentLine.LineNumber == lineNumber, "Invalid line number."); 213 Debug.Assert(currentLine.StartPosition + currentLine.BytesCount == startPosition, "Invalid start position."); 214 215 // 末尾に追加 216 currentLine.Append(bytesCount, chars, charsIndex, charsLength); 217 218 // まだ行の途中の場合 219 if (lineEndType == LineEndType.None) 220 { 221 return; 222 } 223 224 // 改行で終わっている場合 225 ProcessCurrentLine(lineEndType); 226 return; 227 } 228 229 // 手前までを確定 230 ProcessCurrentLine(LineEndType.None); 231 } 232 233 // 新しい行が改行で終わっていない場合 234 if (lineEndType == LineEndType.None) 235 { 236 currentLine = new LogLine(logFile, startPosition, bytesCount, lineNumber, currentLineBuilder, chars, charsIndex, charsLength); 237 return; 238 } 239 240 // 行の続きの場合は null 241 string value 242 = firstLogBlock == null || lastLogBlock.LastLineEndType != LineEndType.None 243 ? new string(chars, charsIndex, charsLength) 244 : null; 245 161 246 process( 162 247 logFile, … … 164 249 bytesCount, 165 250 lineNumber, 166 new string(chars, charsIndex, charsLength)); 251 lineEndType, 252 value); 167 253 } 168 254 … … 183 269 /// <param name="bytesCount">データの長さを表すバイト数。</param> 184 270 /// <param name="lineNumber">行番号。</param> 185 /// <param name="value">行を表す文字列。</param> 186 private void ProcessSingleLine(LogFile logFile, long startPosition, int bytesCount, long lineNumber, string value) 187 { 188 logEntryDetected(new LogEntry(new LogBlock(logFile, startPosition, bytesCount, lineNumber), value)); 189 GC.KeepAlive(value); 271 /// <param name="lineEndType">行末の種類。</param> 272 /// <param name="value"> 273 /// 行を表す文字列。 274 /// 前の行の続きの場合は <see langword="null"/>。 275 /// </param> 276 private void ProcessSingleLine( 277 LogFile logFile, 278 long startPosition, 279 int bytesCount, 280 long lineNumber, 281 LineEndType lineEndType, 282 string value) 283 { 284 // 1 行で完結する場合 285 if (lineEndType != LineEndType.None && firstLogBlock == null) 286 { 287 Debug.Assert(value != null, "value is null."); 288 logEntryDetected(new LogEntry(new LogBlock(logFile, startPosition, bytesCount, lineNumber, lineEndType), value)); 289 GC.KeepAlive(value); 290 return; 291 } 292 293 // 行を追加 294 AppendLine(logFile, startPosition, bytesCount, lineNumber, lineEndType, value); 190 295 } 191 296 … … 197 302 /// <param name="bytesCount">データの長さを表すバイト数。</param> 198 303 /// <param name="lineNumber">行番号。</param> 199 /// <param name="value">行を表す文字列。</param> 200 private void ProcessStartDetection(LogFile logFile, long startPosition, int bytesCount, long lineNumber, string value) 304 /// <param name="lineEndType">行末の種類。</param> 305 /// <param name="value"> 306 /// 行を表す文字列。 307 /// 前の行の続きの場合は <see langword="null"/>。 308 /// </param> 309 private void ProcessStartDetection( 310 LogFile logFile, 311 long startPosition, 312 int bytesCount, 313 long lineNumber, 314 LineEndType lineEndType, 315 string value) 201 316 { 202 317 // ログエントリーの開始がある場合 203 if ( startEntryRegex!= null && startEntryRegex.IsMatch(value))318 if (value != null && startEntryRegex.IsMatch(value)) 204 319 { 205 320 CommitLogEntry(); … … 207 322 208 323 // 行を追加 209 AppendLine(logFile, startPosition, bytesCount, lineNumber, value);324 AppendLine(logFile, startPosition, bytesCount, lineNumber, lineEndType, value); 210 325 } 211 326 … … 217 332 /// <param name="bytesCount">データの長さを表すバイト数。</param> 218 333 /// <param name="lineNumber">行番号。</param> 219 /// <param name="value">行を表す文字列。</param> 220 private void ProcessEndDetection(LogFile logFile, long startPosition, int bytesCount, long lineNumber, string value) 334 /// <param name="lineEndType">行末の種類。</param> 335 /// <param name="value"> 336 /// 行を表す文字列。 337 /// 前の行の続きの場合は <see langword="null"/>。 338 /// </param> 339 private void ProcessEndDetection( 340 LogFile logFile, 341 long startPosition, 342 int bytesCount, 343 long lineNumber, 344 LineEndType lineEndType, 345 string value) 221 346 { 222 347 // 行を追加 223 AppendLine(logFile, startPosition, bytesCount, lineNumber, value);348 AppendLine(logFile, startPosition, bytesCount, lineNumber, lineEndType, value); 224 349 225 350 // ログエントリーの終了がある場合 226 if ( endEntryRegex.IsMatch(value))351 if (value != null && endEntryRegex.IsMatch(value)) 227 352 { 228 353 CommitLogEntry(); … … 237 362 /// <param name="bytesCount">データの長さを表すバイト数。</param> 238 363 /// <param name="lineNumber">行番号。</param> 239 /// <param name="value">行を表す文字列。</param> 240 private void ProcessStartAndEndDetection(LogFile logFile, long startPosition, int bytesCount, long lineNumber, string value) 364 /// <param name="lineEndType">行末の種類。</param> 365 /// <param name="value"> 366 /// 行を表す文字列。 367 /// 前の行の続きの場合は <see langword="null"/>。 368 /// </param> 369 private void ProcessStartAndEndDetection( 370 LogFile logFile, 371 long startPosition, 372 int bytesCount, 373 long lineNumber, 374 LineEndType lineEndType, 375 string value) 241 376 { 242 377 // ログエントリーの開始がある場合 243 if ( startEntryRegex!= null && startEntryRegex.IsMatch(value))378 if (value != null && startEntryRegex.IsMatch(value)) 244 379 { 245 380 CommitLogEntry(); … … 247 382 248 383 // 行を追加 249 AppendLine(logFile, startPosition, bytesCount, lineNumber, value);384 AppendLine(logFile, startPosition, bytesCount, lineNumber, lineEndType, value); 250 385 251 386 // ログエントリーの終了がある場合 252 if ( endEntryRegex.IsMatch(value))387 if (value != null && endEntryRegex.IsMatch(value)) 253 388 { 254 389 CommitLogEntry(); … … 257 392 258 393 /// <summary> 394 /// 現在の行を元に処理を行います。 395 /// </summary> 396 /// <param name="lineEndType">行末の種類。</param> 397 private void ProcessCurrentLine(LineEndType lineEndType) 398 { 399 currentLine.SetLineEnd(lineEndType); 400 401 process( 402 currentLine.LogFile, 403 currentLine.StartPosition, 404 currentLine.BytesCount, 405 currentLine.LineNumber, 406 lineEndType, 407 currentLine.ToString()); 408 409 currentLine = null; 410 currentLineBuilder.Length = 0; 411 } 412 413 /// <summary> 259 414 /// 行を追加します。 260 415 /// </summary> … … 263 418 /// <param name="bytesCount">データの長さを表すバイト数。</param> 264 419 /// <param name="lineNumber">行番号。</param> 265 /// <param name="value">行を表す文字列。</param> 266 private void AppendLine(LogFile logFile, long startPosition, int bytesCount, long lineNumber, string value) 420 /// <param name="lineEndType">行末の種類。</param> 421 /// <param name="value"> 422 /// 行を表す文字列。 423 /// 前の行の続きの場合は <see langword="null"/>。 424 /// </param> 425 private void AppendLine( 426 LogFile logFile, 427 long startPosition, 428 int bytesCount, 429 long lineNumber, 430 LineEndType lineEndType, 431 string value) 267 432 { 268 433 // ログエントリーが空の場合 269 434 if (firstLogBlock == null) 270 435 { 271 lastLogBlock = firstLogBlock = new LogBlock(logFile, startPosition, bytesCount, lineNumber); 436 Debug.Assert(value != null, "value is null."); 437 lastLogBlock = firstLogBlock = new LogBlock(logFile, startPosition, bytesCount, lineNumber, lineEndType); 272 438 logEntryFirstValue = value; 273 439 return; … … 277 443 if (logEntryValueBuilder == null) 278 444 { 279 logEntryValueBuilder = new StringBuilder((logEntryFirstValue.Length + value.Length) * 2);445 logEntryValueBuilder = new StringBuilder((logEntryFirstValue.Length + (value != null ? value.Length : 0)) * 2); 280 446 logEntryValueBuilder.Append(logEntryFirstValue); 281 447 logEntryFirstValue = null; 282 448 } 283 449 284 logEntryValueBuilder.Append(value); 450 if (value != null) 451 { 452 // 行の続きではない場合 453 logEntryValueBuilder.Append(value); 454 } 455 else 456 { 457 // 行の続きで行末記号がある場合 458 switch (lineEndType) 459 { 460 case LineEndType.CarriageReturn: 461 logEntryValueBuilder.Append('\r'); 462 break; 463 case LineEndType.LineFeed: 464 logEntryValueBuilder.Append('\n'); 465 break; 466 case LineEndType.CarriageReturnAndLineFeed: 467 logEntryValueBuilder.Append('\r'); 468 logEntryValueBuilder.Append('\n'); 469 break; 470 } 471 } 285 472 286 473 // 末尾に追加 287 lastLogBlock = lastLogBlock.AppendLine(logFile, startPosition, bytesCount, lineNumber );474 lastLogBlock = lastLogBlock.AppendLine(logFile, startPosition, bytesCount, lineNumber, lineEndType); 288 475 } 289 476 -
TinyLogViewer/trunk/TinyLogViewer/Sources/Parser/LogParser.cs
r1475 r1479 45 45 new Regex("^[^ ]+ [^:]+: [0-9]+ : ", RegexOptions.ExplicitCapture), 46 46 null, 47 1024 * 1024, 47 48 logEntryDetected); 48 49 } -
TinyLogViewer/trunk/TinyLogViewer/TinyLogViewer.csproj
r1476 r1479 88 88 <Compile Include="Sources\Logging.cs" /> 89 89 <Compile Include="Sources\LogBlock.cs" /> 90 <Compile Include="Sources\LogLine.cs" /> 90 91 <Compile Include="Sources\LogProfile.cs" /> 91 92 <Compile Include="Sources\LogProfileEventArgs.cs" /> -
TinyLogViewer/trunk/TinyLogViewerTest/Sources/Parser/LogEntryParserTest.cs
r1474 r1479 63 63 new Regex("^[^ ]+ [^:]+: [0-9]+ : ", RegexOptions.ExplicitCapture), 64 64 null, 65 1024, 65 66 delegate(LogEntry logEntry) 66 67 { … … 106 107 5, 107 108 @"FCosft.TinyLogViewer.Test Information: 103 : Message3. 109 XX yyy. 110 ProcessId=1001 111 ThreadId=2 112 DateTime=2020-01-23T10:20:32.1234567+09:00 113 "), 114 })); 115 } 116 117 /// <summary> 118 /// 長い行の有るログエントリーの開始を検出ルテストです。 119 /// </summary> 120 [Test] 121 public void TestStartDetectionWithLongLine() 122 { 123 List<LogEntryInfo> logEntryInfos = new List<LogEntryInfo>(); 124 LogEntryParser parser 125 = new LogEntryParser( 126 new Regex("^[^ ]+ [^:]+: [0-9]+ : ", RegexOptions.ExplicitCapture), 127 null, 128 60, 129 delegate(LogEntry logEntry) 130 { 131 logEntryInfos.Add(new LogEntryInfo(logEntry)); 132 }); 133 134 Execute( 135 parser, 136 @"FCosft.TinyLogViewer.Test Information: 101 : Message1. 137 ProcessId=1001 138 ThreadId=2 139 DateTime=2020-01-23T10:20:30.1234567+09:00 140 FCosft.TinyLogViewer.Test Information: 102 : Message2. 141 FCosft.TinyLogViewer.Test Information: 103 : 678901234567890FCosft.TinyLogViewer.Test Information: 103 : Message3. 142 XX yyy. 143 ProcessId=1001 144 ThreadId=2 145 DateTime=2020-01-23T10:20:32.1234567+09:00 146 ", 147 120); 148 149 Assert.That( 150 logEntryInfos, 151 Is.EqualTo(new[] 152 { 153 new LogEntryInfo( 154 DefulatLogFilePath, 155 1, 156 4, 157 @"FCosft.TinyLogViewer.Test Information: 101 : Message1. 158 ProcessId=1001 159 ThreadId=2 160 DateTime=2020-01-23T10:20:30.1234567+09:00 161 "), 162 new LogEntryInfo( 163 DefulatLogFilePath, 164 5, 165 1, 166 @"FCosft.TinyLogViewer.Test Information: 102 : Message2. 167 "), 168 new LogEntryInfo( 169 DefulatLogFilePath, 170 6, 171 5, 172 @"FCosft.TinyLogViewer.Test Information: 103 : 6789012345678 108 173 XX yyy. 109 174 ProcessId=1001 … … 152 217 } 153 218 219 /// <summary> 220 /// 文字列をパーサに供給します。 221 /// </summary> 222 /// <param name="parser">パーサ。</param> 223 /// <param name="text">文字列。</param> 224 /// <param name="bufferSize">バッファサイズ。</param> 225 private static void Execute(LogEntryParser parser, string text, int bufferSize) 226 { 227 LogFile logFile = new LogFile(DefulatLogFilePath, 0x1000, Encoding.Unicode, Encoding.Unicode, 0x1000); 228 229 TextDecoder decoder 230 = new TextDecoder( 231 bufferSize, 232 Encoding.Unicode, 233 delegate(long startPosition, int bytesCount, long lineNumber, LineEndType lineEndType, char[] chars, int charsIndex, int charsLength) 234 { 235 parser.FeedLine(logFile, startPosition, bytesCount, lineNumber, lineEndType, chars, charsIndex, charsLength); 236 }); 237 238 using (MemoryStream memoryStream = new MemoryStream(Encoding.Unicode.GetBytes(text), false)) 239 { 240 decoder.DecodeFrom(memoryStream); 241 } 242 243 parser.Flush(); 244 } 245 154 246 155 247 /// <summary>
※ 詳しい使い方は
TracChangeset を参照してください。