Lean  $LEAN_TAG$
Log.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.Collections;
18 using System.Globalization;
19 using System.Runtime.CompilerServices;
20 using System.Text;
21 
22 namespace QuantConnect.Logging
23 {
24  /// <summary>
25  /// Logging management class.
26  /// </summary>
27  public static class Log
28  {
29  private static string _lastTraceText = "";
30  private static string _lastErrorText = "";
31  private static bool _debuggingEnabled;
32  private static int _level = 1;
33  private static ILogHandler _logHandler = new ConsoleLogHandler();
34 
35  /// <summary>
36  /// Gets or sets the ILogHandler instance used as the global logging implementation.
37  /// </summary>
38  public static ILogHandler LogHandler
39  {
40  get { return _logHandler; }
41  set { _logHandler = value; }
42  }
43 
44  /// <summary>
45  /// Global flag whether to enable debugging logging:
46  /// </summary>
47  public static bool DebuggingEnabled
48  {
49  get { return _debuggingEnabled; }
50  set { _debuggingEnabled = value; }
51  }
52 
53  /// <summary>
54  /// Global flag to specify file based log path
55  /// </summary>
56  /// <remarks>Only valid for file based loggers</remarks>
57  public static string FilePath { get; set; } = "log.txt";
58 
59  /// <summary>
60  /// Set the minimum message level:
61  /// </summary>
62  public static int DebuggingLevel
63  {
64  get { return _level; }
65  set { _level = value; }
66  }
67 
68  /// <summary>
69  /// Log error
70  /// </summary>
71  /// <param name="error">String Error</param>
72  /// <param name="overrideMessageFloodProtection">Force sending a message, overriding the "do not flood" directive</param>
73  public static void Error(string error, bool overrideMessageFloodProtection = false)
74  {
75  try
76  {
77  if (error == _lastErrorText && !overrideMessageFloodProtection) return;
78  _logHandler.Error(error);
79  _lastErrorText = error; //Stop message flooding filling diskspace.
80  }
81  catch (Exception err)
82  {
83  Console.WriteLine("Log.Error(): Error writing error: " + err.Message);
84  }
85  }
86 
87  /// <summary>
88  /// Log error. This overload is usefull when exceptions are being thrown from within an anonymous function.
89  /// </summary>
90  /// <param name="method">The method identifier to be used</param>
91  /// <param name="exception">The exception to be logged</param>
92  /// <param name="message">An optional message to be logged, if null/whitespace the messge text will be extracted</param>
93  /// <param name="overrideMessageFloodProtection">Force sending a message, overriding the "do not flood" directive</param>
94  private static void Error(string method, Exception exception, string message = null, bool overrideMessageFloodProtection = false)
95  {
96  message = method + "(): " + (message ?? string.Empty) + " " + exception;
97  Error(message, overrideMessageFloodProtection);
98  }
99 
100  /// <summary>
101  /// Log error
102  /// </summary>
103  /// <param name="exception">The exception to be logged</param>
104  /// <param name="message">An optional message to be logged, if null/whitespace the messge text will be extracted</param>
105  /// <param name="overrideMessageFloodProtection">Force sending a message, overriding the "do not flood" directive</param>
106  [MethodImpl(MethodImplOptions.NoInlining)]
107  public static void Error(Exception exception, string message = null, bool overrideMessageFloodProtection = false)
108  {
109  Error(WhoCalledMe.GetMethodName(1), exception, message, overrideMessageFloodProtection);
110  }
111 
112  /// <summary>
113  /// Log trace
114  /// </summary>
115  public static void Trace(string traceText, bool overrideMessageFloodProtection = false)
116  {
117  try
118  {
119  if (traceText == _lastTraceText && !overrideMessageFloodProtection) return;
120  _logHandler.Trace(traceText);
121  _lastTraceText = traceText;
122  }
123  catch (Exception err)
124  {
125  Console.WriteLine("Log.Trace(): Error writing trace: " +err.Message);
126  }
127  }
128 
129  /// <summary>
130  /// Writes the message in normal text
131  /// </summary>
132  public static void Trace(string format, params object[] args)
133  {
134  Trace(string.Format(CultureInfo.InvariantCulture, format, args));
135  }
136 
137  /// <summary>
138  /// Writes the message in red
139  /// </summary>
140  public static void Error(string format, params object[] args)
141  {
142  Error(string.Format(CultureInfo.InvariantCulture, format, args));
143  }
144 
145  /// <summary>
146  /// Output to the console
147  /// </summary>
148  /// <param name="text">The message to show</param>
149  /// <param name="level">debug level</param>
150  public static void Debug(string text, int level = 1)
151  {
152  try
153  {
154  if (!_debuggingEnabled || level < _level) return;
155  _logHandler.Debug(text);
156  }
157  catch (Exception err)
158  {
159  Console.WriteLine("Log.Debug(): Error writing debug: " + err.Message);
160  }
161  }
162 
163  /// <summary>
164  /// C# Equivalent of Print_r in PHP:
165  /// </summary>
166  /// <param name="obj"></param>
167  /// <param name="recursion"></param>
168  /// <returns></returns>
169  public static string VarDump(object obj, int recursion = 0)
170  {
171  var result = new StringBuilder();
172 
173  // Protect the method against endless recursion
174  if (recursion < 5)
175  {
176  // Determine object type
177  var t = obj.GetType();
178 
179  // Get array with properties for this object
180  var properties = t.GetProperties();
181 
182  foreach (var property in properties)
183  {
184  try
185  {
186  // Get the property value
187  var value = property.GetValue(obj, null);
188 
189  // Create indenting string to put in front of properties of a deeper level
190  // We'll need this when we display the property name and value
191  var indent = String.Empty;
192  var spaces = "| ";
193  var trail = "|...";
194 
195  if (recursion > 0)
196  {
197  indent = new StringBuilder(trail).Insert(0, spaces, recursion - 1).ToString();
198  }
199 
200  if (value != null)
201  {
202  // If the value is a string, add quotation marks
203  var displayValue = value.ToString();
204  if (value is string) displayValue = String.Concat('"', displayValue, '"');
205 
206  // Add property name and value to return string
207  result.AppendFormat(CultureInfo.InvariantCulture, "{0}{1} = {2}\n", indent, property.Name, displayValue);
208 
209  try
210  {
211  if (!(value is ICollection))
212  {
213  // Call var_dump() again to list child properties
214  // This throws an exception if the current property value
215  // is of an unsupported type (eg. it has not properties)
216  result.Append(VarDump(value, recursion + 1));
217  }
218  else
219  {
220  // 2009-07-29: added support for collections
221  // The value is a collection (eg. it's an arraylist or generic list)
222  // so loop through its elements and dump their properties
223  var elementCount = 0;
224  foreach (var element in ((ICollection)value))
225  {
226  var elementName = $"{property.Name}[{elementCount}]";
227  indent = new StringBuilder(trail).Insert(0, spaces, recursion).ToString();
228 
229  // Display the collection element name and type
230  result.AppendFormat(CultureInfo.InvariantCulture, "{0}{1} = {2}\n", indent, elementName, element.ToString());
231 
232  // Display the child properties
233  result.Append(VarDump(element, recursion + 2));
234  elementCount++;
235  }
236 
237  result.Append(VarDump(value, recursion + 1));
238  }
239  } catch { }
240  }
241  else
242  {
243  // Add empty (null) property to return string
244  result.AppendFormat(CultureInfo.InvariantCulture, "{0}{1} = {2}\n", indent, property.Name, "null");
245  }
246  }
247  catch
248  {
249  // Some properties will throw an exception on property.GetValue()
250  // I don't know exactly why this happens, so for now i will ignore them...
251  }
252  }
253  }
254 
255  return result.ToString();
256  }
257  }
258 }