---记录错误日记 log------------ 队列Queue

本文介绍了一种基于队列的数据结构实现的错误日志记录机制,通过多线程技术确保了高并发环境下日志记录的准确性和效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1》定义一个错误日记类

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Utility
{
    public class LogHelper
    {
        //创建一个队列
        private static Queue<string> qu = new Queue<string>();

        /// <summary>
        /// 只要有错误,就将错误信息放入队列中
        /// </summary>
        /// <param name="ex"></param>
        public static void WriteLog(Exception ex)
        {

            //为什么要加这个锁?因为可能会有多个人同时错日记,调用这个线程造成并发。
            //加锁:用于解决了多线程同时写文件的并发问题
            lock ("lok")
            {

                StringBuilder sb = new StringBuilder();

                sb.AppendLine("----------------" + DateTime.Now.ToString() + "-----------------------");
                sb.AppendLine(ex.Message);

                //把sb这个字符串放入内存当中去。(其实就是将sb这个字符串添加到qu这个队列中去)
                qu.Enqueue(sb.ToString());
            }
           


        }

        /// <summary>
        /// 我们不想每调用一次该方法就开启一个线程,如果没调用一次该方法就开启一个新线程,那么经过多次调用该方法后,就会产生多个新的线程,那么假如遇到多个人同时操作该方法,将错误信息写入log.txt文件就会造成并发问题。 那么我们希望这个方法就只能调用一次,然后它里面的现场就一直开启(死循环)。所以我们就会想到将这个方法放在当前类的静态构造函数中去调用。因为静态构造函数只调用一次。 这样就保证了,当前方法只调用一次,然后就一直开启方法里面的后台线程。这样也保证了只产生一个新子线程。从而保证了在多个人同时调用该方法的时候,也只有一个线程去执行将错误信息写入log.txt文件的操作,从而不会引起并发的问题。(因为只有一个子线程,并发是指多个线程同时操作一个文件产生的问题)
        /// </summary>
        public static void WriteTxt()
        {
            Thread th = new Thread(() =>
            {
                while (true)
                {
                    if (qu.Count > 0)
                    {
                        //AppDomain类:表示应用程序域,它是一个应用程序在其中执行的独立环境。 此类不能被继承。
                        //AppDomain.CurrentDomain表示:获取当前 System.Threading.Thread 的当前应用程序域。
                        //BaseDirectory表示:获取基目录,它由程序集冲突解决程序用来探测程序集。
                        using (StreamWriter sw = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "App_Data/log.txt", true))
                        {
                            sw.Write(qu.Dequeue());
                        }
                    }
                }

            });
            th.IsBackground = true;
            th.Start();
        }

        /// <summary>
        /// 因为静态构造函数只执行一次。
        /// 静态构造函数的作用是用于静态数据成员完成值的初始化。静态类不能创建对象,所以它的作用仅仅是用于静态数据成员完成值的初始化。
        ///并且静态构造函数只被执行一次,什么时候被执行呢?就是这个类被第一次调用的时候被执行。
        /// </summary>
        static LogHelper()
        {
            WriteTxt();
        }
    }
}


2》调用错误日记类

在Global.asax中调用

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
using Utility;

namespace WebApp
{
    public class Global : System.Web.HttpApplication
    {

        protected void Application_Start(object sender, EventArgs e)
        {

        }

        protected void Session_Start(object sender, EventArgs e)
        {

        }

        protected void Application_BeginRequest(object sender, EventArgs e)
        {
            //string ip = Request.UserHostAddress;
            //if (ip == "::1")
            //{
            //    Response.Redirect("HtmlPage2.html");
            //}
        }

        protected void Application_AuthenticateRequest(object sender, EventArgs e)
        {

        }

        protected void Application_Error(object sender, EventArgs e)
        {
            ////错误信息  (注意:Environment.NewLine表示换行符)
            //string errorMsg = Context.Error.Message + Environment.NewLine + Context.Error.StackTrace + Environment.NewLine;

            ////将错误信息写入到日记
            //File.AppendAllText(Server.MapPath("~/log.txt"),errorMsg);



            //记录错误日记
            Exception ex = HttpContext.Current.Error;
            LogHelper.WriteLog(ex);

            //跳转到错误页
            Response.Redirect("~/ErrorPage.html");
        }

        protected void Session_End(object sender, EventArgs e)
        {

        }

        protected void Application_End(object sender, EventArgs e)
        {

        }
    }
}

Queue和ArrayList有什么不同啊?

Queue:先进先出,不能重新排序,不能索引访问

ArrayList:可以重新排序,可以索引访问

Queue(队列)类主要实现了一个FIFO(First In First Out,先进先出)的机制。元素在队列的尾部插入(入队操作),并从队列的头部移出(出队操作)。在Queue中主要使用Enqueue、Dequeue、Peek三个方法对队进行操作。Enqueue方法用于将对象添加到 Queue 的结尾处;Dequeue方法移除并返回位于 Queue 开始处的对象;Peek方法用于返回位于 Queue 开始处的对象但不将其移除。


ArrayList类主要用于对一个数组中的元素进行各种处理。在ArrayList中主要使用Add、Remove、RemoveAt、Insert四个方法对栈进行操作。Add方法用于将对象添加到 ArrayList 的结尾处;Remove方法用于从 ArrayList 中移除特定对象的第一个匹配项;RemoveAt方法用于移除 ArrayList 的指定索引处的元素;Insert方法用于将元素插入 ArrayList 的指定索引处。


根据您提供的命令及返回结果来看,尝试通过 `runmqsc` 命令连接到指定的队列管理器时出现了错误提示:**"AMQ8146: IBM MQ queue manager not available."**。这表明当前所请求的队列管理器不可用或未能成功建立连接。 以下是可能出现问题的原因及其对应解决方案: --- ### 1. **确认队列管理器名称是否正确** 错误的一个常见原因是输入了无效的队列管理器名。请再次核对您实际创建和启动的是不是叫作 "QMU_CCPS" 的队列管理器。可以通过下面指令列出所有已知队列管理器: ```bash dspmq ``` 结果示例如下所示: ```plaintext QMGR_NAME_1 STOPPED INACTIVE false QMGR_NAME_2 RUNNING ACTIVE true ``` --- ### 2. **验证端口号与主机地址匹配性** 另一可能性在于配置中的端口(PORT)或是宿主机器地址(HOSTNAME)。虽然这里用了 'localhost',但在某些特殊场景比如虚拟环境里,'127.0.0.1' 或者真实IP地址也许更合适一些。同时也要保证端口号准确无误,默认IBM WebSphere MQ监听于1414而非例子里面的1468除非明确更改过它。 使用以下方法检验端口状况: - 在Linux系统上执行 netstat 查看特定端口是否正在监听: ```bash sudo netstat -tulpn | grep :<port> # 示例查找1414端口情况 sudo netstat -tulpn | grep :1414 ``` --- ### 3. **检查队列管理器的状态和服务运行状态** 如果确实存在名为 "QMU_CCPS" 并且它的端口设定为非标准值如上述提到过的自定义设置成1468而不是常规的1414的情况,请确定该实例已经激活并且关联的服务也正处于活动当中。可以借助这样的脚本查看其健康度: ```bash strmqtrc -e on && endmqtrc -i all && dmpmqtrc -a > trace.txt ``` 上述序列开启追踪、收集数据然后导出诊断文档供后续查阅剖析之用。 --- ### 4. **审查日志文件获取更多信息** 最后别忘了审阅相关的日记条目来捕获更多潜在线索。一般来说重要事件会被记录进 `/var/mqm/qmgrs/<QueueManagerName>/errors/*.LOG` 文件组之中。举例来说若怀疑因为授权失败导致拒绝访问则特别留意似 AMQxxxx 编号开头的信息行内容。 --- 综上所述,在经历以上各环节检测之后仍不能解决问题的情况下,则有必要提供额外的技术细节包括但不限于确切的操作平台版本号以及其他定制化部署选项等等因素才能更好地协助解答疑惑之处。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值