首页 > 代码库 > MongoDB学习笔记~监控Http请求的消息链

MongoDB学习笔记~监控Http请求的消息链

在微服务架构里,你的一个任务可以需要经过多次中转,去多个接口获取数据,而在这个过程中,出现问题后的解决就成了一个大难点,你无法定位它的问题,这时,大叔的分布式消息树就出现了,费话不多说,主要看一下实现的逻辑。

大叔的想法

技术分享

在消息传递过程中,使用这个消息上下文

    /// <summary>    /// 消息上下文    /// </summary>    public class LoggerContext    {        /// <summary>        /// 消息根ID(完整请求)        /// </summary>        [BsonId]        [BsonRepresentation(BsonType.ObjectId)]        public string Id { get; set; }        public string RootId { get; set; }        /// <summary>        /// 上级消息ID(前一个请求)        /// </summary>        public string ParentId { get; set; }        /// <summary>        /// 当前消息ID(当前请求)        /// </summary>        public string ChildId { get; set; }        /// <summary>        /// 消息体        /// </summary>        public string MessageBody { get; set; }        /// <summary>        /// 当前url        /// </summary>        public string Url { get; set; }        /// <summary>        /// 时间        /// </summary>        public DateTime AddTime { get; set; }    }

大叔对消息处理程序的封装

    /// <summary>    /// 分布式消息树实现    /// </summary>    public class LoggerContextImpl    {        static ILogger logger = new EmptyLogger();        #region Fields & Consts        const string Format_Msg_Before = "请求之前,地址:{0},方式:{1},时间:{2}";        const string Format_Msg = "响应之后,地址:{0},状态码:{1},时间:{2}";        /// <summary>        /// HttpContext上存储的日志上下文        /// </summary>        const string LOGGERCONTEXT = "LoggerContext";        #endregion        #region Private Methods        /// <summary>        /// 从请求头中拿到当前的消息树对象        /// client发布端:SetContextToServer        /// server接收端:GetContextFromServer        /// </summary>        /// <returns></returns>        static LoggerContext GetContextFromServer()        {            try            {                var result = System.Web.HttpContext.Current.Request.Headers.GetValues(LOGGERCONTEXT);                if (result != null && result.Length > 0)                {                    var cat = JsonConvert.DeserializeObject<LoggerContext>(result[0].ToString());                    return cat;                }                return null;            }            catch (Exception ex)            {                logger.Logger_Error(ex);                return null;            }        }        static LoggerContext GetContextFromServer(HttpClient http)        {            try            {                IList<string> result = http.DefaultRequestHeaders.GetValues(LOGGERCONTEXT) as IList<string>;                if (result != null && result.Count > 0)                {                    var cat = JsonConvert.DeserializeObject<LoggerContext>(result[0].ToString());                    return cat;                }                return null;            }            catch (Exception ex)            {                logger.Logger_Error(ex);                return null;            }        }        /// <summary>        /// 设置消息树到当前请求头        /// </summary>        /// <returns></returns>        internal static void SetContextToRequestHeader(System.Web.HttpContext http, LoggerContext context)        {            try            {                if (http.Request.Headers.GetValues(LOGGERCONTEXT) != null && http.Request.Headers.GetValues(LOGGERCONTEXT).Length > 0)                {                    http.Request.Headers.Remove(LOGGERCONTEXT);                }                http.Request.Headers.Add(LOGGERCONTEXT, JsonConvert.SerializeObject(context));            }            catch (Exception ex)            {                logger.Logger_Error(ex);            }        }        /// <summary>        /// 设置消息树到当前请求头        /// </summary>        /// <param name="http"></param>        /// <param name="context"></param>        internal static void SetContextToRequestHeader(HttpClient http, LoggerContext context)        {            try            {                http.DefaultRequestHeaders.Remove(LOGGERCONTEXT);                http.DefaultRequestHeaders.Add(LOGGERCONTEXT, JsonConvert.SerializeObject(context));            }            catch (Exception ex)            {                logger.Logger_Error(ex);            }        }        /// <summary>        /// 设置消息树到当前请求头        /// </summary>        /// <param name="http"></param>        /// <param name="context"></param>        internal static void SetContextToRequestHeader(System.Web.HttpContextBase http, LoggerContext context)        {            try            {                if (http.Request.Headers.GetValues(LOGGERCONTEXT) != null && http.Request.Headers.GetValues(LOGGERCONTEXT).Length > 0)                {                    http.Request.Headers.Remove(LOGGERCONTEXT);                }                http.Request.Headers.Add(LOGGERCONTEXT, JsonConvert.SerializeObject(context));            }            catch (Exception ex)            {                logger.Logger_Error(ex);            }        }        /// <summary>        /// 设置请求头,它来自某个响应头        /// </summary>        /// <param name="response"></param>        internal static void SetContextToRequestHeader(HttpResponseMessage response, string currentUrl = null)        {            try            {                IEnumerable<string> context = new List<string>();                if (response.Headers.TryGetValues(LOGGERCONTEXT, out context) || response.RequestMessage.Headers.TryGetValues(LOGGERCONTEXT, out context))                {                    if (context != null)                    {                        var cat = JsonConvert.DeserializeObject<LoggerContext>((context as string[])[0].ToString());                        SetContextToRequestHeader(System.Web.HttpContext.Current, cat);                        GetCurrentContext("响应结束", currentUrl);                    }                }            }            catch (Exception ex)            {                logger.Logger_Error(ex);            }        }        /// <summary>        /// 设置LoggerContext到响应头        /// </summary>        /// <param name="response"></param>        /// <param name="context"></param>        internal static void SetContextToResponseHeader(HttpResponseBase response, LoggerContext context)        {            try            {                if (response.Headers.GetValues(LOGGERCONTEXT) != null                               && response.Headers.GetValues(LOGGERCONTEXT).Length > 0)                {                    response.Headers.Remove(LOGGERCONTEXT);                }                response.Headers.Add(LOGGERCONTEXT, JsonConvert.SerializeObject(context));            }            catch (Exception ex)            {                logger.Logger_Error(ex);            }        }        /// <summary>        /// 生产一个ROOTID        /// </summary>        /// <returns></returns>        static string GenerateRootID()        {            return DateTime.Now.ToString("yyyyMMddHHmmssfff") + Thread.CurrentThread.ManagedThreadId;        }        /// <summary>        /// 递归树        /// </summary>        /// <param name="str"></param>        /// <param name="id"></param>        /// <param name="timer"></param>        static void MsgTree(StringBuilder str, string id, List<DateTime> timer)        {            var list = NoSql.MongodbManager<LoggerContext>.Instance.Find(i => i.ParentId == id).ToList();            if (list != null)            {                str.Append("<ul class=‘treeMsg‘>");                foreach (var item in list)                {                    timer.Add(item.AddTime);                    str.AppendFormat("<li><span style=‘color:red‘>{0}</span><span style=‘color:green‘>{1}</span><span>{2}</span></li>"                     , item.Url                     , item.MessageBody                     , item.AddTime);                    MsgTree(str, item.ChildId, timer);                }                str.Append("</ul>");            }        }        #endregion        #region 分布式消息树的封装(仓储大叔)         /// <summary>        ///  建立一个上下文对象        /// </summary>        /// <param name="rootId">根ID</param>        /// <param name="parentId">上一请求ID</param>        /// <param name="url"></param>        /// <returns></returns>        public static LoggerContext DoTransaction(string rootId, string parentId, string url)        {            if (GlobalConfig.ConfigManager.Config.Logger.IsHttpClientLog != 1)                return new LoggerContext();            //建立一个日志,返回rootid,parentid(第一个应该是空),currentid,其中currentid将做为下一次请求的parentid            var filter = Builders<LoggerContext>.Filter.Eq(i => i.RootId, rootId);            var context = NoSql.MongodbManager<LoggerContext>.Instance.Find(filter).FirstOrDefault();            if (!string.IsNullOrWhiteSpace(parentId))            {                filter = Builders<LoggerContext>.Filter.Eq(i => i.ParentId, parentId);                context = NoSql.MongodbManager<LoggerContext>.Instance.Find(filter).FirstOrDefault();            }            if (context == null)            {                context = new LoggerContext                {                    RootId = GenerateRootID(),                    ParentId = null,                    ChildId = Domain.PrimaryKey.GenerateNewStringId(),                    MessageBody = "开启一个新的请求:" + url,                    Url = System.Web.HttpContext.Current.Request.Url.AbsoluteUri.Split(new char[] { ? }, StringSplitOptions.RemoveEmptyEntries)[0],                    AddTime = DateTime.Now,                };                NoSql.MongodbManager<LoggerContext>.Instance.InsertOne(context);            }            context.MessageBody = HttpUtility.UrlEncode(context.MessageBody);            return context;        }        /// <summary>        /// 添加日志,它依赖于一个会话        /// root->message->message1->message1.1->message1.1.1        /// </summary>        /// <param name="parentId">父会话ID</param>        /// <param name="url"></param>        /// <param name="message"></param>        public static LoggerContext LogEvent(string parentId, string url, string message)        {            if (GlobalConfig.ConfigManager.Config.Logger.IsHttpClientLog != 1)                return new LoggerContext();            var filter = Builders<LoggerContext>.Filter.Eq(i => i.ChildId, parentId);            var context = NoSql.MongodbManager<LoggerContext>.Instance.Find(filter).FirstOrDefault();            if (context != null)            {                context = new LoggerContext                {                    RootId = context.RootId,                    ParentId = context.ChildId,                    ChildId = Domain.PrimaryKey.GenerateNewStringId(),                    MessageBody = message + ":" + url,                    Url = System.Web.HttpContext.Current.Request.Url.AbsoluteUri.Split(new char[] { ? }, StringSplitOptions.RemoveEmptyEntries)[0],                    AddTime = DateTime.Now,                };                NoSql.MongodbManager<LoggerContext>.Instance.InsertOne(context);            }            return context;        }        /// <summary>        /// 返回当前上下文        /// </summary>        /// <returns></returns>        public static LoggerContext GetCurrentContext(string message, string currentUrl = null)        {            try            {                currentUrl = (currentUrl ?? System.Web.HttpContext.Current.Request.Url.AbsoluteUri).Split(new char[] { ? }, StringSplitOptions.RemoveEmptyEntries)[0];                var context = GetContextFromServer();                if (context == null)                {                    context = DoTransaction("", "", currentUrl);                }                else                {                    context = LogEvent(context.ChildId, currentUrl, message);                }                return context;            }            catch (Exception ex)            {                logger.Logger_Error(ex);                return new LoggerContext();            }        }        #endregion        #region 消息树UI        /// <summary>        /// 返回UI消息树        /// </summary>        /// <returns></returns>        public static string GetMongoLog(DateTime? fromDate, DateTime? toDate, int page = 1)        {            string from = DateTime.Now.AddYears(-1).Date.ToString("yyyy-MM-dd");            string to = DateTime.Now.Date.AddDays(1).ToString("yyyy-MM-dd");            if (fromDate.HasValue)            {                from = fromDate.Value.ToString("yyyy-MM-dd");            }            if (toDate.HasValue)            {                to = toDate.Value.ToString("yyyy-MM-dd");            }            var stages = new List<IPipelineStageDefinition>();            stages.Add(new JsonPipelineStageDefinition<BsonDocument, BsonDocument>("{$match:{AddTime:{$gt:ISODate(‘" + from + "‘),$lt:ISODate(‘" + to + "‘)}}}"));            stages.Add(new JsonPipelineStageDefinition<BsonDocument, BsonDocument>("{$group:{_id: \"$RootId\", count: {$sum: 1}}}"));            stages.Add(new JsonPipelineStageDefinition<BsonDocument, BsonDocument>("{$skip:" + page * 5 + "}"));            stages.Add(new JsonPipelineStageDefinition<BsonDocument, BsonDocument>("{$limit:5}"));            var pipeline = new PipelineStagePipelineDefinition<BsonDocument, BsonDocument>(stages);            var result = NoSql.MongodbManager<LoggerContext>.Collection.Aggregate(pipeline);            StringBuilder str = new StringBuilder();            str.Append("<ol class=‘treeMsg‘>");            foreach (var item in result.ToList())            {                var timer = new List<DateTime>();                var old = NoSql.MongodbManager<LoggerContext>.Instance.Find(i => i.RootId == item.Values.ToArray()[0].ToString() && i.ParentId == null).FirstOrDefault();                timer.Add(old.AddTime);                str.Append("<li style=‘margin:5px;border:1px dashed #aaa‘>");                str.AppendFormat("<span style=‘color:red;‘>{0}</span><span style=‘color:green‘>{1}</span><span>{2}</span>"                   , old.Url                   , old.MessageBody                   , old.AddTime);                MsgTree(str, old.ChildId, timer);                str.AppendFormat("<p><b><em>本次请求用时{0}毫秒({1}秒)<em></b></p>"                    , (timer.Max() - timer.Min()).TotalMilliseconds                    , (timer.Max() - timer.Min()).TotalSeconds);                str.Append("</li>");            }            str.Append("</ol>");            return str.ToString();        }        #endregion    }

 

MongoDB学习笔记~监控Http请求的消息链