系统架构方案中访问、操作日志的记录非常关键,他可以让我们快速发现系统存在异常的服务,同时通过用户的操作访问可以对数据做深度分析,从而提取出更优需求的产品功能。随着系统各微服务的数量的增多,系统业务逻辑的增多,平台产的日志数据量也在成倍数增长,所以传统的Nlog和Log4net已经不能满足实际需求。


一.微服务日志中心架构设计

我们先了解一下微服务中的体系(结构):

  • 域:一个域是一套注册中心、配置中心、监控中心、网关等等组成的结构体系,一个域中可以有多个系统。

  • 系统:一个系统相当于一个容器集群,这个容器系统内可以部署多个应用节点。

  • 节点:实现了微服务的轻耦合节点(应用)。

当然,理解这些是不够的架构设计的,我们还需要了解整个日志收集中的每个流程:

  • 日志选择:确定哪些日志类型需要进行收集分析,比如调试,网络等等类型。

  • 日志采集:使用哪种日志组件来作为采集,.NET上常用有Nlog和Log4net。

  • 日志缓冲:使用Kafka或Redios来缓冲日志收集的大量请求。

  • 日志筛选:筛选(过滤)哪些日志类型将要被存储,提前埋点。

  • 日志存储:日志的统一存储,例如ES(Elasticsearch)。

  • 日志检索:日志的快速检索功能,例如ES(Elasticsearch)。

  • 日志展现:日志的UI展现,例如ExceptionLess

二.搭建本地Exceptionless环境

提前先下载好对应的程序包

  • .NET 4.6.1 (如果已安装过VS请忽略)
  • java JDK1.8+  
  • Eleasticsearch
  • Exceptionless

第一步,安装JDK并配置环境变量

第二步,解压elasticsearch,进入bin目录,运行elasticsearch.bat

如果安装过程遇到问题请在网上找对应的处理,这里成功安装之后,在Web服务器上把Web系统搭建起来目录指向wwwroot本机可以通过http://localhost:5000访问,我这里自己修改了IP我通过下面地址在外网访问。

如果可以访问到上面系统说明的Exceptionless 系统部署好了,同时请通过下面方式启动ES

在ES启动的情况下,自己可以在上面Exceptionless 系统中自主注册,添加一个日志服务记录项目,我这里是已经创建好,创建结果如下:

三、代码调用

接口访问过滤器代码

    public class LoggerFilterAttribute : ActionFilterAttribute
    {
        private string MoudleName { get; set; }
        private string MethodName { get; set; }
        /// <summary>
        /// 构造日志类型
        /// </summary>
        /// <param name="Moudle">模块名称</param>
        /// <param name="Method">方法名称</param>
        public LoggerFilterAttribute(string Moudle, string Method)
        {
            this.MoudleName = Moudle;
            this.MethodName = Method;
        }
        /// <summary>
        /// 添加操作日志
        /// </summary>
        /// <param name="actionContext"></param>
        public override void OnActionExecuted(HttpActionExecutedContext actionContext)
        {
            base.OnActionExecuted(actionContext);
            string Token = null;
            try
            {
                ApiResultModel result = new ApiResultModel();
                //取得由API返回的状态代码
                result.StatusCode = actionContext.ActionContext.Response.StatusCode;
                //取得由API返回的资料
                result.Data =  actionContext.ActionContext.Response.Content.ReadAsStringAsync().Result;
                //请求是否成功
                result.IsSucess = actionContext.ActionContext.Response.IsSuccessStatusCode;
                //接口名称
                var actiondescriptor = actionContext.ActionContext.ActionDescriptor;
                //RepairManServices.Controllers.TestDemoController
                string Controller = actionContext.ActionContext.ControllerContext.Controller.ToString();
                var _eLLog = actionContext.ActionContext.Request.RequestUri;              
                if (actionContext.Request.Headers.Authorization != null)
                {
                    var vToken = actionContext.Request.Headers.Authorization.Parameter;
                    AuthRepositorys AuthRe = new AuthRepositorys();
                    var DecToken = AuthRe.DecodeToken(vToken);
                    Token = JsonSerialization.JsonSerializeToString(DecToken);
                }
                var Model = JsonConvert.SerializeObject(actionContext.ActionContext.ActionArguments);
                ExceptionlessClient.Default.CreateLog("[" + MoudleName + "]-[" + MethodName + "]-[" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "]", LogLevel.Info)
                                           .SetSource("[" + MoudleName + "]-[" + MethodName + "]-[" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "]")
                                           .SetMessage("接口参数:" + Model ?? "")
                                           .SetUserIdentity(Token ?? null)
                                           .SetProperty("Response", JsonSerialization.JsonSerializeToString(result))
                                           .AddTags(MoudleName)
                                           .AddTags(MethodName)
                                           .Submit();
            }
            catch (Exception ex)
            {
                ex.ToExceptionless().AddTags(MoudleName)
                                    .AddTags(MethodName)
                                    .SetUserIdentity(Token ?? null)
                                    .Submit();

            }
        }
    }

    /// <summary>
    /// 接口返回参数对象
    /// </summary>
    public class ApiResultModel
    {
        /// <summary>
        /// API请求状态码
        /// </summary>
        public HttpStatusCode StatusCode { get; set; }
        /// <summary>
        /// 请求是否成功
        /// </summary>
        public bool IsSucess { get; set; }
        /// <summary>
        /// 返回结果
        /// </summary>
        public string Data { get; set; }

    }

访问调用

        [HttpPost, Route("api/v1/xxx")]
        [LoggerFilter("xxx", "xxx")]
        public IHttpActionResult GetPLGet(Parameter item)
        {
            var vModel =null;
            return Json<dynamic>(vModel);
        }

通过上面用户对于接口的访问及参数、返回结果都会通过日志方式记录

总结: Exceptionless 还有很多很灵活的用法,这里就不详细的说明了。这里只是一个简单指引,更有价值和自己需要的功能需要你去尝试。希望以上内容对你有所帮助。

Logo

开源、云原生的融合云平台

更多推荐