Lean  $LEAN_TAG$
FileLogHandler.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14 */
15 
16 using System;
17 using System.Globalization;
18 using System.IO;
19 
20 namespace QuantConnect.Logging
21 {
22  /// <summary>
23  /// Provides an implementation of <see cref="ILogHandler"/> that writes all log messages to a file on disk.
24  /// </summary>
25  public class FileLogHandler : ILogHandler
26  {
27  private bool _disposed;
28 
29  // we need to control synchronization to our stream writer since it's not inherently thread-safe
30  private readonly object _lock = new object();
31  private readonly Lazy<TextWriter> _writer;
32  private readonly bool _useTimestampPrefix;
33 
34  /// <summary>
35  /// Initializes a new instance of the <see cref="FileLogHandler"/> class to write messages to the specified file path.
36  /// The file will be opened using <see cref="FileMode.Append"/>
37  /// </summary>
38  /// <param name="filepath">The file path use to save the log messages</param>
39  /// <param name="useTimestampPrefix">True to prefix each line in the log which the UTC timestamp, false otherwise</param>
40  public FileLogHandler(string filepath, bool useTimestampPrefix = true)
41  {
42  _useTimestampPrefix = useTimestampPrefix;
43  _writer = new Lazy<TextWriter>(
44  () => new StreamWriter(File.Open(filepath, FileMode.Append, FileAccess.Write, FileShare.Read))
45  );
46  }
47 
48  /// <summary>
49  /// Initializes a new instance of the <see cref="FileLogHandler"/> class using 'log.txt' for the filepath.
50  /// </summary>
51  public FileLogHandler()
52  : this(Log.FilePath)
53  {
54  }
55 
56  /// <summary>
57  /// Write error message to log
58  /// </summary>
59  /// <param name="text">The error text to log</param>
60  public void Error(string text)
61  {
62  WriteMessage(text, "ERROR");
63  }
64 
65  /// <summary>
66  /// Write debug message to log
67  /// </summary>
68  /// <param name="text">The debug text to log</param>
69  public void Debug(string text)
70  {
71  WriteMessage(text, "DEBUG");
72  }
73 
74  /// <summary>
75  /// Write debug message to log
76  /// </summary>
77  /// <param name="text">The trace text to log</param>
78  public void Trace(string text)
79  {
80  WriteMessage(text, "TRACE");
81  }
82 
83  /// <summary>
84  /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
85  /// </summary>
86  /// <filterpriority>2</filterpriority>
87  public void Dispose()
88  {
89  lock (_lock)
90  {
91  if (_writer.IsValueCreated)
92  {
93  _disposed = true;
94  _writer.Value.Dispose();
95  }
96  }
97  }
98 
99  /// <summary>
100  /// Creates the message to be logged
101  /// </summary>
102  /// <param name="text">The text to be logged</param>
103  /// <param name="level">The logging leel</param>
104  /// <returns></returns>
105  protected virtual string CreateMessage(string text, string level)
106  {
107  if (_useTimestampPrefix)
108  {
109  return $"{DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture)} {level}:: {text}";
110  }
111  return $"{level}:: {text}";
112  }
113 
114  /// <summary>
115  /// Writes the message to the writer
116  /// </summary>
117  private void WriteMessage(string text, string level)
118  {
119  var message = CreateMessage(text, level);
120  lock (_lock)
121  {
122  if (_disposed) return;
123  _writer.Value.WriteLine(message);
124  _writer.Value.Flush();
125  }
126  }
127  }
128 }