摘要:使用記錄系統日志在構建一個系統時,我們常常需要記錄當前發生的事情,以及記錄特定消息出現的頻率,根據出現頻率的高低來決定消息的排列信息,幫助我們找到重要的信息。常見記錄日志的方法有兩種將日志記錄在文件中。
使用Redis記錄系統日志
在構建一個系統時,我們常常需要記錄當前發生的事情,以及記錄特定消息出現的頻率,根據出現頻率的高低來決定消息的排列信息,幫助我們找到重要的信息。
常見記錄日志的方法有兩種:
將日志記錄在文件中。隨時時間流逝將日志行不斷添加到文件里面,并在一段時間后創建新的日志文件。這種方式為每個不同的服務創建不同的日志,由于服務輪換日志的機制不同,也缺少一種能夠方便地聚合所有日志并對其進行處理的常見方法。
syslog服務。這種服務幾乎運行在Linux服務器和Unix服務器的514號TCP端口和UDP端口上。syslog接受其他程序發來的日志消息,并將這個消息路由至存儲在硬盤上的各個日志文件,并且負責舊日志的輪換和刪除工作。甚至還可以將日志消息轉發給其他服務來做進一步的處理。
syslog的轉發功能可以將不同的日志分別存儲在同一臺服務器的多個文件里面,對于長時間地記錄日志非常有幫助。我們可以使用redis來存儲與時間緊密相關的日志,從而在功能上替代那些需要在短期內被存儲的syslog消息。
1. 最新日志我們需要使用 “列表” 來存儲最新日志文件,使用LPUSH命令將日志消息推入到列表中。如果我們之后想要查看已有日志消息的話,可以使用LRANGE命令來拉取列表中的消息。
我們還要命名不同的日志消息隊列,根據問題的嚴重性對日志進行分級。
import time import logging import unittest import redis from datetime import datetime # 設置一個字典,將大部分日志的安全級別映射為字符串 SEVERITY = { logging.DEBUG: "debug", logging.INFO: "info", logging.WARNING: "warning", logging.ERROR: "error", logging.CRITICAL: "critical", } SEVERITY.update((name, name) for name in SEVERITY.values()) """ 存儲最新日志文件,命名不同的日志消息隊列,根據問題的嚴重性對日志進行分級 @param {object} @param {string} name 消息隊列名稱 @param {string} message 消息 @param {string} severity安全級別 @param {object} pip pipline """ def logRecent(conn, name, message, severity=logging.INFO, pip=None): # 將日志的安全級別轉換為簡單的字符串 severity = str(SEVERITY.get(severity, severity)).lower() # 創建要保存的redis列表key destination = "recent:%s:%s"%(name, severity) # 將當前時間加到消息里面,用于記錄消息的發送時間 message = time.asctime() + " " + message # 使用流水線來將通信往返次數降低為一次 pipe = pip or conn.pipeline() # 將消息添加到列表的最前面 pipe.lpush(destination, message) # 修剪日志列表,讓它只包含最新的100條消息 pipe.ltrim(destination, 0, 99) pipe.execute()2. 常見日志
我們需要記錄較高頻率出現的日志,使用“有序集合”,將消息作為成員,消息出現的頻率為成員的分值。
為了確保我們看到的常見消息都是最新的,需要以每小時一次的頻率對消息進行輪換,并在輪換日志的時候保留上一個小時記錄的常見消息,從而防止沒有任何消息存儲的情況出現。
""" 記錄較高頻率出現的日志,每小時一次的頻率對消息進行輪換,并在輪換日志的時候保留上一個小時記錄的常見消息 @param {object} @param {string} name 消息隊列名稱 @param {string} message 消息 @param {string} severity安全級別 @param {int} timeout 執行超時時間 """ def logCommon(conn, name, message, severity=logging.INFO, timeout=5): # 設置日志安全級別 severity = str(SEVERITY.get(severity, severity)).lower() # 負責存儲近期的常見日志消息的鍵 destination = "common:%s:%s"%(name, severity) # 每小時需要輪換一次日志,需要記錄當前的小時數 start_key = destination + ":start" pipe = conn.pipeline() end = time.time() + timeout while time.time() < end: try: # 對記錄當前小時數的鍵進行監聽,確保輪換操作可以正常進行 pipe.watch(start_key) # 當前時間 now = datetime.utcnow().timetuple() # 取得當前所處的小時數 hour_start = datetime(*now[:4]).isoformat() existing = pipe.get(start_key) # 開始事務 pipe.multi() # 如果這個常見日志消息記錄的是上個小時的日志 if existing and existing < hour_start: # 將這些舊的常見日志歸檔 pipe.rename(destination, destination + ":last") pipe.rename(start_key, destination + ":pstart") # 更新當前所處的小時數 pipe.set(start_key, hour_start) elif not existing: pipe.set(start_key, hour_start) # 記錄日志出現次數 pipe.zincrby(destination, message) # 將日志記錄到日志列表中,調用excute logRecent(pipe, name, message, severity, pipe) return except redis.exceptions.WatchError: continue
測試
測試代碼如下:
class TestLog(unittest.TestCase): def setUp(self): import redis self.conn = redis.Redis(db=15) self.conn.flushdb def tearDown(self): self.conn.flushdb() del self.conn print print def testLogRecent(self): import pprint conn = self.conn print "Let"s write a few logs to the recent log" for msg in xrange(5): logRecent(conn, "test", "this is message %s"%msg) recent = conn.lrange("recent:test:info", 0, -1) print "The current recent message log has this many message:", len(recent) print "Those message include:" pprint.pprint(recent[:10]) self.assertTrue(len(recent) >= 5) def testLogCommon(self): import pprint conn = self.conn print "Let"s writ a few logs to the common log" for count in xrange(1, 6): for i in xrange(count): logCommon(conn, "test", "message-%s"%count) common = conn.zrevrange("common:test:info", 0, -1, withscores=True) print "The current common message log has this many message:", len(common) print "Those common message include:" pprint.pprint(common) self.assertTrue(len(common) >= 5) if __name__ == "__main__": unittest.main()
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/40910.html
摘要:包括在內的很多軟件都使用這種方法來記錄日志。在這一節中,我們將介紹如何使用來存儲于時間緊密相關的日志,從而在功能上替代那些需要在短期內被存儲的消息。 上一篇文章:Python--Redis實戰:第四章:數據安全與性能保障:第8節:關于性能方面的注意事項下一篇文章:Python--Redis實戰:第五章:使用Redis構建支持程序:第2節:計數器和統計數據 在構建應用程序和服務的過程中...
摘要:持久化到中反向代理的負載均衡基于的集群搭建如何實現從中訂閱消息轉發到客戶端的擴展是阻塞式,使用訂閱發布模式時,會導致整個進程進入阻塞。緩存是用于解決高并發場景下系統的性能及穩定性問題的銀彈。 showImg(https://segmentfault.com/img/bVYE6k?w=900&h=385); Redis 是由意大利程序員 Salvatore Sanfilippo(昵稱:a...
閱讀 1978·2019-08-30 15:54
閱讀 3602·2019-08-29 13:07
閱讀 3129·2019-08-29 12:39
閱讀 1793·2019-08-26 12:13
閱讀 1552·2019-08-23 18:31
閱讀 2164·2019-08-23 18:05
閱讀 1852·2019-08-23 18:00
閱讀 1048·2019-08-23 17:15