導航:首頁 > 凈水問答 > local過濾

local過濾

發布時間:2022-02-06 15:06:21

⑴ html5 localstorage 怎麼取存儲條數

1在HTML5本地存儲出現以前,WEB數據存儲的方法已經有很多,比如HTTP Cookie,IE userData,Flash Cookie,Google Gears。其實再說細點,瀏覽WEB的歷史記錄也算是本地存儲的一種方式。到目前為止,HTML5本地存儲方式已經獲得了廣泛的支持,其中支持的瀏覽器包括:IE 8+、FF 3.5+、Safari 4+、Chrome 4+、Opera 10.5+,手機平台包括iPhone 2+和Android 2+。最新的HTML5本地存儲規範文檔,可以在線查看
2http://dev.w3.org/html5/webstorage/
3 HTML5本地存儲的前身就是Cookie,通過使用localStorage對象將WEB數據持久留存在本地。相比較而言,HTML5本地存儲中每個域的存儲大小默認是5M,比起Cookie的4K要大的多。而且存儲和讀取數據的代碼極為簡練:
那麼現在我們是否可以簡單的認為,HTML5存儲已經可以代替Cookie存儲了呢?還有這種新的存儲方式在實際應用中帶來了哪些新的安全風險呢?帶著這些疑問我們來進行下面的討論。
(1) 是否可以代替Cookie
瀏覽器使用Cookie進行身份驗證已經好多年,既然現在localStorage存儲空間那麼大,是否可以把身份驗證的數據直接移植過來呢?目前來看,把身份驗證數據使用localStorage進行存儲還不太成熟。我們知道,通常可以使用XSS漏洞來獲取到Cookie,然後用這個Cookie進行身份驗證登錄。後來為了防止通過XSS獲取Cookie數據,瀏覽器支持了使用HTTPONLY來保護Cookie不被XSS攻擊獲取到。而目前localStorage存儲沒有對XSS攻擊有任何抵禦機制,一旦出現XSS漏洞,那麼存儲在localStorage里的數據就極易被獲取到。
如果一個網站存在XSS漏洞,那麼攻擊者注入如下代碼,就可以獲取使用localStorage存儲在本地的所有信息。

攻擊者也可以簡單的使用localStorage.removeItem(key)和localStorage.clear()對存儲數據進行清空。
(2) 不要存儲敏感信息
從(1)中知道,從遠程攻擊角度來看,localStorage存儲的數據容易被XSS攻擊獲取,所以不宜把身份驗證信息或敏感信息用localStorage存儲。而從本地攻擊角度來看, localStorage自身的存儲方式和存儲時效並不宜存儲敏感信息。
五大瀏覽器現在都已經支持以localStorage方式進行存儲,其中Chrome,Opera,Safari這三款瀏覽器中都有了查看本地存儲的功能模塊。但是不同瀏覽器對localStorage存儲方式還是略有不同的。以下是五大瀏覽器localStorage存儲方式:

通過上面的描述可以看出,除了Opera瀏覽器採用BASE64加密外(BASE64也是可以輕松解密的),其他瀏覽器均採用明文存儲數據。
另一方面,在數據存儲的時效上,localStorage並不會像Cookie那樣可以設置數據存活的時限,只要用戶不主動刪除,localStorage存儲的數據將會永久存在。
根據以上對存儲方式和存儲時效的分析,建議不要使用localStorage方式存儲敏感信息,那怕這些信息進行過加密。
(3) 嚴格過濾輸入輸出
對於本地存儲,為了方便載入數據,常常會把數據存儲在本地,等再次載入時,直接從本地讀取數據顯示在網頁上。在某些情況下,在localStorage存儲中寫入或讀取數據的時候,如果數據沒有經過輸入輸出嚴格過濾,那麼這些數據極可能被作為HTML代碼進行解析,從而產生XSS攻擊。
Twitter就發生過localStorage XSS漏洞。此漏洞觸發的條件是,在Twitter的個人主頁上執行以下存儲代碼後,每次再打開個人主頁時就會彈出/xss/框。
從這段代碼可以看出,Twitter會使用localStorage方法把一些個人數據存儲到本地,每次載入個人主頁面的時候就會從本地存儲獲取數據,然後由於Twitter忽略了對去除數據的嚴格過濾,導致存儲的代碼會被當作HMTL編碼執行,進而發生跨站攻擊。

有關Twitter localStorage XSS 漏洞詳的細信息可以查看:http://www.wooyun.org/bugs/ wooyun-2010-03075。雖然Twitter這個漏洞利用起來非常困難,但它再一次告訴我們:本著一切輸入輸出都是有害的原則,要對數據進行嚴格的輸入輸出過濾。
(4) 容易遭受跨目錄攻擊
localStroage存儲方式不會像Cookie存儲一樣可以指定域中的路徑,在localStroage存儲方式中沒有域路徑的概念。也就是說,如果同一個域下的任意路徑存在XSS漏洞,整個域下存儲的數據在知道存儲名稱的情況下都可以被獲取到。
假設下面兩個鏈接是使用localStorage來存儲數據:

用戶xisigr和xhack各自的blog鏈接雖然屬於同一個域,但卻有不同的路徑,一個路徑為xisigr,另一個路徑為xhack。假設xisigr用戶發現自己的路徑下存在存儲型XSS漏洞,那麼就可以在自己的blog中加入獲取數據代碼,其中核心代碼為localStorage.getItem(「name」)。xhack用戶並不需要登錄blog,他只要訪問http://h.example.com/xisigr,本地存儲數據就會被獲取到。
(5) 容易遭受DNS欺騙攻擊
Google在沒有使用HTML5本地存儲前,是使用Google Gears方式來進行本地存儲的。那時Google Gears就遭到過DNS欺騙攻擊。Google Gears支持離線存儲,可以把Gmail,WordPresss這樣的網站數據以SQLite資料庫的形式存儲下來,以後用戶就可以對存儲的網站數據進行離線讀取或刪除操作。如果攻擊者發動DNS欺騙攻擊,那麼就可以注入本地資料庫,獲取數據或者留下永久的後門,造成對用戶持久的危害。Google Gears所遭受的DNS欺騙攻擊方式在HTML5本地存儲上也是同樣有效的。
(6) 惡意代碼棲息的溫床
在第六點中給出「惡意代碼棲息的溫床」這個小標題有些誇大的效果。其實這里想說的是,HTML5本地存儲在空間上和時間上都將成為今後存儲的趨勢,料想「惡意代碼們」自然會大雁南飛轉移棲息到這張溫床上。

那麼,何為HTML5本地存儲的空間和時間呢?空間這里指的是存儲空間,比起Cookie 4K空間的微小來說,HTML5的localStroage方法默認就可以使瀏覽器存儲5M空間可以說是博大,而Safari瀏覽器可以支持到500M更加讓HTML5存儲霸氣外露。時間上,隨著HTML5技術日漸成熟,除了各大瀏覽器廠商爭先在自己的產品中支持HTML5外,一些大應用軟體廠商也對其信賴有加。比如2011年11月Adobe宣布放棄手機上的FLASH, 而由HTML5全面取而代之。隨著時間的推移,HTML5大步流星的前行速度也會越來越快,也會使得用到HTML5本地存儲的應用會越來越多。
上面從理論上分析了 「惡意代碼棲息的溫床」的可能性。而從實際技術上的可行性也非常簡單。下面是在本地留後門的核心代碼:
以上分析,均出自天融信TopLAB前沿安全實驗室的研究,希望藉此文讓HTML5的本地存儲安全問題得到大家的廣泛重視。HTML5非常精彩,但也存在風險,我們要做的工作還很多。

⑵ MAC地址被過濾怎麼辦

一般MAC地址在網卡中是固定的,當然也有網路高手會想辦法去修改自己的MAC地址。修改自己的MAC地址有兩種方法,一種是硬體修改,另外一種是軟體修改。
硬體的方法就是直接對網卡進行操作,修改保存在網卡的EPROM裡面的MAC地址,通過網卡生產廠家提供的修改程序可以更改存儲器里的地址。那麼什麼叫做EPROM呢?EPROM是電子學中一種存儲器的專業術語,它是可擦寫的,也就是說一張白紙你用鋼筆寫了一遍以後就不能再用橡皮擦去了,而EPROM這張白紙用鉛筆寫後可以再擦去,可以反復改變其中數據的存儲器。
當然軟體修改的方法就相對來說要簡單得多了,在Windows中,網卡的MAC保存在注冊表中,實際使用也是從注冊表中提取的,所以只要修改注冊表就可以改變MAC。Windows 9x中修改:打開注冊表編輯器,在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\
Service\Class\Net\下的0000,0001,0002。

Windows 2000/XP中的修改:同樣打開注冊表編輯器,HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\
Class\4D36E970-E325-11CE-BFC1-08002BE10318 中的0000,0001,0002中的DriverDesc,如果在0000找到,就在0000下面添加字元串變數,命名為「NetworkAddress」,值為要設置的MAC地址,例如:000102030405

完成上述操作後重啟就好了。一般網卡發出的包的源MAC地址並不是網卡本身寫上去的,而是應用程序提供的,只是在通常的實現中,應用程序先從網卡上得到MAC地址,每次發送的時候都用這個MAC作為源MAC而已,而注冊表中的MAC地址是在Windows安裝的時候從網卡中讀入的,只要你的操作系統不重新安裝應該問題不大。

有些人說可以有些人嘗試過沒用,超級兔子據說可以更改這個,你可以試下.

不過目前還沒碰到過這么缺德的人,交錢還來這套,大可以跟房東說.人多的話,交的錢比房東寬頻的月租還多呢

⑶ 求個文本過濾方面的批處理。

@echooff&
for/f"tokens=*"%%iin('ipconfig/all')do(
set"h=%%i"
ifdefinednset/an+=1
ifnot"!h:本地連接:=!"=="!h!"set/an=-2
if"!n!"gtr"0"if"!n!"lss"8"(
set"h=!h:.=!"
set"h=!h::=:!"
set"h=!h::=:!"
for/f"tokens=1,2delims=:"%%jin("!h!")do(
set"#!n!=%%j=%%k"))
if"!n!"=="8"(
if"!h:adapter=!"=="!h!"set#8=DNS_2=!h!
set"n="))
for/L%%iin(1,1,8)doifdefined#%%iecho!#%%i!&set"!#%%i!"
echo/&echo使用時以上面顯示的等號左邊為變數即可,例如IPAddress
echo%ipaddress%
pause

⑷ windows下如何過濾CMD的命令結果(按行號過濾)

@專echo off
setlocal enabledelayedexpansion
set n=&set stop=
for /f "tokens=*" %%a in ('ipconfig') do (
set /a n+=1
if !屬n! equ 5 set stop=1
if !n! gtr 10 set stop=
if !n! equ 12 set stop=1
if !n! gtr 17 set stop=
if not defined stop echo %%a
)
pause

⑸ 如果我的MAC地址被過濾了怎麼辦!

不能通過路由器去另外一個網路,但有辦法能修改你的MAC地址:
1 、在 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0000 、 0001 、 0002 等主鍵下,查找 DriverDesc ,內容為你要修改的網卡的描述,如「 Realtek RTL8029(AS)-based PCI Ethernet Adapter 」。

2 、在其下,添加一個字元串,命名為 NetworkAddress ,其值設為你要的 MAC 地址(注意地址還是連續寫)。如: 00E0DDE0E0E0 。

3 、然後到其下 Ndi\params 中添加一項名為 NetworkAddress 的主鍵,在該主鍵下添加名為 default 的字元串,其值是你要設的 MAC 地址,要連續寫,如: 000000000000 。(實際上這只是設置在後面提到的高級屬性中的「初始值」,實際使用的 MAC 地址還是取決於在第 2 點中提到的 NetworkAddress 參數,這個參數一旦設置後,以後高級屬性中的值就是 NetworkAddress 給出的值而非 default 給出的了。)

4 、在 NetworkAddress 的主鍵下繼續添加名為 ParamDesc 的字元串,其作用為指定 NetworkAddress 主鍵的描述,其值可自己命名,如「 Network Address 」,這樣在網卡的高級屬性中就會出現 Network Address 選項,就是你剛在注冊表中加的新項 NetworkAddress ,以後只要在此修改 MAC 地址就可以了。繼續添加名為 Optional 的字元串,其值設為「 1 」,則以後當你在網卡的高級屬性中選擇 Network Address 項時,右邊會出現「不存在」選項。

5 、重新啟動你的計算機,打開網路鄰居的屬性,雙擊相應網卡項會發現有一個 Network Address 的高級設置項,可以用來直接修改 MAC 地址或恢復原來的地址。

⑹ 陸游器配置中的login local是什麼意思

好好看看吧 不多說了

路由器在計算機網路中有著舉足輕重的地位,是計算機網路的橋梁。通過它不僅可以連通不同的網路,還能選擇數據傳送的路徑,並能阻隔非法的訪問。

路由器的配置對初學者來說,並不是件十分容易的事。現將路由器的一般配置和簡單調試介紹給大家,供朋友們在配置路由器時參考,本文以Cisco2501為例。

Cisco2501有一個乙太網口(AUI)、一個Console口(RJ45)、一個AUX口(RJ45)和兩個同步串口,支持DTE和DCE設備,支持 EIA/TIA-232、 EIA/TIA-449、 V.35 、X.25和EIA-530介面。

一.配置

1.配置乙太網埠

# conf t(從終端配置路由器)

# int e0(指定E0口)

# ip addr ABCD XXXX(ABCD 為乙太網地址,XXXX為子網掩碼)

# ip addr ABCD XXXX secondary(E0口同時支持兩個地址類型。如果第一個為 A類地址,則第二個為B或C類地址)

# no shutdown(激活E0口)

# exit

完成以上配置後,用ping命令檢查E0口是否正常。如果不正常,一般是因為沒有激活該埠,初學者往往容易忽視。用no shutdown命令激活E0口即可。

2.X.25的配置

# conf t

# int S0(指定S0口)

# ip addr ABCD XXXX(ABCD 為乙太網S0 的IP地址,XXXX為子網掩碼)

# encap X25-ABC(封裝X.25協議。ABC指定X.25為DTE或DCE操作,預設為DTE)

# x25 addr ABCD(ABCD為S0的X.25埠地址,由郵電局提供)

# x25 map ip ABCD XXXX br(映射的X.25地址。ABCD為對方路由器(如:S0)的IP 地址,XXXX為對方路由器(如:S0)的X.25埠地址)

# x25 htc X(配置最高雙向通道數。X的取值范圍1-4095,要根據 郵電局實際提供的數字配置)

# x25 nvc X(配置虛電路數,X不可超過郵電局實際提供的數否則將影響數據的正常傳輸)

# exit

S0埠配置完成後,用no shutdown命令激活E0口。如果ping S0埠正常,ping 映射的X.25 IP地址即對方路由器埠IP地址不通,則可能是以下幾種情況引起的:1)本機X.25地址配置錯誤,重新與郵局核對(X.25地址長度為13位);2)本機映射IP地址或X.25地址配置錯誤,重新配置正確;3)對方IP地址或X.25地址配置錯誤;4)本機或對方路由配置錯誤。

能夠與對方通訊,但有丟包現象。出現這種情況,一般有以下幾種可能:1)線路情況不好,或網卡、RJ45插頭接觸不良;2)x25 htc最高雙向通道數X的取值范圍和x25nvc 虛電路數X超出郵電局實際提供的數字。最高雙向通道數和虛電路數這兩個值越大越好,但絕對不能超出郵電局實際提供的數字,否則就會出現丟包現象。

3.專線的配置

# conf t

# intS2(指定S2口)

# ip addr ABCD XXXX(ABCD 為S2 的IP地址,XXXX為子網掩碼)

# exit

專線口配置完成後,用no shutdown命令激活S2口即可。

4.幀中繼的配置

# conf t

# int s0

# ip addr ABCD XXXX (ABCD 為S0 的IP地址,XXXX為子網掩碼)

# encap frante_relay (封裝frante_relay 協議)

# no nrzi_encoding (NRZI=NO)

# frame_relay lmi_type q933a (LMI使用Q933A標准.LMI(Local management Interface) 有3種:ANSI:T1.617、CCITTY:Q933A和Cisco特有的標准)

# fram-relay intf-typ ABC(ABC為幀中繼設備類型,它們分別是DTE設備、DCE交換機或NNI(網路接點介面)支持)

# frame_relay interface_dlci 110 br(配置DLCI(數據鏈路連接標識符))

# frame-relay map ip ABCD XXXX broadcast (建立幀中繼映射。ABCD為對方IP地址,XXXX為本地DLCI號,broadcast允許廣播向前轉發或更新路由)

# no shutdown (激活本埠)

# exit

幀中繼S0埠配置完成後,用ping命令檢查S0口。如果不正常,通常是因為沒有激活該埠,用no shutdown命令激活S0口即可。如果ping S0埠正常,ping 映射的IP地址不正常,則可能是幀中繼交換機或對方配置錯誤,需要綜合排查。

5.配置同步/非同步口(適用於2522)

# conf t

# int s2

# ph asyn (配置S2為非同步口)

# ph sync (配置S2為同步口)

6.動態路由的配置

# conf t

# router eigrp 20 (使用EIGRP路由協議。常用的路由協議有RIP、IGRP、IS-IS等)

# passive-interface serial0 (若S0與X.25相連,則輸入本條指令)

# passive-interface serial1 (若S1與X.25相連,則輸入本條指令)

# network ABCD (ABCD為本機的乙太網地址)

# network XXXX (XXXX為S0的IP地址)

# no auto-summary

# exit

7.靜態路由的配置

# ip router ABCD XXXX YYYY 90 (ABCD為對方路由器的乙太網地址,XXXX 為子網掩碼,YYYY為對方對應的廣域網埠地址)

# dialer-list 1 protocol ip permail

二. 綜合調試

當路由器全部配置完畢後,可進行一次綜合調試。

1.首先將路由器的乙太網口和所有要使用的串口都激活。方法是進入該口,執行no shutdown。

2.將和路由器相連的主機加上預設路由(中心路由器的以太地址)。方法是在Unix系統的超級用戶下執行:router add default XXXX 1(XXXX為路由器的E0口地址)。每台主機都要加預設路由,否則,將不能正常通訊。

3.ping本機的路由器乙太網口,若不通,可能乙太網口沒有激活或不在一個網段上。ping廣域網口,若不通,則沒有加預設路由。ping對方廣域網口,若不通,路由器配置錯誤。ping主機乙太網口,若不通,對方主機沒有加預設路由。

4.在專線卡X.25主機上加網關(靜態路由)。方法是在Unix系統的超級用戶下執行:router add X.X.X.X Y.Y.Y.Y 1(X.X.X.X為對方乙太網地址,Y.Y.Y.Y為對方廣域網地址)。

5.使用Tracert對路由進行跟蹤,以確定不通網段。

⑺ 銳捷校園網認證 IE代理過濾顯示*.local,電腦不能上網。

我也碰到這種情況了,你後來解決了嗎?

⑻ winpcap怎麼設置過濾一個網段

設置過濾器要用到兩個函數,一個是pcap_compile(),另一個是pcao_setfilter()。他們的函數原型如下所示:
int pcap_compile (pcap_t *p, struct bpf_program *fp, char *str, int optimize, bpf_u_int32 netmask)

1、p是一個打開的網路設備的描述符。
2、fp是一個指針,用來存儲一個編譯好的過濾碼。我們需要提前設置 struct bpf_program fcode 在這里使用。
3、str是字元串(以\0結尾),它指定一個字元串性質的過濾描述,通過這個函數把這個描述轉換成可供內部使用的過濾碼。
4、optimize設置是否要進行優化。一般為1。
5、netmask就是我們所打開的設備的netmask,不知道這個怎麼用。一般用d->addresses->netmask這個就可以了。
return: 如果出錯的話,就會返回一個小於0的值。

然後就是設置這個過濾器:
int pcap_setfilter (pcap_t *p, struct bpf_program *fp)

1、p就是一個已經打開的設備的描述符。
2、fp是用上面的函數編譯好的過濾碼,現在把這個過濾碼設置到系統中去。

附上一個代碼:
#define _CRT_SECURE_NO_WARNINGS

#include "pcap.h"

void packet_handler(u_char *user, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data);

int main()
{
pcap_t *cap_ins_des;
pcap_if_t *alldevs;
pcap_if_t *d;
char source[PCAP_BUF_SIZE];
char errbuf[PCAP_ERRBUF_SIZE];
int i;
u_int netmask;
char packet_filter[] = "ip and udp"; // the filter
struct bpf_program fcode; // used in pcap_compile()

/* set the source */
if (pcap_createsrcstr(source, PCAP_SRC_IFLOCAL, NULL, NULL, NULL, errbuf) == -1) {
printf("%s\n", errbuf);
exit(-1);
}
printf("source: %s\n", source);

/* find all devices */
if (pcap_findalldevs_ex(source, NULL, &alldevs, errbuf) == -1) {
printf("%s\n", errbuf);
exit(-1);
}

/* choose one devices */
d = alldevs;
while (d != NULL) {
printf("%s, %s\n", d->name, d->description);
d = d->next;
}
scanf("%d", &i);
d = alldevs;
while (--i)
d = d->next;
printf("selected device: %s\n", d->name);

/* open one device */
cap_ins_des = pcap_open(d->name, 65536, PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, errbuf);
if (cap_ins_des == NULL) {
printf("%s\n", errbuf);
pcap_freealldevs(alldevs);
exit(-1);
}

/* get the netmask, used at compiling the filter */
if (d->addresses != NULL)
netmask = ((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr; /*@#$%^&*!*/
else
netmask = 0xffffff; /* 255.25.255.0 */

// netmask = 0;

/* compile the filter */
if (pcap_compile(cap_ins_des, &fcode, packet_filter, 1, netmask) < 0) {
printf("Error\n");
pcap_freealldevs(alldevs);
exit(-1);
}

/* set the filter */
if (pcap_setfilter(cap_ins_des, &fcode) < 0) {
printf("Error\n");
pcap_freealldevs(alldevs);
exit(-1);
}

pcap_freealldevs(alldevs);

/* start the capture */
pcap_loop(cap_ins_des, 30, packet_handler, NULL);

return 0;
}

void packet_handler(u_char *user, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data)
{
printf("in packet handler\n");
return;
}

⑼ 如何在批處理中過濾包含特定名字的文件

這個方法很多, 簡單點就比較下子串就專好




for/r.%%ain(*.js)do(
setFile=%%a
if"min"neq!屬File:~-6,3!(
ug...
)
)

⑽ 如何快速過濾出一次請求的所有日誌

如何快速過濾出一次請求的所有日誌?
前言
在現網出現故障時,我們經常需要獲取一次請求流程里的所有日誌進行定位。如果請求只在一個線程里處理,則我們可以通過線程ID來過濾日誌,但如果請求包含非同步線程的處理,那麼光靠線程ID就顯得捉襟見肘了。
IoT平台,提供了接收設備上報數據的能力, 當數據到達平台後,平台會進行一些復雜的業務邏輯處理,如數據存儲,規則引擎,數據推送,命令下發等等。由於這個邏輯之間沒有強耦合的關系,所以通常是非同步處理。如何將一次數據上報請求中包含的所有業務日誌快速過濾出來,就是本文要介紹的。
正文
SLF4J日誌框架提供了一個MDC(Mapped Diagnostic Contexts)工具類,谷歌翻譯為映射的診斷上下文,從字面上很難理解,我們可以先實戰一把。
public class Main {
private static final String KEY = "requestId";
private static final Logger logger = LoggerFactory.getLogger(Main.class);

public static void main(String[] args) {
// 入口傳入請求ID
MDC.put(KEY, UUID.randomUUID().toString());

// 列印日誌
logger.debug("log in main thread 1");
logger.debug("log in main thread 2");
logger.debug("log in main thread 3");
// 出口移除請求ID
MDC.remove(KEY);
}
}
我們在main函數的入口調用MDC.put()方法傳入請求ID,在出口調用MDC.remove()方法移除請求ID。配置好log4j2.xml文件後,運行main函數,可以在控制台看到以下日誌輸出:
2018-02-17 13:19:52.606 {requestId=f97ea0fb-2a43-40f4-a3e8-711f776857d0} [main] DEBUG cn.wudashan.Main - log in main thread 1
2018-02-17 13:19:52.609 {requestId=f97ea0fb-2a43-40f4-a3e8-711f776857d0} [main] DEBUG cn.wudashan.Main - log in main thread 2
2018-02-17 13:19:52.609 {requestId=f97ea0fb-2a43-40f4-a3e8-711f776857d0} [main] DEBUG cn.wudashan.Main - log in main thread 3
從日誌中可以明顯地看到花括弧中包含了(映射的)請求ID(requestId),這其實就是我們定位(診斷)問題的關鍵字(上下文)。有了MDC工具,只要在介面或切面植入put()和remove()代碼,在現網定位問題時,我們就可以通過grep requestId=xxx *.log快速的過濾出某次請求的所有日誌。
進階
然而,MDC工具真的有我們所想的這么方便嗎?回到我們開頭,一次請求可能涉及多線程非同步處理,那麼在多線程非同步的場景下,它是否還能正常運作呢?Talk is cheap, show me the code。
public class Main {
private static final String KEY = "requestId";
private static final Logger logger = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
// 入口傳入請求ID
MDC.put(KEY, UUID.randomUUID().toString());
// 主線程列印日誌
logger.debug("log in main thread");
// 非同步線程列印日誌
new Thread(new Runnable() {
@Override
public void run() {
logger.debug("log in other thread");
}
}).start();
// 出口移除請求ID
MDC.remove(KEY);
}
}
代碼里我們新起了一個非同步線程,並在匿名對象Runnable的run()方法列印日誌。運行main函數,可以在控制台看到以下日誌輸出:
2018-02-17 14:05:43.487 {requestId=e6099c85-72be-4986-8a28-de6bb2e52b01} [main] DEBUG cn.wudashan.Main - log in main thread
2018-02-17 14:05:43.490 {} [Thread-1] DEBUG cn.wudashan.Main - log in other thread
不幸的是,請求ID在非同步線程里不列印了。這是怎麼回事呢?要解決這個問題,我們就得知道MDC的實現原理。由於篇幅有限,這里就暫不詳細介紹,MDC之所以在非同步線程中不生效是因為底層採用ThreadLocal作為數據結構,我們調用MDC.put()方法傳入的請求ID只在當前線程有效。感興趣的小夥伴可以自己深入一下代碼細節。
知道了原理那麼解決這個問題就輕而易舉了,我們可以使用裝飾器模式,新寫一個MDCRunnable類對Runnable介面進行一層裝飾。在創建MDCRunnable類時保存當前線程的MDC值,在執行run()方法時再將保存的MDC值拷貝到非同步線程中去。代碼實現如下:
public class MDCRunnable implements Runnable {
private final Runnable runnable;
private final Map<String, String> map;
public MDCRunnable(Runnable runnable) {
this.runnable = runnable;
// 保存當前線程的MDC值
this.map = MDC.getCopyOfContextMap();
}
@Override
public void run() {
// 傳入已保存的MDC值
for (Map.Entry<String, String> entry : map.entrySet()) {
MDC.put(entry.getKey(), entry.getValue());
}
// 裝飾器模式,執行run方法
runnable.run();
// 移除已保存的MDC值
for (Map.Entry<String, String> entry : map.entrySet()) {
MDC.remove(entry.getKey());
}
}

}
接著,我們需要對main函數里創建的Runnable實現類進行裝飾:
public class Main {
private static final String KEY = "requestId";
private static final Logger logger = LoggerFactory.getLogger(Main.class);
private static final ExecutorService EXECUTOR = Executors.newSingleThreadExecutor();
public static void main(String[] args) {
// 入口傳入請求ID
MDC.put(KEY, UUID.randomUUID().toString());
// 主線程列印日誌
logger.debug("log in main thread");
// 非同步線程列印日誌,用MDCRunnable裝飾Runnable
new Thread(new MDCRunnable(new Runnable() {
@Override
public void run() {
logger.debug("log in other thread");
}
})).start();
// 非同步線程池列印日誌,用MDCRunnable裝飾Runnable
EXECUTOR.execute(new MDCRunnable(new Runnable() {
@Override
public void run() {
logger.debug("log in other thread pool");
}
}));
EXECUTOR.shutdown();
// 出口移除請求ID
MDC.remove(KEY);
}
}
執行main函數,將會輸出以下日誌:
2018-03-04 23:44:05.343 {requestId=5ee2a117-e090-41d8-977b-cef5dea09d34} [main] DEBUG cn.wudashan.Main - log in main thread
2018-03-04 23:44:05.346 {requestId=5ee2a117-e090-41d8-977b-cef5dea09d34} [Thread-1] DEBUG cn.wudashan.Main - log in other thread
2018-03-04 23:44:05.347 {requestId=5ee2a117-e090-41d8-977b-cef5dea09d34} [pool-2-thread-1] DEBUG cn.wudashan.Main - log in other thread pool
Congratulations!經過我們的努力,最終在非同步線程和線程池中都有requestId列印了!
總結
本文講述了如何使用MDC工具來快速過濾一次請求的所有日誌,並通過裝飾器模式使得MDC工具在非同步線程里也能生效。有了MDC,再通過AOP技術對所有的切面植入requestId,就可以將整個系統的任意流程的日誌過濾出來。使用MDC工具,在開發自測階段,可以極大地節省定位問題的時間,提升開發效率;在運維維護階段,可以快速地收集相關日誌信息,加快分析速度。

閱讀全文

與local過濾相關的資料

熱點內容
印度沒葯樹脂豐胸嗎 瀏覽:159
小米的空氣凈化器的作用是什麼 瀏覽:654
景區污水處理方案公司 瀏覽:633
特恩潔ro反滲透膜怎麼更換 瀏覽:496
可寶空氣凈化器的濾芯如何保養 瀏覽:55
污水處理廠一般工資多少上海 瀏覽:119
光敏樹脂硬度等級 瀏覽:351
污水處理產生的有毒氣體有哪些 瀏覽:702
離子交換動力學實驗 瀏覽:565
飲水機插座沒電怎麼辦 瀏覽:678
養生壺為什麼不長水垢 瀏覽:549
污水處理廠水質超標應急 瀏覽:427
某城鎮污水處理 瀏覽:284
別墅污水提升泵應該建到哪 瀏覽:986
陽離子交換膜製作方法 瀏覽:297
漢川市鄉鎮自來水水垢多 瀏覽:33
水處理微生物學論文3500字 瀏覽:228
選擇蒸餾瓶應考慮什麼因素6 瀏覽:456
空氣凈化器怎麼清洗水箱 瀏覽:418
二氧化氯污水處理流程 瀏覽:731