线程安全日志记录类的实现

如何解决线程安全日志记录类的实现

| 以下是实现相当简单的线程安全日志记录类的正确方法吗? 我知道我从来没有明确地关闭ѭ0,这会是一个问题吗? 最初使用
TextWriter.Synchronized
方法时,它似乎无法工作,直到我在静态构造函数中对其进行了初始化并将其设置为只读,如下所示:
public static class Logger
{
    static readonly TextWriter tw; 

    static Logger()
    {
        tw = TextWriter.Synchronized(File.AppendText(SPath() + \"\\\\Log.txt\")); 
    }

    public static string SPath()
    {
        return ConfigManager.GetAppSetting(\"logPath\"); 
    }

    public static void Write(string logMessage)
    {
        try
        {
            Log(logMessage,tw);
        }
        catch (IOException e)
        {
            tw.Close();
        }
    }

    public static void Log(string logMessage,TextWriter w)
    {
        w.WriteLine(\"{0} {1}\",DateTime.Now.ToLongTimeString(),DateTime.Now.ToLongDateString());
        w.WriteLine(\"  :\");
        w.WriteLine(\"  :{0}\",logMessage);
        w.WriteLine(\"-------------------------------\");

        // Update the underlying file.
        w.Flush();
    }
}
    

解决方法

        在这里,我将采用与其他答案完全不同的方法,并假设您实际上是想学习如何编写更好的线程感知代码,并且没有从我们这里寻求第三者的建议(即使您可能最终会得到建议)使用一个。) 正如其他人所说,您正在创建一个线程安全的“ 0”,这意味着对WriteLine的调用是线程安全的,这并不意味着一堆对
WriteLine
的调用将作为原子操作执行。我的意思是,不能保证四个WriteLine调用将按顺序进行。您可能具有线程安全的
TextWriter
,但是没有线程安全的
Logger.Log
方法;)为什么?因为在这四个调用期间的任何时候,另一个线程可能会决定也调用ѭ7。这意味着您的
WriteLine
通话将不同步。解决此问题的方法是使用
lock
语句,如下所示:
private static readonly object _syncObject = new object();

public static void Log(string logMessage,TextWriter w)    {
   // only one thread can own this lock,so other threads
   // entering this method will wait here until lock is
   // available.
   lock(_syncObject) {
      w.WriteLine(\"{0} {1}\",DateTime.Now.ToLongTimeString(),DateTime.Now.ToLongDateString());
      w.WriteLine(\"  :\");
      w.WriteLine(\"  :{0}\",logMessage);
      w.WriteLine(\"-------------------------------\");
      // Update the underlying file.
      w.Flush();
   }
}
因此,现在您有了一个线程安全的“ 0”和一个线程安全的“ 12”。 合理?     ,        在调用TextWriter.Synchronized时将保护that0ѭ的单个实例,但不会同步您的写入,因此一个\“ Log \”调用将保留在文件内。 如果从多个线程调用
Write
(或使用内部
TextWriter
实例使用
Log
),则各个inter4ѭ调用可能会交织在一起,从而使日期和时间戳无法使用。 我个人将使用为此已存在的第三方日志记录解决方案。如果不是这种选择,那么自己同步(即使使用简单的锁)也可能比使用框架的ѭ1包装器更为有用。     ,        有人在今天讨论一些日志记录问题时将我指向这篇文章。我们已经在这里有了很好的答案,但是我添加我的答案只是为了展示
Logger
类的一个简单版本,该类以完全
Threadsafe
的方式做同样的事情。 这里要注意的一件事是,为了安全起见,不需要ѭ1,因为我们正在适当的ѭ9内写入文件。 注意:这已经在x0n答案的注释部分中进行了讨论。
public static class Logger
{
    static readonly object _locker = new object();

    public static void Log(string logMessage)
    {
        try
        {
            var logFilePath = Path.Combine(@\"C:\\YourLogDirectoryHere\",\"Log.txt\");
            //Use this for daily log files : \"Log\" + DateTime.Now.ToString(\"yyyy-MM-dd\") + \".txt\";
            WriteToLog(logMessage,logFilePath);
        }
        catch (Exception e)
        {
            //log log-exception somewhere else if required!
        }
    }

    static void WriteToLog(string logMessage,string logFilePath)
    {
        lock (_locker)
        {
            File.AppendAllText(logFilePath,string.Format(\"Logged on: {1} at: {2}{0}Message: {3}{0}--------------------{0}\",Environment.NewLine,DateTime.Now.ToLongDateString(),logMessage));
        }
    }
}
要记录一些东西,只需调用
Logger.Log(\"Some important event has occurred!\");
它会像这样创建一个日志条目   登录:2015年10月7日在:02:11:23   消息:发生了一些重要事件!       --------------------     ,        您应该研究此类(.NET 2.0的一部分),而无需“创建”自己的记录器。使您可以登录到文本文件,事件视图等。 http://msdn.microsoft.com/zh-CN/library/system.diagnostics.tracesource.aspx 您的\“ Log \”方法可能类似于以下内容(假设有一个名为\'traceSource \'的内部成员变量):
    public void Log(TraceEventType eventType,string message)
    {
        this.traceSource.TraceEvent(eventType,message);
        this.traceSource.Flush();
    }
支持此操作的是一个配置部分,该部分命名TraceSource并具有一些Config设置。假定在记录器中构造TraceSource时,将使用配置中命名的跟踪源之一实例化它。
<system.diagnostics>
<sources>
  <source name=\"Sample\" switchValue=\"Information,ActivityTracing\">
    <listeners>
      <add name=\"file\"
         initializeData=\"C:\\temp\\Sample-trace.log\"
         traceOutputOptions=\"DateTime\"
         type=\"System.Diagnostics.TextWriterTraceListener,System,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089\"/>
    </listeners>
  </source>
</sources>
另外,请不要将记录器设为静态。相反,请使用Enterprise Library 5.0 Unity进行依赖性注入/ IOC。 希望这可以帮助!     ,        如果您正在寻找一种检测代码的简单方法,则该工具已经在.NET中存在: http://msdn.microsoft.com/zh-CN/library/system.diagnostics.trace.aspx 此外,第三方工具将为您提供强大的日志记录解决方案;示例包括log4net,nLog和企业库。 我真的建议不要在此方面重新发明轮子:)     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-