CAT和ELK简单接入

CAT监控

参考

  • CAT(Central Application Tracking)是基于Java开发的实时应用监控平台
  • 参考源代码 部署 C#客户端

CAT支持的监控消息类型包括:

  • Transaction 适合记录跨越系统边界的程序访问行为,比如远程调用,数据库调用,也适合执行时间较长的业务逻辑监控,Transaction用来记录一段代码的执行时间和次数。
  • Event 用来记录一件事发生的次数,比如记录系统异常,它和transaction相比缺少了时间的统计,开销比transaction要小。
  • Heartbeat 表示程序内定期产生的统计信息, 如CPU%, MEM%, 连接池状态, 系统负载等。
  • Metric 用于记录业务指标、指标可能包含对一个指标记录次数、记录平均值、记录总和,业务指标最低统计粒度为1分钟。
  • Trace 用于记录基本的trace信息,类似于log4j的info信息,这些信息仅用于查看一些相关信息

    需要注意的是除了Transaction其他消息类型都是原子的不能再嵌套

    接入

  • 服务端启动好后,在client端配置文件client.xml,文件路径/data/appdatas/cat/client.xml,server.ip,server.port写服务端的地址

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <?xml version="1.0" encoding="utf-8"?>
    <config mode="client" enabled="true" queue-size="123">
    <!--logEnabled enabled="true"></logEnabled-->
    <!-- 配置Domain ID-->
    <domain id="Mango" enabled="true" max-message-size="1000"/>
    <servers>
    <!-- 配置CAT服务器地址-->
    <server ip="10.2.6.98" port="2280" http-port="8080"></server>
    </servers>
    </config>
  • 调用CAT API埋点。示例代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Org.Unidal.Cat.Message;
    using Org.Unidal.Cat;
    using System.Threading;
    namespace ConsoleApplication1
    {
    class Program
    {
    static void Main(string[] args)
    {
    ITransaction transaction = null; ;
    try
    {
    transaction = Cat.NewTransaction("Order", "Cash");
    // Do your business...
    Cat.LogEvent("City", "Shanghai");
    transaction.Status = CatConstants.SUCCESS;
    }
    catch (Exception ex)
    {
    Cat.LogError(ex);
    transaction.SetStatus(ex);
    // You may need to re-throw exception ex out.
    }
    finally
    {
    transaction.Complete();
    // 程序退出前睡一会儿。使得CAT客户端有时间发出最后一批消息到网络。
    Thread.Sleep(1000);
    }
    }
    }
    }
  • 在BaseController中定义拦截方法,注意一定要在action执行之后设置CAT的状态为Complete

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    using Mango.Infrastructure.Config;
    using Mango.Infrastructure.Log;
    using Mango.Infrastructure.Serialization;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    namespace Mango.Online.BaseClass
    {
    public class BaseController : Controller
    {
    private static ISerializer _iSerializer = new JsonSerializer();
    private CatHelper _CatHelper = new CatHelper();
    /// <summary>
    /// Action执行前
    /// </summary>
    /// <param name="filterContext"></param>
    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
    #region cat
    var request = filterContext.RequestContext.HttpContext.Request;
    var response = filterContext.RequestContext.HttpContext.Response;
    string url = request.Url != null ? request.Url.ToString() : "Empty";
    string urlRefer = request.UrlReferrer != null ? request.UrlReferrer.ToString() : "Entry";
    string agent = request.UserAgent;
    string statusCode = response.StatusCode.ToString();
    Dictionary<string, string> spots = new Dictionary<string, string>();
    spots.Add("URL", url);
    spots.Add("URLRefer", urlRefer);
    spots.Add("Agent", agent);
    spots.Add("StatusCode", statusCode);
    _CatHelper.PVTrace("URL", url, spots);
    #endregion
    }
    /// <summary>
    /// Action执行后
    /// </summary>
    /// <param name="filterContext"></param>
    protected override void OnActionExecuted(ActionExecutedContext filterContext)
    {
    _CatHelper.TraceEnd();
    }
    /// <summary>
    /// Exception过滤
    /// </summary>
    /// <param name="filterContext"></param>
    protected override void OnException(ExceptionContext filterContext)
    {
    if (!filterContext.ExceptionHandled && !ApplicationConfig.DebugModel)
    {
    #region cat
    var request = filterContext.RequestContext.HttpContext.Request;
    string url = request.Url != null ? request.Url.ToString() : "Empty";
    _CatHelper.ExceptionTrace("Request", url, filterContext.Exception);
    _CatHelper.TraceEnd();
    #endregion
    //Log&Rdirect
    LoggerHelper.Error("参数_filterContext", filterContext.Exception);
    filterContext.HttpContext.Response.Redirect("~/Home/Error");
    }
    }
    }
    }

ELK日志监控

基本架构

ELK简单架构图片

  • 分布式日志监控,目前采用Log4Net的UdpAppender和Log4J的TCP可以收集所有能与中控服务器通信机器的所有日志
  • Elasticsearch负责搜索日志筛选数据,Logstash负责采集数据进行简单处理,Kibana负责用户界面展示和报表
  • 利用Log4NET的Appender来进行传输,所以配置和Log4NET原本配置很类似

    使用

  • 先在站点配置日志输出的地方添加Appender

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <appender name="UdpAppender" type="log4net.Appender.UdpAppender">
    <param name="Encoding" value="utf-8" />
    <RemoteAddress value="10.10.12.46" />
    <RemotePort value="5960" />
    <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%level %date{ISO8601} %logger [%thread] [%C] [%property{requestId}] [%property{log4net:HostName}] %message %exception %newline" />
    </layout>
    </appender>
    <logger name="LogStash">
    <level value="Monitor" />
    <appender-ref ref="UdpAppender" />
    </logger>
  • 其中10.10.12.46地址是Logstash实例所在的地址,上线需要指定,在LoggerHelper中获取LogStash实例

    private static readonly log4net.ILog LogStash = log4net.LogManager.GetLogger(“LogStash”);

  • 目前是将Logstash的方法和本地写文件方法写在一起,也可以单独抽离

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public static void Info(string msg, Exception ex = null)
    {
    if (ex != null)
    {
    LogInfo.Info(msg, ex);
    LogStash.Info(msg, ex);
    }
    else
    {
    LogInfo.Info(msg);
    }
    }
  • 记录的内容根据写的pattern进行正则匹配,通过Logstash输出到elasticsearch实例进行索引

    简单展示

  • 索引后的数据保存在elasticsearch中,可以通过kibana进行关联,用户可以通过搜索框直接进行查询了,查询基于lucence基本语法,右上角的时间图标可以限定查询的时间范围
    下图查看的是今天错误名称带有“火车票的”
    Kibana截图
  • Kibana的Visualize功能可以根据保存的语句生成你想要的图表,比如这个月的错误数量折线图
    报表