Bootstrap

JRT调试优化

JRT提供的是业务脚本化,在Windows下开发时候有问题时候可以借助System.out.prinln输出信息到tomcat的控制台来调试程序。在Linux上发布后看输出就得到catalina.out里,这样虽然也能用xftp连着看日志,但是有个致命问题是:部署环境有很多用户在使用,输出日志的话日志太多了,根本难以辅助跟踪问题(开发环境只有一个人用就好查日志)。

演示视频

为了简化JRT跟踪问题,设计新的日志跟踪体系:

在这里插入图片描述

在这里插入图片描述

在业务基类里共提供zw、zwg、zwu、zwk几个写日志的方法。其中zw输出日志到相同IP的调试端,zwg输出到登录相同组的调试端、zwu输出到相同登录用户的调试端、zwk输出到指定key的调试端。最常用的是zw,自己操作网站功能来调试程序、然后是zwk适用于外部接口调用的逻辑、操作地方不在本机、也没有会话和组。zwu和zwg适合有些操作只有用户才能重现的时候写日志。

跟踪日志会话的对象:


package JRT.Core.Debug;

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedDeque;

/**
 * 调试会话对象
 */
public class DebugSession {
    /**
     * 前端最后查询时间,长时间没被查询的会话就去除会话
     */
    public long LastSelectTime;

    /**
     * 调试会话唯一键,用IP-用户-组构成
     */
    private String SessionKey;

    /**
     * 按自定义键写日志
     */
    public String SelfKey;

    /**
     * 按IP写日志
     */
    public String IpAddr;

    /**
     * 按GroupID写日志
     */
    public String GroupID;

    /**
     * 按UserID写日志
     */
    public String UserID;

    /**
     * 日志缓存队列
     */
    public ConcurrentLinkedDeque<String> LogQueue;
}

日志管理器:


package JRT.Core.Debug;

import java.util.*;
import java.util.concurrent.ConcurrentLinkedDeque;

import JRT.Core.Debug.DebugSession;

/**
 * 管理调试信息
 */
public class DebugManager {
    /**
     * 存储调试会话
     */
    private static HashMap<String, DebugSession> SessionMap=new HashMap<>();

    /**
     * 按IP地址写日志
     * @param ipAddr ip
     * @param obj 对象
     * @param title 标题
     * @throws Exception
     */
    public static void ZW(String ipAddr,Object obj,String title) throws Exception
    {
        boolean hasOut=false;
        //使用迭代器遍历
        Iterator<HashMap.Entry<String, DebugSession>> iterator = SessionMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, DebugSession> entry = iterator.next();
            //两分钟不活动的会话就移除
            if (JRT.Core.Util.TimeParser.GetTimeInMillis()-entry.getValue().LastSelectTime>120000) {
                iterator.remove();
                continue;
            }
            //按IP写日志
            DebugSession one=entry.getValue();
            if(one.IpAddr.equals(ipAddr))
            {
                String logStr="[Usr:"+one.UserID+"#Grp:"+one.GroupID+"#"+JRT.Core.Util.TimeParser.GetNowTimeStr()+"]#   "+title+"="+ JRT.Core.Util.JsonUtil.Object2Json(obj);
                one.LogQueue.addLast(logStr);
                System.out.println(logStr);
                hasOut=true;
            }
        }
        if(hasOut==false)
        {
            System.out.println(JRT.Core.Util.TimeParser.GetNowTimeStr()+"]#   "+title+"="+ JRT.Core.Util.JsonUtil.Object2Json(obj));
        }
    }

    /**
     * 按自定义Key写日志
     * @param selfKey 自定义Key
     * @param obj 对象
     * @param title 标题
     * @throws Exception
     */
    public static void ZWK(String selfKey,Object obj,String title) throws Exception
    {
        boolean hasOut=false;
        //使用迭代器遍历
        Iterator<HashMap.Entry<String, DebugSession>> iterator = SessionMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, DebugSession> entry = iterator.next();
            //两分钟不活动的会话就移除
            if (JRT.Core.Util.TimeParser.GetTimeInMillis()-entry.getValue().LastSelectTime>120000) {
                iterator.remove();
                continue;
            }
            //按IP写日志
            DebugSession one=entry.getValue();
            if(one.SelfKey.equals(selfKey))
            {
                String logStr="[Usr:"+one.UserID+"#Grp:"+one.GroupID+"#"+JRT.Core.Util.TimeParser.GetNowTimeStr()+"]#   "+title+"="+ JRT.Core.Util.JsonUtil.Object2Json(obj);
                one.LogQueue.addLast(logStr);
                System.out.println(logStr);
                hasOut=true;
            }
        }
        if(hasOut==false)
        {
            System.out.println(JRT.Core.Util.TimeParser.GetNowTimeStr()+"]#   "+title+"="+ JRT.Core.Util.JsonUtil.Object2Json(obj));
        }
    }

    /**
     * 按登录组写日志
     * @param groupID 组
     * @param obj 对象
     * @param title 标题
     * @throws Exception
     */
    public static void ZWG(String groupID,Object obj,String title) throws Exception
    {
        boolean hasOut=false;
        //使用迭代器遍历
        Iterator<HashMap.Entry<String, DebugSession>> iterator = SessionMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, DebugSession> entry = iterator.next();
            //两分钟不活动的会话就移除
            if (JRT.Core.Util.TimeParser.GetTimeInMillis()-entry.getValue().LastSelectTime>120000) {
                iterator.remove();
                continue;
            }
            //按组写日志
            DebugSession one=entry.getValue();
            if(one.GroupID.equals(groupID))
            {
                String logStr="[Usr:"+one.UserID+"#Grp:"+one.GroupID+"#"+JRT.Core.Util.TimeParser.GetNowTimeStr()+"]#   "+title+"="+ JRT.Core.Util.JsonUtil.Object2Json(obj);
                one.LogQueue.addLast(logStr);
                System.out.println(logStr);
                hasOut=true;
            }
        }
        if(hasOut==false)
        {
            System.out.println(JRT.Core.Util.TimeParser.GetNowTimeStr()+"]#   "+title+"="+ JRT.Core.Util.JsonUtil.Object2Json(obj));
        }
    }

    /**
     * 按用户写日志
     * @param userID 用户
     * @param obj 对象
     * @param title 标题
     * @throws Exception
     */
    public static void ZWU(String userID,Object obj,String title) throws Exception
    {
        boolean hasOut=false;
        //使用迭代器遍历
        Iterator<HashMap.Entry<String, DebugSession>> iterator = SessionMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, DebugSession> entry = iterator.next();
            //两分钟不活动的会话就移除
            if (JRT.Core.Util.TimeParser.GetTimeInMillis()-entry.getValue().LastSelectTime>120000) {
                iterator.remove();
                continue;
            }
            //按用户写日志
            DebugSession one=entry.getValue();
            if(one.UserID.equals(userID))
            {
                String logStr="[Usr:"+one.UserID+"#Grp:"+one.GroupID+"#"+JRT.Core.Util.TimeParser.GetNowTimeStr()+"]#   "+title+"="+ JRT.Core.Util.JsonUtil.Object2Json(obj);
                one.LogQueue.addLast(logStr);
                System.out.println(logStr);
                hasOut=true;
            }
        }
        if(hasOut==false)
        {
            System.out.println(JRT.Core.Util.TimeParser.GetNowTimeStr()+"]#   "+title+"="+ JRT.Core.Util.JsonUtil.Object2Json(obj));
        }
    }

    /**
     * 开启调试会话
     * @param ipAddr ip地址
     * @param userID 用户
     * @param groupID 组
     * @param selfKey 自定义键
     */
    public static void StartDebugSession(String ipAddr,String userID,String groupID,String selfKey)
    {
        //构造会话
        String key=ipAddr+"-"+userID+"-"+groupID;
        DebugSession session=new DebugSession();
        session.SelfKey=selfKey;
        session.IpAddr=ipAddr;
        session.UserID=userID;
        session.GroupID=groupID;
        session.LastSelectTime= JRT.Core.Util.TimeParser.GetTimeInMillis();
        session.LogQueue=new ConcurrentLinkedDeque<String>();
        SessionMap.put(key,session);
        //移除不活动会话
        CheckOutTimeSession();
    }

    /**
     * 停止调试会话
     * @param ipAddr ip地址
     * @param userID 用户
     * @param groupID 组
     */
    public static void StopDebugSession(String ipAddr,String userID,String groupID)
    {
        //构造会话
        String key=ipAddr+"-"+userID+"-"+groupID;
        if(SessionMap.containsKey(key))
        {
            SessionMap.remove(key);
        }
        //移除不活动会话
        CheckOutTimeSession();
    }

    /**
     * 得到日志数据
     * @param ipAddr ip地址
     * @param userID 用户
     * @param groupID 组
     * @return 日志数据
     * @throws Exception
     */
    public static String GetLogs(String ipAddr,String userID,String groupID) throws Exception
    {
        String key=ipAddr+"-"+userID+"-"+groupID;
        HashMap retMap=new HashMap();
        List<String> logList=new ArrayList<>();
        if(SessionMap.containsKey(key))
        {
            DebugSession one=SessionMap.get(key);
            one.LastSelectTime= JRT.Core.Util.TimeParser.GetTimeInMillis();
            while (one.LogQueue.size()>0)
            {
                logList.add(one.LogQueue.poll());
            }

        }
        retMap.put("Logs",logList);
        retMap.put("SessionNum",SessionMap.size());
        return JRT.Core.Util.JsonUtil.Object2Json(retMap);
    }

    /**
     * 查询长时间没活动的会话清除
     */
    public static void CheckOutTimeSession()
    {
        try {
            //使用迭代器安全地删除元素
            Iterator<HashMap.Entry<String, DebugSession>> iterator = SessionMap.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, DebugSession> entry = iterator.next();
                //两分钟不活动的会话就移除
                if (JRT.Core.Util.TimeParser.GetTimeInMillis() - entry.getValue().LastSelectTime > 120000) {
                    iterator.remove();
                }
            }
        }
        catch (Exception ex)
        {
            JRT.Core.Util.LogUtils.WriteExceptionLog("检测超时的调试会话",ex);
        }
    }
}

业务基类提供的写日志方法:

/**
     * 按照客户端IP地址输出日志
     * @param obj 对象
     * @throws Exception
     */
    public void zw(Object obj) throws Exception
    {
        DebugManager.ZW(JRTContext.GetClientIP(Request),obj,"obj");
    }

    /**
     * 按照客户端IP地址输出日志
     * @param obj 对象
     * @param title 标题
     * @throws Exception
     */
    public void zw(Object obj,String title) throws Exception
    {
        DebugManager.ZW(JRTContext.GetClientIP(Request),obj,title);
    }

    /**
     * 按照自定义键输出日志
     * @param selfkey 自定义键
     * @param obj 对象
     * @param title 标题
     * @throws Exception
     */
    public void zwk(String selfkey,Object obj,String title) throws Exception
    {
        if(selfkey==null)
        {
            return;
        }
        DebugManager.ZWK(selfkey,obj,title);
    }

    /**
     * 按照自定义键输出日志
     * @param selfkey 自定义键
     * @param obj 对象
     * @throws Exception
     */
    public void zwk(String selfkey,Object obj) throws Exception
    {
        if(selfkey==null)
        {
            return;
        }
        DebugManager.ZWK(selfkey,obj,"obj");
    }

    /**
     * 按照登录的GroupID输出日志
     * @param obj 对象
     * @throws Exception
     */
    public void zwg(Object obj) throws Exception
    {
        DebugManager.ZWG(UserLogin().GroupID,obj,"obj");
    }

    /**
     * 按照登录的GroupID输出日志
     * @param obj 对象
     * @param title 标题
     * @throws Exception
     */
    public void zwg(Object obj,String title) throws Exception
    {
        DebugManager.ZWG(UserLogin().GroupID,obj,title);
    }

    /**
     * 按照登录的UserID输出日志
     * @param obj 对象
     * @throws Exception
     */
    public void zwu(Object obj) throws Exception
    {
        DebugManager.ZWU(UserLogin().UserID,obj,"obj");
    }

    /**
     * 按照登录的UserID输出日志
     * @param obj 对象
     * @param title 标题
     * @throws Exception
     */
    public void zwu(Object obj,String title) throws Exception
    {
        DebugManager.ZWU(UserLogin().UserID,obj,title);
    }
;