chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:02:50 +08:00
commit 0fc60fdcb1
5008 changed files with 910633 additions and 0 deletions
+109
View File
@@ -0,0 +1,109 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace QuantConnect.Logging
{
/// <summary>
/// Provides an <see cref="ILogHandler"/> implementation that composes multiple handlers
/// </summary>
public class CompositeLogHandler : ILogHandler
{
private readonly ILogHandler[] _handlers;
/// <summary>
/// Initializes a new instance of the <see cref="CompositeLogHandler"/> that pipes log messages to the console and log.txt
/// </summary>
public CompositeLogHandler()
: this(new ConsoleLogHandler(), new FileLogHandler())
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CompositeLogHandler"/> class from the specified handlers
/// </summary>
/// <param name="handlers">The implementations to compose</param>
public CompositeLogHandler(params ILogHandler[] handlers)
{
if (handlers == null || handlers.Length == 0)
{
throw new ArgumentNullException(nameof(handlers));
}
_handlers = handlers;
}
/// <summary>
/// Write error message to log
/// </summary>
/// <param name="text"></param>
public void Error(string text)
{
foreach (var handler in _handlers)
{
handler.Error(text);
}
}
/// <summary>
/// Write debug message to log
/// </summary>
/// <param name="text"></param>
public void Debug(string text)
{
foreach (var handler in _handlers)
{
handler.Debug(text);
}
}
/// <summary>
/// Write debug message to log
/// </summary>
/// <param name="text"></param>
public void Trace(string text)
{
foreach (var handler in _handlers)
{
handler.Trace(text);
}
}
/// <summary>
/// Write report message to log
/// </summary>
/// <param name="text">The report text to log</param>
public void Report(string text)
{
foreach (var handler in _handlers)
{
handler.Report(text);
}
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <filterpriority>2</filterpriority>
public void Dispose()
{
foreach (var handler in _handlers)
{
handler.Dispose();
}
}
}
}
+47
View File
@@ -0,0 +1,47 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace QuantConnect.Logging
{
/// <summary>
/// Subclass of ConsoleLogHandler that only logs error messages
/// </summary>
public class ConsoleErrorLogHandler : ConsoleLogHandler
{
/// <summary>
/// Hide debug messages from log
/// </summary>
/// <param name="text">The debug text to log</param>
public override void Debug(string text)
{
}
/// <summary>
/// Hide trace messages from log
/// </summary>
/// <param name="text">The trace text to log</param>
public override void Trace(string text)
{
}
/// <summary>
/// Write report message to log
/// </summary>
/// <param name="text">The report text to log</param>
public override void Report(string text)
{
}
}
}
+103
View File
@@ -0,0 +1,103 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Globalization;
using System.IO;
namespace QuantConnect.Logging
{
/// <summary>
/// ILogHandler implementation that writes log output to console.
/// </summary>
public class ConsoleLogHandler : ILogHandler
{
private const string DefaultDateFormat = "yyyyMMdd HH:mm:ss.fff";
private readonly TextWriter _trace;
private readonly TextWriter _error;
private readonly string _dateFormat;
/// <summary>
/// Initializes a new instance of the <see cref="QuantConnect.Logging.ConsoleLogHandler"/> class.
/// </summary>
public ConsoleLogHandler()
: this(DefaultDateFormat)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="QuantConnect.Logging.ConsoleLogHandler"/> class.
/// </summary>
/// <param name="dateFormat">Specifies the date format to use when writing log messages to the console window</param>
public ConsoleLogHandler(string dateFormat = DefaultDateFormat)
{
// saves references to the real console text writer since in a deployed state we may overwrite this in order
// to redirect messages from algorithm to result handler
_trace = Console.Out;
_error = Console.Error;
_dateFormat = dateFormat;
}
/// <summary>
/// Write error message to log
/// </summary>
/// <param name="text">The error text to log</param>
public virtual void Error(string text)
{
#if DEBUG
Console.ForegroundColor = ConsoleColor.Red;
#endif
_error.WriteLine($"{DateTime.UtcNow.ToString(_dateFormat, CultureInfo.InvariantCulture)} ERROR:: {text}");
#if DEBUG
Console.ResetColor();
#endif
}
/// <summary>
/// Write debug message to log
/// </summary>
/// <param name="text">The debug text to log</param>
public virtual void Debug(string text)
{
_trace.WriteLine($"{DateTime.UtcNow.ToString(_dateFormat, CultureInfo.InvariantCulture)} DEBUG:: {text}");
}
/// <summary>
/// Write debug message to log
/// </summary>
/// <param name="text">The trace text to log</param>
public virtual void Trace(string text)
{
_trace.WriteLine($"{DateTime.UtcNow.ToString(_dateFormat, CultureInfo.InvariantCulture)} TRACE:: {text}");
}
/// <summary>
/// Write report message to log
/// </summary>
/// <param name="text">The report text to log</param>
public virtual void Report(string text)
{
_trace.WriteLine($"{DateTime.UtcNow.ToString(_dateFormat, CultureInfo.InvariantCulture)} REPORT:: {text}");
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <filterpriority>2</filterpriority>
public void Dispose()
{
}
}
}
+137
View File
@@ -0,0 +1,137 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Globalization;
using System.IO;
namespace QuantConnect.Logging
{
/// <summary>
/// Provides an implementation of <see cref="ILogHandler"/> that writes all log messages to a file on disk.
/// </summary>
public class FileLogHandler : ILogHandler
{
private bool _disposed;
// we need to control synchronization to our stream writer since it's not inherently thread-safe
private readonly object _lock = new object();
private readonly Lazy<TextWriter> _writer;
private readonly bool _useTimestampPrefix;
/// <summary>
/// Initializes a new instance of the <see cref="FileLogHandler"/> class to write messages to the specified file path.
/// The file will be opened using <see cref="FileMode.Append"/>
/// </summary>
/// <param name="filepath">The file path use to save the log messages</param>
/// <param name="useTimestampPrefix">True to prefix each line in the log which the UTC timestamp, false otherwise</param>
public FileLogHandler(string filepath, bool useTimestampPrefix = true)
{
_useTimestampPrefix = useTimestampPrefix;
_writer = new Lazy<TextWriter>(
() => new StreamWriter(File.Open(filepath, FileMode.Append, FileAccess.Write, FileShare.Read))
);
}
/// <summary>
/// Initializes a new instance of the <see cref="FileLogHandler"/> class using 'log.txt' for the filepath.
/// </summary>
public FileLogHandler()
: this(Log.FilePath)
{
}
/// <summary>
/// Write error message to log
/// </summary>
/// <param name="text">The error text to log</param>
public void Error(string text)
{
WriteMessage(text, "ERROR");
}
/// <summary>
/// Write debug message to log
/// </summary>
/// <param name="text">The debug text to log</param>
public void Debug(string text)
{
WriteMessage(text, "DEBUG");
}
/// <summary>
/// Write debug message to log
/// </summary>
/// <param name="text">The trace text to log</param>
public void Trace(string text)
{
WriteMessage(text, "TRACE");
}
/// <summary>
/// Write report message to log
/// </summary>
/// <param name="text">The report text to log</param>
public void Report(string text)
{
WriteMessage(text, "REPORT");
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <filterpriority>2</filterpriority>
public void Dispose()
{
lock (_lock)
{
if (_writer.IsValueCreated)
{
_disposed = true;
_writer.Value.Dispose();
}
}
}
/// <summary>
/// Creates the message to be logged
/// </summary>
/// <param name="text">The text to be logged</param>
/// <param name="level">The logging leel</param>
/// <returns></returns>
protected virtual string CreateMessage(string text, string level)
{
if (_useTimestampPrefix)
{
return $"{DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture)} {level}:: {text}";
}
return $"{level}:: {text}";
}
/// <summary>
/// Writes the message to the writer
/// </summary>
private void WriteMessage(string text, string level)
{
var message = CreateMessage(text, level);
lock (_lock)
{
if (_disposed) return;
_writer.Value.WriteLine(message);
_writer.Value.Flush();
}
}
}
}
+119
View File
@@ -0,0 +1,119 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.ComponentModel.Composition;
using System.Globalization;
namespace QuantConnect.Logging
{
/// <summary>
/// ILogHandler implementation that writes log output to result handler
/// </summary>
[PartNotDiscoverable]
public class FunctionalLogHandler : ILogHandler
{
private const string DateFormat = "yyyyMMdd HH:mm:ss";
private readonly Action<string> _debug;
private readonly Action<string> _trace;
private readonly Action<string> _error;
private readonly Action<string> _report;
/// <summary>
/// Default constructor to handle MEF.
/// </summary>
public FunctionalLogHandler()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="QuantConnect.Logging.FunctionalLogHandler"/> class.
/// </summary>
public FunctionalLogHandler(Action<string> debug, Action<string> trace, Action<string> error)
{
// saves references to the real console text writer since in a deployed state we may overwrite this in order
// to redirect messages from algorithm to result handler
_debug = debug;
_trace = trace;
_error = error;
}
/// <summary>
/// Initializes a new instance of the <see cref="QuantConnect.Logging.FunctionalLogHandler"/> class.
/// </summary>
public FunctionalLogHandler(Action<string> debug, Action<string> trace, Action<string> error, Action<string> report)
: this(debug, trace, error)
{
_report = report;
}
/// <summary>
/// Write error message to log
/// </summary>
/// <param name="text">The error text to log</param>
public void Error(string text)
{
if (_error != null)
{
_error(DateTime.Now.ToString(DateFormat, CultureInfo.InvariantCulture) + " ERROR " + text);
}
}
/// <summary>
/// Write debug message to log
/// </summary>
/// <param name="text">The debug text to log</param>
public void Debug(string text)
{
if (_debug != null)
{
_debug(DateTime.Now.ToString(DateFormat, CultureInfo.InvariantCulture) + " DEBUG " + text);
}
}
/// <summary>
/// Write debug message to log
/// </summary>
/// <param name="text">The trace text to log</param>
public void Trace(string text)
{
if (_trace != null)
{
_trace(DateTime.Now.ToString(DateFormat, CultureInfo.InvariantCulture) + " TRACE " + text);
}
}
/// <summary>
/// Write report message to log
/// </summary>
/// <param name="text">The report text to log</param>
public void Report(string text)
{
if (_report != null)
{
_report(DateTime.Now.ToString(DateFormat, CultureInfo.InvariantCulture) + " REPORT " + text);
}
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <filterpriority>2</filterpriority>
public void Dispose()
{
}
}
}
+51
View File
@@ -0,0 +1,51 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.ComponentModel.Composition;
namespace QuantConnect.Logging
{
/// <summary>
/// Interface for redirecting log output
/// </summary>
[InheritedExport(typeof(ILogHandler))]
public interface ILogHandler : IDisposable
{
/// <summary>
/// Write error message to log
/// </summary>
/// <param name="text">The error text to log</param>
void Error(string text);
/// <summary>
/// Write debug message to log
/// </summary>
/// <param name="text">The debug text to log</param>
void Debug(string text);
/// <summary>
/// Write debug message to log
/// </summary>
/// <param name="text">The trace text to log</param>
void Trace(string text);
/// <summary>
/// Write report message to log
/// </summary>
/// <param name="text">The report text to log</param>
void Report(string text);
}
}
+74
View File
@@ -0,0 +1,74 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Globalization;
namespace QuantConnect.Logging
{
/// <summary>
/// Logging extensions.
/// </summary>
public static class LogHandlerExtensions
{
/// <summary>
/// Write error message to log
/// </summary>
/// <param name="logHandler"></param>
/// <param name="text">Message</param>
/// <param name="args">Arguments to format.</param>
public static void Error(this ILogHandler logHandler, string text, params object[] args)
{
if (logHandler == null)
{
throw new ArgumentNullException(nameof(logHandler), "Log Handler cannot be null");
}
logHandler.Error(string.Format(CultureInfo.InvariantCulture, text, args));
}
/// <summary>
/// Write debug message to log
/// </summary>
/// <param name="logHandler"></param>
/// <param name="text">Message</param>
/// <param name="args">Arguments to format.</param>
public static void Debug(this ILogHandler logHandler, string text, params object[] args)
{
if (logHandler == null)
{
throw new ArgumentNullException(nameof(logHandler), "Log Handler cannot be null");
}
logHandler.Debug(string.Format(CultureInfo.InvariantCulture, text, args));
}
/// <summary>
/// Write debug message to log
/// </summary>
/// <param name="logHandler"></param>
/// <param name="text">Message</param>
/// <param name="args">Arguments to format.</param>
public static void Trace(this ILogHandler logHandler, string text, params object[] args)
{
if (logHandler == null)
{
throw new ArgumentNullException(nameof(logHandler), "Log Handler cannot be null");
}
logHandler.Trace(string.Format(CultureInfo.InvariantCulture, text, args));
}
}
}
+327
View File
@@ -0,0 +1,327 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Buffers;
using System.Collections;
using System.Globalization;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
namespace QuantConnect.Logging
{
/// <summary>
/// Logging management class.
/// </summary>
public static class Log
{
private static readonly SearchValues<char> ReportCsvEscapedChars = SearchValues.Create("\",");
private static readonly Regex LeanPathRegex = new Regex("(?:\\S*?\\\\pythonnet\\\\)|(?:\\S*?\\\\Lean\\\\)|(?:\\S*?/Lean/)|(?:\\S*?/pythonnet/)", RegexOptions.Compiled);
private static string _lastTraceText = "";
private static string _lastErrorText = "";
private static bool _debuggingEnabled;
private static int _level = 1;
private static ILogHandler _logHandler = new ConsoleLogHandler();
/// <summary>
/// Gets the job user id
/// </summary>
public static int UserId { get; private set; }
/// <summary>
/// Gets the ob project id
/// </summary>
public static int ProjectId { get; private set; }
/// <summary>
/// Gets the job id (algorithm, live or optimization id)
/// </summary>
public static string JobId { get; private set; }
/// <summary>
/// Gets or sets the ILogHandler instance used as the global logging implementation.
/// </summary>
public static ILogHandler LogHandler
{
get { return _logHandler; }
set { _logHandler = value; }
}
/// <summary>
/// Global flag whether to enable debugging logging:
/// </summary>
public static bool DebuggingEnabled
{
get { return _debuggingEnabled; }
set { _debuggingEnabled = value; }
}
/// <summary>
/// Global flag to specify file based log path
/// </summary>
/// <remarks>Only valid for file based loggers</remarks>
public static string FilePath { get; set; } = "log.txt";
/// <summary>
/// Set the minimum message level:
/// </summary>
public static int DebuggingLevel
{
get { return _level; }
set { _level = value; }
}
/// <summary>
/// Initialized the Log class
/// </summary>
public static void Initialize(int userId, int projectId, string jobId)
{
UserId = userId;
ProjectId = projectId;
JobId = jobId;
}
/// <summary>
/// Log error
/// </summary>
/// <param name="error">String Error</param>
/// <param name="overrideMessageFloodProtection">Force sending a message, overriding the "do not flood" directive</param>
public static void Error(string error, bool overrideMessageFloodProtection = false)
{
try
{
if (error == _lastErrorText && !overrideMessageFloodProtection) return;
_logHandler.Error(error);
_lastErrorText = error; //Stop message flooding filling diskspace.
}
catch (Exception err)
{
Console.WriteLine("Log.Error(): Error writing error: " + err.Message);
}
}
/// <summary>
/// Log error. This overload is usefull when exceptions are being thrown from within an anonymous function.
/// </summary>
/// <param name="method">The method identifier to be used</param>
/// <param name="exception">The exception to be logged</param>
/// <param name="message">An optional message to be logged, if null/whitespace the messge text will be extracted</param>
/// <param name="overrideMessageFloodProtection">Force sending a message, overriding the "do not flood" directive</param>
private static void Error(string method, Exception exception, string message = null, bool overrideMessageFloodProtection = false)
{
message = method + "(): " + (message ?? string.Empty) + " " + ClearLeanPaths(exception?.ToString());
Error(message, overrideMessageFloodProtection);
}
/// <summary>
/// Log error
/// </summary>
/// <param name="exception">The exception to be logged</param>
/// <param name="message">An optional message to be logged, if null/whitespace the messge text will be extracted</param>
/// <param name="overrideMessageFloodProtection">Force sending a message, overriding the "do not flood" directive</param>
[MethodImpl(MethodImplOptions.NoInlining)]
public static void Error(Exception exception, string message = null, bool overrideMessageFloodProtection = false)
{
Error(WhoCalledMe.GetMethodName(1), exception, message, overrideMessageFloodProtection);
}
/// <summary>
/// Log trace
/// </summary>
public static void Trace(string traceText, bool overrideMessageFloodProtection = false)
{
try
{
if (traceText == _lastTraceText && !overrideMessageFloodProtection) return;
_logHandler.Trace(traceText);
_lastTraceText = traceText;
}
catch (Exception err)
{
Console.WriteLine("Log.Trace(): Error writing trace: " +err.Message);
}
}
/// <summary>
/// Writes the message in normal text
/// </summary>
public static void Trace(string format, params object[] args)
{
Trace(string.Format(CultureInfo.InvariantCulture, format, args));
}
/// <summary>
/// Writes the message in red
/// </summary>
public static void Error(string format, params object[] args)
{
Error(string.Format(CultureInfo.InvariantCulture, format, args));
}
/// <summary>
/// Output to the console
/// </summary>
/// <param name="text">The message to show</param>
/// <param name="level">debug level</param>
public static void Debug(string text, int level = 1)
{
try
{
if (!_debuggingEnabled || level < _level) return;
_logHandler.Debug(text);
}
catch (Exception err)
{
Console.WriteLine("Log.Debug(): Error writing debug: " + err.Message);
}
}
/// <summary>
/// Output report log to the console
/// </summary>
/// <param name="text">The message to write</param>
public static void Report(string text)
{
try
{
_logHandler.Report(text);
}
catch (Exception err)
{
Console.WriteLine("Log.Report(): Error writing report: " + err.Message);
}
}
/// <summary>
/// Output report log to the console
/// </summary>
/// <param name="args">Values to write as csv line</param>
public static void Report(params object[] args)
{
Report($"{UserId},{ProjectId},{JobId},{string.Join(",", args.Select(x => x is string s && s.IndexOfAny(ReportCsvEscapedChars) >= 0 ? $"\"{s}\"" : x))}");
}
/// <summary>
/// C# Equivalent of Print_r in PHP:
/// </summary>
/// <param name="obj"></param>
/// <param name="recursion"></param>
/// <returns></returns>
public static string VarDump(object obj, int recursion = 0)
{
var result = new StringBuilder();
// Protect the method against endless recursion
if (recursion < 5)
{
// Determine object type
var t = obj.GetType();
// Get array with properties for this object
var properties = t.GetProperties();
foreach (var property in properties)
{
try
{
// Get the property value
var value = property.GetValue(obj, null);
// Create indenting string to put in front of properties of a deeper level
// We'll need this when we display the property name and value
var indent = String.Empty;
var spaces = "| ";
var trail = "|...";
if (recursion > 0)
{
indent = new StringBuilder(trail).Insert(0, spaces, recursion - 1).ToString();
}
if (value != null)
{
// If the value is a string, add quotation marks
var displayValue = value.ToString();
if (value is string) displayValue = String.Concat('"', displayValue, '"');
// Add property name and value to return string
result.AppendFormat(CultureInfo.InvariantCulture, "{0}{1} = {2}\n", indent, property.Name, displayValue);
try
{
if (!(value is ICollection))
{
// Call var_dump() again to list child properties
// This throws an exception if the current property value
// is of an unsupported type (eg. it has not properties)
result.Append(VarDump(value, recursion + 1));
}
else
{
// 2009-07-29: added support for collections
// The value is a collection (eg. it's an arraylist or generic list)
// so loop through its elements and dump their properties
var elementCount = 0;
foreach (var element in ((ICollection)value))
{
var elementName = $"{property.Name}[{elementCount}]";
indent = new StringBuilder(trail).Insert(0, spaces, recursion).ToString();
// Display the collection element name and type
result.AppendFormat(CultureInfo.InvariantCulture, "{0}{1} = {2}\n", indent, elementName, element.ToString());
// Display the child properties
result.Append(VarDump(element, recursion + 2));
elementCount++;
}
result.Append(VarDump(value, recursion + 1));
}
} catch { }
}
else
{
// Add empty (null) property to return string
result.AppendFormat(CultureInfo.InvariantCulture, "{0}{1} = {2}\n", indent, property.Name, "null");
}
}
catch
{
// Some properties will throw an exception on property.GetValue()
// I don't know exactly why this happens, so for now i will ignore them...
}
}
}
return result.ToString();
}
/// <summary>
/// Helper method to clear undesired paths from stack traces
/// </summary>
/// <param name="error">The error to cleanup</param>
/// <returns>The sanitized error</returns>
public static string ClearLeanPaths(string error)
{
if (string.IsNullOrEmpty(error))
{
return error;
}
return LeanPathRegex.Replace(error, string.Empty);
}
}
}
+75
View File
@@ -0,0 +1,75 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using System.Globalization;
namespace QuantConnect.Logging
{
/// <summary>
/// Log entry wrapper to make logging simpler:
/// </summary>
public class LogEntry
{
/// <summary>
/// Time of the log entry
/// </summary>
public DateTime Time { get; set; }
/// <summary>
/// Message of the log entry
/// </summary>
public string Message { get; set; }
/// <summary>
/// Descriptor of the message type.
/// </summary>
public LogType MessageType { get; set; }
/// <summary>
/// Create a default log message with the current time.
/// </summary>
/// <param name="message"></param>
public LogEntry(string message)
{
Time = DateTime.UtcNow;
Message = message;
MessageType = LogType.Trace;
}
/// <summary>
/// Create a log entry at a specific time in the analysis (for a backtest).
/// </summary>
/// <param name="message">Message for log</param>
/// <param name="time">Utc time of the message</param>
/// <param name="type">Type of the log entry</param>
public LogEntry(string message, DateTime time, LogType type = LogType.Trace)
{
Time = time;
Message = message;
MessageType = type;
}
/// <summary>
/// Helper override on the log entry.
/// </summary>
/// <returns></returns>
public override string ToString()
{
return $"{Time.ToString("o", CultureInfo.InvariantCulture)} {MessageType} {Message}";
}
}
}
+41
View File
@@ -0,0 +1,41 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace QuantConnect.Logging
{
/// <summary>
/// Error level
/// </summary>
public enum LogType
{
/// <summary>
/// Debug log level
/// </summary>
Debug,
/// <summary>
/// Trace log level
/// </summary>
Trace,
/// <summary>
/// Error log level
/// </summary>
Error,
/// <summary>
/// Report log level
/// </summary>
Report
}
}
+17
View File
@@ -0,0 +1,17 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("QuantConnect.Logging")]
[assembly: AssemblyProduct("QuantConnect.Logging")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("687f62a5-f512-459a-9d66-64815d62a790")]
+48
View File
@@ -0,0 +1,48 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Logging</RootNamespace>
<AssemblyName>QuantConnect.Logging</AssemblyName>
<TargetFramework>net10.0</TargetFramework>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>
<DocumentationFile>bin\$(Configuration)\QuantConnect.Logging.xml</DocumentationFile>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<Description>QuantConnect LEAN Engine: Logging Project - The logging library implementation</Description>
<NoWarn>CA1062</NoWarn>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugType>full</DebugType>
<Optimize>$(SelectedOptimization)</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' AND '$(SelectedOptimization)' == ''">
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<Target Name="Print" BeforeTargets="Build">
<Message Text="SelectedOptimization $(SelectedOptimization)" Importance="high" />
</Target>
<ItemGroup>
<PackageReference Include="System.ComponentModel.Composition" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="..\LICENSE">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>
</Project>
+136
View File
@@ -0,0 +1,136 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Concurrent;
using System.Globalization;
using System.IO;
namespace QuantConnect.Logging
{
/// <summary>
/// ILogHandler implementation that queues all logs and writes them when instructed.
/// </summary>
public class QueueLogHandler : ILogHandler
{
private readonly ConcurrentQueue<LogEntry> _logs;
private const string DateFormat = "yyyyMMdd HH:mm:ss";
private readonly TextWriter _trace;
private readonly TextWriter _error;
/// <summary>
/// Public access to the queue for log processing.
/// </summary>
public ConcurrentQueue<LogEntry> Logs
{
get { return _logs; }
}
/// <summary>
/// LOgging event delegate
/// </summary>
public delegate void LogEventRaised(LogEntry log);
/// <summary>
/// Logging Event Handler
/// </summary>
public event LogEventRaised LogEvent;
/// <summary>
/// Initializes a new instance of the <see cref="QueueLogHandler"/> class.
/// </summary>
public QueueLogHandler()
{
_logs = new ConcurrentQueue<LogEntry>();
_trace = Console.Out;
_error = Console.Error;
}
/// <summary>
/// Write error message to log
/// </summary>
/// <param name="text">The error text to log</param>
public void Error(string text)
{
var log = new LogEntry(text, DateTime.UtcNow, LogType.Error);
_logs.Enqueue(log);
OnLogEvent(log);
Console.ForegroundColor = ConsoleColor.Red;
_error.WriteLine(DateTime.Now.ToString(DateFormat, CultureInfo.InvariantCulture) + " Error:: " + text);
Console.ResetColor();
}
/// <summary>
/// Write debug message to log
/// </summary>
/// <param name="text">The debug text to log</param>
public void Debug(string text)
{
var log = new LogEntry(text, DateTime.UtcNow, LogType.Debug);
_logs.Enqueue(log);
OnLogEvent(log);
_trace.WriteLine(DateTime.Now.ToString(DateFormat, CultureInfo.InvariantCulture) + " Debug:: " + text);
}
/// <summary>
/// Write debug message to log
/// </summary>
/// <param name="text">The trace text to log</param>
public void Trace(string text)
{
var log = new LogEntry(text, DateTime.UtcNow, LogType.Trace);
_logs.Enqueue(log);
OnLogEvent(log);
_trace.WriteLine(DateTime.Now.ToString(DateFormat, CultureInfo.InvariantCulture) + " Trace:: " + text);
}
/// <summary>
/// Write report message to log
/// </summary>
/// <param name="text">The report text to log</param>
public void Report(string text)
{
var log = new LogEntry(text, DateTime.UtcNow, LogType.Report);
_logs.Enqueue(log);
OnLogEvent(log);
_trace.WriteLine(DateTime.Now.ToString(DateFormat, CultureInfo.InvariantCulture) + " Report:: " + text);
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <filterpriority>2</filterpriority>
public void Dispose()
{
}
/// <summary>
/// Raise a log event safely
/// </summary>
protected virtual void OnLogEvent(LogEntry log)
{
var handler = LogEvent;
if (handler != null)
{
handler(log);
}
}
}
}
+36
View File
@@ -0,0 +1,36 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace QuantConnect.Logging
{
/// <summary>
/// Provides an implementation of <see cref="ILogHandler"/> that writes all log messages to a file on disk
/// without timestamps.
/// </summary>
/// <remarks>
/// This type is provided for convenience/setting from configuration
/// </remarks>
public class RegressionFileLogHandler : FileLogHandler
{
/// <summary>
/// Initializes a new instance of the <see cref="RegressionFileLogHandler"/> class
/// that will write to a 'regression.log' file in the executing directory
/// </summary>
public RegressionFileLogHandler()
: base("regression.log", false)
{
}
}
}
+40
View File
@@ -0,0 +1,40 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace QuantConnect.Logging
{
/// <summary>
/// Provides methods for determining higher stack frames
/// </summary>
public static class WhoCalledMe
{
/// <summary>
/// Gets the method name of the caller
/// </summary>
/// <param name="frame">The number of stack frames to retrace from the caller's position</param>
/// <returns>The method name of the containing scope 'frame' stack frames above the caller</returns>
[MethodImpl(MethodImplOptions.NoInlining)] // inlining messes this up pretty badly
public static string GetMethodName(int frame = 1)
{
// we need to increment the frame to account for this method
var methodBase = new StackFrame(frame + 1).GetMethod();
var declaringType = methodBase.DeclaringType;
return declaringType != null ? declaringType.Name + "." + methodBase.Name : methodBase.Name;
}
}
}