C#等同于Python的日志库

时间:2010-12-17 20:49:22

标签: c# python logging

使用python,我可以使用非常方便的logging库。

C#的日志库是什么?

5 个答案:

答案 0 :(得分:8)

您可以使用log4netTraceListener

答案 1 :(得分:5)

您还应该考虑NLog(http://nlog-project.org),因为自2006年4月以来log4net尚未更新。以下是关于.NET日志记录的另一个讨论 - log4net vs. Nlog

答案 2 :(得分:2)

log4net并在EntLib中记录应用程序块,但我在log4net中听到了一些并发问题。

答案 3 :(得分:1)

我发现log4net非常方便:http://logging.apache.org/log4net/index.html

或者如果要登录到事件日志,请使用tracelistener。通过http://www.google.se/search?sourceid=chrome&ie=UTF-8&q=c%23+tracelistener

可以找到很多例子

答案 4 :(得分:0)

以下是Python public class Logger { private static readonly System.Collections.Generic.Dictionary<string, Logger> Loggers = new System.Collections.Generic.Dictionary<string, Logger>(); private readonly string _name; private LoggingLevel _level; private readonly System.Collections.Generic.List<Filter> _filters; private readonly System.Collections.Generic.List<Handler> _handlers; public static Logger GetLogger(string name = "root") { Logger value; if (Logger.Loggers.TryGetValue(name, out value)) { return value; } value = new Logger(name); Logger.Loggers.Add(name, value); return value; } private Logger(string name) { this._name = name; this._level = LoggingLevel.Warning; this._filters = new System.Collections.Generic.List<Filter>(); this._handlers = new System.Collections.Generic.List<Handler>(); } public void SetLevel(LoggingLevel level) { this._level = level; } public void AddHandler(Handler handler) { this._handlers.Add(handler); } public void RemoveHandler(Handler handler) { this._handlers.Remove(handler); } public void AddFilter(Filter filter) { this._filters.Add(filter); } public void RemoveFilter(Filter filter) { this._filters.Remove(filter); } public void Debug(string message, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "") { this.Log(LoggingLevel.Debug, message, null, filePath, lineNumber, memberName); } public void Info(string message, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "") { this.Log(LoggingLevel.Info, message, null, filePath, lineNumber, memberName); } public void Warning(string message, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "") { this.Log(LoggingLevel.Warning, message, null, filePath, lineNumber, memberName); } public void Error(string message, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "") { this.Log(LoggingLevel.Error, message, null, filePath, lineNumber, memberName); } public void Critical(string message, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "") { this.Log(LoggingLevel.Critical, message, null, filePath, lineNumber, memberName); } public void Exception(Exception error, string message = "", [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "") { this.Log(LoggingLevel.Error, message, error, filePath, lineNumber, memberName); } public void Log(LoggingLevel level, string message, Exception error = null, [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "") { if (this.IsEnabledFor(level)) { var record = new LogRecord(this._name, level, filePath, lineNumber, memberName, message, error); if (this._filters.All(x => x.Check(record))) { this._handlers.ForEach(x => x.Process(record)); } } } public bool IsEnabledFor(LoggingLevel level) { return level >= this._level; } } public abstract class Handler { public static ExceptionSetting RaiseExceptions = ExceptionSetting.Write; private static readonly Formatter DefaultFormatter = new Formatter(); private LoggingLevel _level; private readonly System.Collections.Generic.List<Filter> _filters; private Formatter _formatter; protected Handler() { this._level = LoggingLevel.Warning; this._filters = new System.Collections.Generic.List<Filter>(); this._formatter = null; } public void SetLevel(LoggingLevel level) { this._level = level; } public void SetFormatter(Formatter formatter) { this._formatter = formatter; } public void AddFilter(Filter filter) { this._filters.Add(filter); } public void RemoveFilter(Filter filter) { this._filters.Remove(filter); } public void Process(LogRecord record) { if (this.IsEnabledFor(record.Level) && this._filters.All(x => x.Check(record))) { lock (this) { this.Emit(record); } } } protected abstract void Emit(LogRecord record); public bool IsEnabledFor(LoggingLevel level) { return level >= this._level; } private Formatter SafeFormatter => this._formatter ?? Handler.DefaultFormatter; protected string Format(LogRecord record) { return this.SafeFormatter.Format(record); } protected void HandleError(LogRecord record, Exception error) { if (Handler.RaiseExceptions != ExceptionSetting.Pass) { Console.Error.WriteLine("--- Logging error ---"); Console.Error.WriteLine(error); Console.Error.WriteLine($"Logged from file {record.FilePath}, line {record.LineNumber}"); Console.Error.WriteLine($"Message: {record.Message}"); Console.Error.WriteLine($"Created: {this.SafeFormatter.FormatTime(record)}"); if (Handler.RaiseExceptions == ExceptionSetting.Throw) { throw error; } } } } public class StreamHandler : Handler { public static readonly string Terminator = Environment.NewLine; protected System.IO.TextWriter Stream; public StreamHandler(System.IO.TextWriter stream = null) { this.Stream = stream ?? Console.Error; } public void Flush() { this.Stream.Flush(); } protected override void Emit(LogRecord record) { try { var message = this.Format(record); this.Stream.Write(message); this.Stream.Write(StreamHandler.Terminator); this.Flush(); } catch (Exception error) { this.HandleError(record, error); } } } public class FileHandler : StreamHandler { public static readonly System.Text.Encoding DefaultEncoding = System.Text.Encoding.GetEncoding("iso-8859-1"); protected readonly string FileName; private readonly System.IO.FileMode _mode; private readonly System.Text.Encoding _codec; public FileHandler(string fileName, System.IO.FileMode mode, System.Text.Encoding codec = null) : base( new System.IO.StreamWriter(new System.IO.FileStream(fileName, mode), codec ?? FileHandler.DefaultEncoding)) { this.FileName = fileName; this._mode = mode; this._codec = codec; } public void Close() { this.Flush(); this.Stream.Close(); } protected System.IO.StreamWriter Open() { return new System.IO.StreamWriter(new System.IO.FileStream(this.FileName, this._mode), this._codec ?? FileHandler.DefaultEncoding); } } public abstract class BaseRotatingHandler : FileHandler { protected Func<string, string> Namer; protected Action<string, string> Rotator; protected BaseRotatingHandler(string fileName, System.IO.FileMode mode, System.Text.Encoding codec = null) : base( fileName, mode, codec) { this.Namer = null; this.Rotator = null; } protected override void Emit(LogRecord record) { try { if (this.ShouldRollover(record)) { this.DoRollover(); } base.Emit(record); } catch (Exception error) { this.HandleError(record, error); } } protected abstract bool ShouldRollover(LogRecord record); protected abstract void DoRollover(); protected string GetRotationFilename(string defaultName) { return this.Namer == null ? defaultName : this.Namer(defaultName); } protected void Rotate(string source, string destination) { if (this.Rotator == null) { System.IO.File.Move(source, destination); } else if (System.IO.File.Exists(source)) { this.Rotator(source, destination); } } } public class RotatingFileHandler : BaseRotatingHandler { private readonly int _maxBytes; private readonly int _backupCount; public RotatingFileHandler(string fileName, System.IO.FileMode mode, int maxBytes = 0, int backupCount = 0, System.Text.Encoding codec = null) : base(fileName, mode, codec) { this._maxBytes = maxBytes; this._backupCount = backupCount; } protected override bool ShouldRollover(LogRecord record) { if (this._maxBytes <= 0) return false; var message = $"{this.Format(record)}{StreamHandler.Terminator}"; return ((System.IO.StreamWriter) this.Stream).BaseStream.Position + message.Length >= this._maxBytes; } protected override void DoRollover() { this.Close(); if (this._backupCount > 0) { string destination; foreach (var i in Enumerable.Range(1, this._backupCount - 1).Reverse()) { var source = this.GetRotationFilename($"{this.FileName}.{i}"); destination = this.GetRotationFilename($"{this.FileName}.{i + 1}"); if (System.IO.File.Exists(source)) { if (System.IO.File.Exists(destination)) { System.IO.File.Delete(destination); } System.IO.File.Move(source, destination); } } destination = this.GetRotationFilename($"{this.FileName}.1"); if (System.IO.File.Exists(destination)) { System.IO.File.Delete(destination); } this.Rotate(this.FileName, destination); } this.Stream = this.Open(); } } public class SmtpHandler : Handler { private readonly System.Net.DnsEndPoint _mailServer; private readonly string _fromAddress; private readonly System.Collections.Generic.List<string> _toAddress; private readonly string _subject; private readonly int _timeout; public SmtpHandler(System.Net.DnsEndPoint mailServer, string fromAddress, System.Collections.Generic.List<string> toAddress, string subject, int timeout = 1000) { this._mailServer = mailServer; this._fromAddress = fromAddress; this._toAddress = toAddress; this._subject = subject; this._timeout = timeout; } protected string GetSubject(LogRecord record) { return this._subject; } protected override void Emit(LogRecord record) { try { var message = new System.Net.Mail.MailMessage { From = new System.Net.Mail.MailAddress(this._fromAddress), Subject = this.GetSubject(record), Body = this.Format(record) }; this._toAddress.ForEach(x => message.To.Add(new System.Net.Mail.MailAddress(x))); using (var client = new System.Net.Mail.SmtpClient(this._mailServer.Host, this._mailServer.Port)) { client.Timeout = this._timeout; client.Send(message); } } catch (Exception error) { this.HandleError(record, error); } } } public class Filter { private readonly string _name; public Filter(string name = null) { this._name = name; } public bool Check(LogRecord record) { return this._name == null || this._name == record.Name; } } public class StyleSettings { public string DefaultFormat { get; } public string TimeToken { get; } public string RegexSearch { get; } public string PreferredFormat { get; } public StyleSettings(string defaultFormat, string timeToken, string regexSearch, string preferredFormat) { this.DefaultFormat = defaultFormat; this.TimeToken = timeToken; this.RegexSearch = regexSearch; this.PreferredFormat = preferredFormat; } } public class Style { public static readonly StyleSettings Percent = new StyleSettings("%(Message)", "%(Created)", @"%\((\w+)\)", "%(Level):%(Name):%(Message)"); public static readonly StyleSettings StringFormat = new StyleSettings("{Message}", "{Created}", @"\{(\w+)\}", "{Level}:{Name}:{Message}"); public static readonly StyleSettings StringTemplate = new StyleSettings("${Message}", "${Created}", @"\$\{(\w+)\}", "${Level}:${Name}:${Message}"); private readonly StyleSettings _settings; private readonly string _format; public Style(StyleSettings settings, string format = null) { this._settings = settings; this._format = format ?? settings.DefaultFormat; } public bool UsesTime => this._format.IndexOf(this._settings.TimeToken, StringComparison.Ordinal) >= 0; public string Format(LogRecord record, string dateFormat = null) { var regex = new System.Text.RegularExpressions.Regex(this._settings.RegexSearch); return regex.Replace(this._format, x => Style.Replace(x, record, dateFormat)); } private static string Replace(System.Text.RegularExpressions.Match match, LogRecord record, string dateFormat) { System.Diagnostics.Debug.Assert(match.Groups.Count == 2, "one item should be captured"); var value = Functions.GetProperty<LogRecord, object>(record, match.Groups[1].Value); return value is DateTime && dateFormat != null ? ((DateTime) value).ToString(dateFormat) : value.ToString(); } } public class Formatter { private readonly Style _style; private readonly string _dateFormat; public Formatter(string format = null, string dateFormat = null, StyleSettings settings = null) { var preferredSettings = settings ?? Style.StringFormat; this._style = new Style(preferredSettings, format ?? preferredSettings.PreferredFormat); this._dateFormat = dateFormat ?? Scan.DateTimeFormat; } public string FormatTime(LogRecord record, string dateFormat = null) { return record.Created.ToString(dateFormat ?? this._dateFormat); } public string FormatException(LogRecord record) { return record.Error.ToString(); } public bool UsesTime => this._style.UsesTime; public string FormatMessage(LogRecord record) { return this._style.Format(record, this._dateFormat); } public string Format(LogRecord record) { var message = this.FormatMessage(record); if (record.Error != null) { message += StreamHandler.Terminator + this.FormatException(record); } return message; } } public class LogRecord { public string Name { get; } public LoggingLevel Level { get; } public string FilePath { get; } public int LineNumber { get; } public string MemberName { get; } public string Message { get; } public Exception Error { get; } public DateTime Created { get; } public int ThreadId { get; } public string ThreadName { get; } public int ProcessId { get; } public string ProcessName { get; } public LogRecord(string name, LoggingLevel level, string filePath, int lineNumber, string memberName, string message, Exception error = null) { this.Name = name; this.Level = level; this.FilePath = filePath; this.LineNumber = lineNumber; this.MemberName = memberName; this.Message = message; this.Error = error; this.Created = DateTime.Now; var thread = System.Threading.Thread.CurrentThread; this.ThreadId = thread.ManagedThreadId; this.ThreadName = thread.Name; var process = System.Diagnostics.Process.GetCurrentProcess(); this.ProcessId = process.Id; this.ProcessName = process.ProcessName; } public override string ToString() { return $"<{nameof(LogRecord)}: {this.Name}, {this.Level}, {this.FilePath}, {this.LineNumber}, {this.Message}>"; } } public enum LoggingLevel { Debug, // Detailed information, typically of interest only when diagnosing problems. Info, // Confirmation that things are working as expected. Warning, // An indication that something unexpected happened, or indicative of some problem in the near future (e.g. ‘disk space low’). The software is still working as expected. Error, // Due to a more serious problem, the software has not been able to perform some function. Critical // A serious error, indicating that the program itself may be unable to continue running. } public enum ExceptionSetting { Pass, // Do nothing about the problem. Write, // Record problem on standard error. Throw // Propagate the exception once written. } public class Scan { public const string DateTimeFormat = "yyyy-MM-ddTHH:mm:ss"; } public static class Functions { public static TOut GetProperty<TIn, TOut>(TIn value, string name) { return (TOut) Functions.NotNull(value.GetType().GetProperty(name), $"{name} is not available").GetValue(value); } public static T NotNull<T>(T value, string message = null) { if (value == null) { throw new InvalidOperationException(message ?? $"{nameof(value)} may not be null"); } return value; } } 模块中许多概念和功能的C#近似值:

<body>
<!--/*@thymesVar id="cryptos" type="java.util.Map<Integer, jasmin.merusic.domain.Crypto>"*/-->
<!--/*@thymesVar id="crypto" type="jasmin.merusic.domain.Crypto"*/-->
<div class="container-fluid" style="margin-top: 20px">
<div class="row">
    <div class="col-md-6 col-md-offset-3">
        <div class="panel panel-primary">

            <div class="panel-heading">
                <h1 class="panel-title">CryptoCurrencies from API</h1>
            </div>
            <div class="panel-body">
                <div class="table-responsive" th:if="${not #maps.isEmpty(cryptos)}">
                    <table class="table table-hover ">
                        <thead class="thead-inverse">
                        <tr>
                            <th>Name</th>
                            <th>
                               **<form th:action="@{/values/}" >
                                <select name="fiatCurrency" onchange="this.form.submit()">
                                <option  selected="selected" value="USD">USD</option>
                                <option  value="EUR">Euro</option>
                                <option  value="CNY">C. Yuan</option>
                                </select>
                               </form>**
                            </th>
                            <th>Change in 24h(%)</th>
                            <th>Rank</th>
                            <th>Symbol</th>
                        </tr>
                        </thead>
                        <tr th:remove="all">
                            <td>Joe</td>
                            <td>Buck</td>
                            <td>Male</td>
                            <td>foo@example.com</td>
                        </tr>
                        <tr th:remove="all">
                            <td>Joe</td>
                            <td>Buck</td>
                            <td>Male</td>
                            <td>foo@example.com</td>
                        </tr>

                        <tr th:each="crypto : ${cryptos.values()}">
                            <td th:text="${crypto.name}">Joe</td>
                                <span th:each="cryp : ${crypto.quotes.values()}">
                                    <td th:text="${cryp.price}">Buck</td>
                                    <td th:text="${cryp.percent_change_24h}">Buck</td>
                                </span>
                            <td th:text="${crypto.rank}">Male</td>
                            <td th:text="${crypto.symbol}">foo@example.com</td>
                        </tr>
                    </table>
                </div>
            </div>
        </div>
    </div>
   </div>
</div>
</body>