<noframes id="bhrfl"><address id="bhrfl"></address>

    <address id="bhrfl"></address>

    <noframes id="bhrfl"><address id="bhrfl"><th id="bhrfl"></th></address>

    <form id="bhrfl"><th id="bhrfl"><progress id="bhrfl"></progress></th></form>

    <em id="bhrfl"><span id="bhrfl"></span></em>

    全部
    常見問題
    產品動態
    精選推薦

    Spring Boot中使用log4j實現http請求日志入mongodb

    管理 管理 編輯 刪除

    之前在《使用AOP統一處理Web請求日志》一文中介紹了如何使用AOP統一記錄web請求日志?;舅悸肥峭ㄟ^aop去切web層的controller實現,獲取每個http的內容并通過log4j將日志內容寫到應用服務器的文件系統中。

    但是當我們在集群中部署應用之后,應用請求的日志被分散記錄在了不同應用服務器的文件系統上,這樣分散的存儲并不利于我們對日志內容的檢索。解決日志分散問題的方案多種多樣,本文思路以在[《使用AOP統一處理Web請求日志》一文的基礎之上,擴展log4j實現將日志寫入MongoDB。

    #準備工作

    可以先拿《使用AOP統一處理Web請求日志》的結果工程為基礎,進行后續的實驗改造。該工程實現了一個簡單的REST接口,一個對web層的切面,并在web層切面前后記錄http請求的日志內容。

    #通過自定義appender實現

    思路:log4j提供的輸出器實現自Appender接口,要自定義appender輸出到MongoDB,只需要繼承AppenderSkeleton類,并實現幾個方法即可完成。

    #引入mongodb的驅動

    在pom.xml中引入下面依賴


    <dependency>
        <groupId>org.mongodb</groupId>
        <artifactId>mongodb-driver</artifactId>
        <version>3.2.2</version>
    </dependency>
    
    
    
    
    
    
    

    #實現MongoAppender

    編寫MongoAppender類繼承AppenderSkeleton,實現如下:


    public class MongoAppender  extends AppenderSkeleton {
    
        private MongoClient mongoClient;
        private MongoDatabase mongoDatabase;
        private MongoCollection<BasicDBObject> logsCollection;
    
        private String connectionUrl;
        private String databaseName;
        private String collectionName;
    
        @Override
        protected void append(LoggingEvent loggingEvent) {
    
            if(mongoDatabase == null) {
                MongoClientURI connectionString = new MongoClientURI(connectionUrl);
                mongoClient = new MongoClient(connectionString);
                mongoDatabase = mongoClient.getDatabase(databaseName);
                logsCollection = mongoDatabase.getCollection(collectionName, BasicDBObject.class);
            }
            logsCollection.insertOne((BasicDBObject) loggingEvent.getMessage());
    
        }
    
        @Override
        public void close() {
            if(mongoClient != null) {
                mongoClient.close();
            }
        }
    
        @Override
        public boolean requiresLayout() {
            return false;
        }
    
        // 省略getter和setter
    
    }
    
    
    
    
    
    
    • 定義MongoDB的配置參數,可通過log4j.properties配置:
    • connectionUrl:連接mongodb的串
    • databaseName:數據庫名
    • collectionName:集合名
    • 定義MongoDB的連接和操作對象,根據log4j.properties配置的參數初始化:
    • mongoClient:mongodb的連接客戶端
    • mongoDatabase:記錄日志的數據庫
    • logsCollection:記錄日志的集合
    • 重寫append函數:
    • 根據log4j.properties中的配置創建mongodb連接
    • LoggingEvent提供getMessage()函數來獲取日志消息
    • 往配置的記錄日志的collection中插入日志消息
    • 重寫close函數:關閉mongodb的

    #配置log4j.properties

    設置名為mongodb的logger:

    • 記錄INFO級別日志
    • appender實現為com.didispace.log.MongoAppende
    • mongodb連接地址:mongodb://localhost:27017
    • mongodb數據庫名:logs
    • mongodb集合名:logs_request
    log4j.logger.mongodb=INFO, mongodb
    # mongodb輸出
    log4j.appender.mongodb=com.didispace.log.MongoAppender
    log4j.appender.mongodb.connectionUrl=mongodb://localhost:27017
    log4j.appender.mongodb.databaseName=logs
    log4j.appender.mongodb.collectionName=logs_request
    
    
    
    
    
    
    
    

    #切面中使用mongodb logger

    修改后的代碼如下,主要做了以下幾點修改:

    • logger取名為mongodb的
    • 通過getBasicDBObject函數從HttpServletRequest和JoinPoint對象中獲取請求信息,并組裝成BasicDBObject
    • getHeadersInfo函數從HttpServletRequest中獲取header信息
    • 通過logger.info(),輸出BasicDBObject對象的信息到mongodb
    @Aspect
    @Order(1)
    @Component
    public class WebLogAspect {
    
        private Logger logger = Logger.getLogger("mongodb");
    
        @Pointcut("execution(public * com.didispace.web..*.*(..))")
        public void webLog(){}
    
        @Before("webLog()")
        public void doBefore(JoinPoint joinPoint) throws Throwable {
            // 獲取HttpServletRequest
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            // 獲取要記錄的日志內容
            BasicDBObject logInfo = getBasicDBObject(request, joinPoint);
            logger.info(logInfo);
        }
    
    
        private BasicDBObject getBasicDBObject(HttpServletRequest request, JoinPoint joinPoint) {
            // 基本信息
            BasicDBObject r = new BasicDBObject();
            r.append("requestURL", request.getRequestURL().toString());
            r.append("requestURI", request.getRequestURI());
            r.append("queryString", request.getQueryString());
            r.append("remoteAddr", request.getRemoteAddr());
            r.append("remoteHost", request.getRemoteHost());
            r.append("remotePort", request.getRemotePort());
            r.append("localAddr", request.getLocalAddr());
            r.append("localName", request.getLocalName());
            r.append("method", request.getMethod());
            r.append("headers", getHeadersInfo(request));
            r.append("parameters", request.getParameterMap());
            r.append("classMethod", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
            r.append("args", Arrays.toString(joinPoint.getArgs()));
            return r;
        }
    
        private Map<String, String> getHeadersInfo(HttpServletRequest request) {
            Map<String, String> map = new HashMap<>();
            Enumeration headerNames = request.getHeaderNames();
            while (headerNames.hasMoreElements()) {
                String key = (String) headerNames.nextElement();
                String value = request.getHeader(key);
                map.put(key, value);
            }
            return map;
        }
    
    }
    
    
    

    #代碼示例

    本文的相關例子可以查看下面倉庫中的chapter4-2-5目錄:

    請登錄后查看

    CRMEB 最后編輯于2025-01-22 16:45:06

    快捷回復
    回復
    回復
    回復({{post_count}}) {{!is_user ? '我的回復' :'全部回復'}}
    排序 默認正序 回復倒序 點贊倒序

    {{item.user_info.nickname ? item.user_info.nickname : item.user_name}} LV.{{ item.user_info.bbs_level }}

    作者 管理員 企業

    {{item.floor}}# 同步到gitee 已同步到gitee {{item.is_suggest == 1? '取消推薦': '推薦'}}
    {{item.is_suggest == 1? '取消推薦': '推薦'}}
    沙發 板凳 地板 {{item.floor}}#
    {{item.user_info.title || '暫無簡介'}}
    附件

    {{itemf.name}}

    {{item.created_at}}  {{item.ip_address}}
    打賞
    已打賞¥{{item.reward_price}}
    {{item.like_count}}
    {{item.showReply ? '取消回復' : '回復'}}
    刪除
    回復
    回復

    {{itemc.user_info.nickname}}

    {{itemc.user_name}}

    回復 {{itemc.comment_user_info.nickname}}

    附件

    {{itemf.name}}

    {{itemc.created_at}}
    打賞
    已打賞¥{{itemc.reward_price}}
    {{itemc.like_count}}
    {{itemc.showReply ? '取消回復' : '回復'}}
    刪除
    回復
    回復
    查看更多
    打賞
    已打賞¥{{reward_price}}
    893
    {{like_count}}
    {{collect_count}}
    添加回復 ({{post_count}})

    相關推薦

    快速安全登錄

    使用微信掃碼登錄
    {{item.label}} 加精
    {{item.label}} {{item.label}} 板塊推薦 常見問題 產品動態 精選推薦 首頁頭條 首頁動態 首頁推薦
    取 消 確 定
    回復
    回復
    問題:
    問題自動獲取的帖子內容,不準確時需要手動修改. [獲取答案]
    答案:
    提交
    bug 需求 取 消 確 定
    打賞金額
    當前余額:¥{{rewardUserInfo.reward_price}}
    {{item.price}}元
    請輸入 0.1-{{reward_max_price}} 范圍內的數值
    打賞成功
    ¥{{price}}
    完成 確認打賞

    微信登錄/注冊

    切換手機號登錄

    {{ bind_phone ? '綁定手機' : '手機登錄'}}

    {{codeText}}
    切換微信登錄/注冊
    暫不綁定
    亚洲欧美字幕
    CRMEB客服

    CRMEB咨詢熱線 咨詢熱線

    400-8888-794

    微信掃碼咨詢

    CRMEB開源商城下載 源碼下載 CRMEB幫助文檔 幫助文檔
    返回頂部 返回頂部
    CRMEB客服