由于需要,學習了Oracle日志分析工具LogMiner的使用,在此記錄一下: 1,確定你的Oracle安裝的目錄,下面用%ORALCE_HOME%表示。 2,必須以DBA角色登錄,命令如下 SQL>sqlplus /nolog SQL>conn sys/manager@wymis as sysdba 3,(如果第一次做日志分析)安裝LogMiner SQL> @%ORALCE_HOME%\ora90\rdbms\admin\dbmslm.sql SQL> @%ORALCE_HOME%\ora90\rdbms\admin\dbmslmd.sql 4,設置UTL_FILE_DIR值,這個值表示存放日志分析相關文件的目錄,設置方法可以到Oracle的企業管理器下面設置,這個值的例子如c:\log,注意,最后沒有\符號。設置完后,需要重新啟動數據庫。 5,生成數據字典 SQL> execute dbms_logmnr_d.build(- > dictionary_filename => 'logminer_dict.dat',- > dictionary_location => 'c:\import'); 注意上面每行代碼后有一個'-'符號,表示輸入還沒有結束。 注意,dictionary_location的值必須與第4步中UTL_FILE_DIR的值一樣。 6,創建要分析的日志文件列表, 創建列表 SQL> EXECUTE dbms_logmnr.add_logfile(- LogFileName=>' e:\Oracle\oradata\sxf\redo01.log',- Options=>dbms_logmnr.new); 添加其他日志文件到列表 SQL> EXECUTE dbms_logmnr.add_logfile( LogFileName=>' e:\Oracle\oradata\sxf\redo02.log', Options=>dbms_logmnr.addfile); 注意,LogFileName的值可以到相應的數據庫實例文件夾下面的實例獲得。 7,使用LogMiner進行日志分析 SQL> execute dbms_logmnr.start_logmnr(- > dictfilename => 'c:\import\logminer_dict.dat',- > starttime => to_date('2001-9-18 00:00:00','YYYY-MM-DD HH24:MI:SS'),- > endtime => to_date('2009-10-30 00:00:00','YYYY-MM-DD HH24:MI:SS')); 注意,這里的starttime和endtime的范圍必須是你的日志文件涉及的范圍。如果實在拿不準,可以不用這兩個參數。 8,分析結果 LogMiner分析的結果存放在v$LogMnr_Contents表里面。具體的分析,網上有很多好的文章,就不再寫了。 再轉一篇比較好的文章,來自http://www.oracle.com.cn/viewthread.php?tid=22975的 robertmao_2003 作為Oracle DBA,我們有時候需要追蹤數據誤刪除或用戶的惡意操作情況,此時我們不僅需要查出執行這些操作的數據庫賬號,還需要知道操作是由哪臺客戶端(IP地址 等)發出的。針對這些問題,一個最有效實用而又低成本的方法就是分析Oracle數據庫的日志文件。本文將就Oracle日志分析技術做深入探討。 一、如何分析即LogMiner解釋 從目前來看,分析Oracle日志的唯一方法就是使用Oracle公司提供的LogMiner來進行, Oracle數據庫的所有更改都記錄在日志中,但是原始的日志信息我們根本無法看懂,而LogMiner就是讓我們看懂日志信息的工具。從這一點上看,它 和tkprof差不多,一個是用來分析日志信息,一個則是格式化跟蹤文件。通過對日志的分析我們可以實現下面的目的: 1、查明數據庫的邏輯更改; 2、偵察并更正用戶的誤操作; 3、執行事后審計; 4、執行變化分析。 不僅如此,日志中記錄的信息還包括:數據庫的更改歷史、更改類型(INSERT、UPDATE、DELETE、DDL等)、更改對應的SCN號、以及執行 這些操作的用戶信息等,LogMiner在分析日志時,將重構等價的SQL語句和UNDO語句(分別記錄在V$LOGMNR_CONTENTS視圖的 SQL_REDO和SQL_UNDO中)。這里需要注意的是等價語句,而并非原始SQL語句,例如:我們最初執行的是“delete a where c1 <>'cyx';”,而LogMiner重構的是等價的6條DELETE語句。所以我們應該意識到V$LOGMNR_CONTENTS視圖中 顯示的并非是原版的現實,從數據庫角度來講這是很容易理解的,它記錄的是元操作,因為同樣是“delete a where c1 <>'cyx';”語句,在不同的環境中,實際刪除的記錄數可能各不相同,因此記錄這樣的語句實際上并沒有什么實際意義,LogMiner重 構的是在實際情況下轉化成元操作的多個單條語句。 另外由于Oracle重做日志中記錄的并非原始的對象(如表以及其中的列)名稱,而只是它們在Oracle數據庫中的內部編號(對于表來說是它們在數據庫 中的對象ID,而對于表中的列來說,對應的則是該列在表中的排列序號:COL 1, COL 2 等),因此為了使LogMiner重構出的SQL語句易于識別,我們需要將這些編號轉化成相應的名稱,這就需要用到數據字典(也就說LogMiner本身 是可以不用數據字典的,詳見下面的分析過程),LogMiner利用DBMS_LOGMNR_D.BUILD()過程來提取數據字典信息。 LogMiner包含兩個PL/SQL包和幾個視圖: 1、dbms_logmnr_d包,這個包只包括一個用于提取數據字典信息的過程,即dbms_logmnr_d.build()過程。 2、dbms_logmnr包,它有三個過程: add_logfile(name varchar2, options number) - 用來添加/刪除用于分析的日志文件; start_logmnr(start_scn number, end_scn number, start_time number,end_time number, dictfilename varchar2, options number) - 用來開啟日志分析,同時確定分析的時間/SCN窗口以及確認是否使用提取出來的數據字典信息。 end_logmnr() - 用來終止分析會話,它將回收LogMiner所占用的內存。 與LogMiner相關的數據字典。 1、v$logmnr_dictionary,LogMiner可能使用的數據字典信息,因logmnr可以有多個字典文件,該視圖用于顯示這方面信息。 2、v$logmnr_parameters,當前LogMiner所設定的參數信息。 3、v$logmnr_logs,當前用于分析的日志列表。 4、v$logmnr_contents,日志分析結果。 二、Oracle9i LogMiner的增強: 1、支持更多數據/存儲類型:鏈接/遷移行、CLUSTER表操作、DIRECT PATH插入以及DDL操作。在V$LOGMNR_CONTENTS的SQL_REDO中可以看到DDL操作的原句(CREATE USER除外,其中的密碼將以加密的形式出現,而不是原始密碼)。如果TX_AUDITING初始化參數設為TRUE,則所有操作的數據庫賬號將被記錄。 2、提取和使用數據字典的選項:現在數據字典不僅可以提取到一個外部文件中,還可以直接提取到重做日志流中,它在日志流中提供了操作當時的數據字典快照,這樣就可以實現離線分析。 3、允許對DML操作按事務進行分組:可以在START_LOGMNR()中設置COMMITTED_DATA_ONLY選項,實現對DML操作的分組,這樣將按SCN的順序返回已經提交的事務。 4、支持SCHEMA的變化:在數據庫打開的狀態下,如果使用了LogMiner的DDL_DICT_TRACKING選項,Oracle9i的 LogMiner將自動對比最初的日志流和當前系統的數據字典,并返回正確的DDL語句,并且會自動偵察并標記當前數據字典和最初日志流之間的差別,這樣 即使最初日志流中所涉及的表已經被更改或者根本已經不存在,LogMiner同樣會返回正確的DDL語句。 5、在日志中記錄更多列信息的能力:例如對于UPDATE操作不僅會記錄被更新行的情況,還可以捕捉更多前影信息。 6、支持基于數值的查詢:Oracle9i LogMiner在支持原有基于元數據(操作、對象等)查詢的基礎上,開始支持基于實際涉及到的數據的查詢。例如涉及一個工資表,現在我們可以很容易地查 出員工工資由1000變成2000的原始更新語句,而在之前我們只能選出所有的更新語句。 三、Oracle8i/9i的日志分析過程 LogMiner只要在實例起來的情況下都可以運行,LogMiner使用一個字典文件來實現Oracle內部對象名稱的轉換,如果沒有這個字典文件,則直接顯示內部對象編號,例如我們執行下面的語句: delete from "C"."A" where "C1" = ‘gototop’ and ROWID = 'AAABg1AAFAAABQaAAH'; 如果沒有字典文件,LogMiner分析出來的結果將是: delete from "UNKNOWN"."OBJ# 6197" where "COL 1" = HEXTORAW('d6a7d4ae') and ROWID = 'AAABg1AAFAAABQaAAH'; 如果想要使用字典文件,數據庫至少應該出于MOUNT狀態。然后執行dbms_logmnr_d.build過程將數據字典信息提取到一個外部文件中。下面是具體分析步驟: 1、確認設置了初始化參數:UTL_FILE_DIR,并確認Oracle對改目錄擁有讀寫權限,然后啟動實例。示例中UTL_FILE_DIR參數如下: SQL> show parameter utl NAME? ?? ?? ?? ?? ?? ?? ?? ? TYPE? ?? ???VALUE ------------------------ ----------- ------------------------------ utl_file_dir? ?? ?? ?? ?? ???string? ?? ?/data6/cyx/logmnr 這個目錄主要用于存放dbms_logmnr_d.build過程所產生的字典信息文件,如果不用這個,則可以不設,也就跳過下面一步。 2、生成字典信息文件: exec dbms_logmnr_d.build(dictionary_filename =>' dic.ora',dictionary_location => '/data6/cyx/logmnr'); 其中dictionary_location指的是字典信息文件的存放位置,它必須完全匹配UTL_FILE_DIR的值,例如:假設 UTL_FILE_DIR=/data6/cyx/logmnr/,則上面這條語句會出錯,只因為UTL_FILE_DIR后面多了一個“/”,而在很多 其它地方對這一“/”是不敏感的。 dictionary_filename指的是放于字典信息文件的名字,可以任意取。當然我們也可以不明確寫出這兩個選項,即寫成: exec dbms_logmnr_d.build('dic.ora','/data6/cyx/logmnr'); 如果你第一步的參數沒有設,而直接開始這一步,Oracle會報下面的錯誤: ERROR at line 1: ORA-01308: initialization parameter utl_file_dir is not set ORA-06512: at "SYS.DBMS_LOGMNR_D", line 923 ORA-06512: at "SYS.DBMS_LOGMNR_D", line 1938 ORA-06512: at line 1 需要注意的是,在oracle817 for Windows版中會出現以下錯誤: 14:26:05 SQL> execute dbms_logmnr_d.build('oradict.ora','c:\oracle\admin\ora\log'); BEGIN dbms_logmnr_d.build('oradict.ora','c:\oracle\admin\ora\log'); END; * ERROR at line 1: ORA-06532: Subscript outside of limit ORA-06512: at "SYS.DBMS_LOGMNR_D", line 793 ORA-06512: at line 1 解決辦法: 編輯"$ORACLE_HOME/rdbms/admindbmslmd.sql"文件,把其中的 TYPE col_desc_array IS VARRAY(513) OF col_description; 改成: TYPE col_desc_array IS VARRAY(700) OF col_description; 保存文件,然后執行一遍這個腳本: 15:09:06 SQL> @c:\oracle\ora81\rdbms\admin\dbmslmd.sql Package created. Package body created. No errors. Grant succeeded. 然后重新編譯DBMS_LOGMNR_D包: 15:09:51 SQL> alter package DBMS_LOGMNR_D compile body; Package body altered. 之后重新執行dbms_logmnr_d.build即可: 15:10:06 SQL> execute dbms_logmnr_d.build('oradict.ora','c:\oracle\admin\ora\log'); PL/SQL procedure successfully completed. 3、添加需要分析的日志文件 SQL>exec dbms_logmnr.add_logfile( logfilename=>' /data6/cyx/rac1arch/arch_1_197.arc', options=>bms_logmnr.new); PL/SQL procedure successfully completed. 這里的options選項有三個參數可以用: NEW - 表示創建一個新的日志文件列表 ADDFILE - 表示向這個列表中添加日志文件,如下面的例子 REMOVEFILE - 和addfile相反。 SQL> exec dbms_logmnr.add_logfile( logfilename=>' /data6/cyx/rac1arch/arch_2_86.arc', options=>bms_logmnr.addfile); PL/SQL procedure successfully completed. 4、當你添加了需要分析的日志文件后,我們就可以讓LogMiner開始分析了: SQL> exec dbms_logmnr.start_logmnr(dictfilename=>'/data6/cyx/logmnr/dic.ora'); PL/SQL procedure successfully completed. 如果你沒有使用字典信息文件(此時我們只需要啟動實例就可以了),那么就不需要跟dictfilename參數: SQL> exec dbms_logmnr.start_logmnr(); PL/SQL procedure successfully completed. 當然dbms_logmnr.start_logmnr()過程還有其它幾個用于定義分析日志時間/SCN窗口的參數,它們分別是: STARTSCN / ENDSCN - 定義分析的起始/結束SCN號, STARTTIME / ENDTIME - 定義分析的起始/結束時間。 例如下面的過程將只分析從 '2003-09-21 09:39:00'到'2003-09-21 09:45:00'這段時間的日志: SQL> exec dbms_logmnr.start_logmnr(dictfilename=>'/data6/cyx/logmnr/dic.ora' , - starttime => '2003-09-21 09:39:00',endtime => '2003-09-21 09:45:00'); PL/SQL procedure successfully completed. 上面過程第一行結尾的“-”表示轉行,如果你在同一行,則不需要。我們可以看到有效日志的時間戳: SQL> select distinct timestamp from v$logmnr_contents; TIMESTAMP ------------------- 2003-09-21 09:40:02 2003-09-21 09:42:39 這里需要注意的是,因為我之前已經設置NLS_DATE_FORMAT環境變量,所以上面的日期可以直接按這個格式寫就行了,如果你沒有設,則需要使用to_date函數來轉換一下。 SQL> !env|grep NLS NLS_LANG=american_america.zhs16cgb231280 NLS_DATE_FORMAT=YYYY-MM-DD HH24:MI:SS ORA_NLS33=/oracle/oracle9/app/oracle/product/9.2.0/ocommon/nls/admin/data 使用to_date的格式如下: exec dbms_logmnr.start_logmnr(dictfilename=>'/data6/cyx/logmnr/dic.ora',- starttime => to_date('2003-09-21 09:39:00','YYYY-MM-DD HH24:MI:SS'),- endtime => to_date('2003-09-21 09:45:00','YYYY-MM-DD HH24:MI:SS')); STARTSCN 和ENDSCN參數使用方法類似。 5、好了,在上面的過程執行結束之后,我們就可以通過訪問與LogMiner相關的幾個視圖來提取我們需要的信息了。其中在v$logmnr_logs中 可以看到我們當前分析的日志列表,如果數據庫有兩個實例(即OPS/RAC),在v$logmnr_logs中會有兩個不同的THREAD_ID。 而真正的分析結果是放在v$logmnr_contents中,這里面有很多信息,我們可以根據需要追蹤我們感興趣的信息。后面我將單獨列出來講常見的追蹤情形。 6、全部結束之后,我們可以執行dbms_logmnr.end_logmnr過程退出LogMiner分析過程,你也可以直接退出SQL*PLUS,它會自動終止。 四、如何利用LogMiner分析Oracle8的日志文件 雖然說LogMiner是Oracle8i才推出來,但我們同樣可以用它來分析Oracle8的日志文件,只不過稍微麻煩了一點,并且有一定的限制,下面是具體做法: 我們首先復制Oracle8i的$ORACLE_HOME/rdbms/admin/dbmslmd.sql腳本到Oracle8數據庫所在主機的同樣目 錄;這個腳本用于創建dbms_logmnr_d包(注意,Oracle9i中還將創建dbms_logmnr包),如果是8.1.5腳本名字為 dbmslogmnrd.sql。然后在Oracle8的數據庫上運行這個腳本,之后使用dbms_logmnr_d.build過程創建字典信息文件。 現在我們就可以把Oracle8的歸檔日志連同這個字典信息文件復制到Oracle8i數據庫所在的主機上,之后在Oracle8i數據庫中從上面分析過 程的第三步開始分析Oracle8的日志,不過 dbms_logmnr.start_logmnr()中使用的是Oracle8的字典信息文件。 按照我前面所說的那樣,如果不是字典文件,我們則可以直接將Oracle8的歸檔日志復制到Oracle8i數據庫所在主機,然后對它進行分析。 其實這里涉及到了一個跨平臺使用LogMiner的問題,筆者做過試驗,也可以在Oracle9i中來分析Oracle8i的日志。但這些都是有所限制的,主要表現在: 1、LogMiner所使用的字典文件必須和所分析的日志文件是同一個數據庫所產生的,并且該數據庫的字符集應和執行LogMiner數據庫的相同。這很好理解,如果不是同一個數據庫所產生就不存在對應關系了。 2、生成日志的數據庫硬件平臺和執行LogMiner數據庫的硬件平臺要求一致,操作系統版本可以不一致。筆者做試驗時(如果讀者有興趣可以到我網站http://www.ncn.cn上下載試驗全過程,因為太長就不放在這里了),所用的兩個數據庫操作系統都是Tru64 UNIX,但一個是 V5.1A,另一個則是V4.0F。如果操作系統不一致則會出現下面的錯誤: ORA-01284: file /data6/cyx/logmnr/arch_1_163570.arc cannot be opened ORA-00308: cannot open archived log '/data6/cyx/logmnr/arch_1_163570.arc' ORA-27048: skgfifi: file header information is invalid ORA-06512: at "SYS.DBMS_LOGMNR", line 63 ORA-06512: at line 1 五、分析v$logmnr_contents 前面我們已經知道了LogMiner的分析結果是放在v$logmnr_contents中,這里面有很多信息,我們可以根據需要追蹤我們感興趣的信息。那么我們通常感興趣的有哪些呢? 1、追蹤數據庫結構變化情況,即DDL操作,如前所述,這個只有Oracle9i才支持: SQL> select timestamp,sql_redo from v$logmnr_contents2 where upper(sql_redo) like '%CREATE%'; TIMESTAMP ------------------- SQL_REDO ------------------------- 2003-09-21 10:01:55 create table t (c1 number); 2、追蹤用戶誤操作或惡意操作: 例如我們現實中有這樣需求,有一次我們發現一位員工通過程序修改了業務數據庫信息,把部分電話的收費類型改成免費了,現在就要求我們從數據庫中查出到底是 誰干的這件事?怎么查?LogMiner提供了我們分析日志文件的手段,其中v$logmnr_contents的SESSION_INFO列包含了下面 的信息: login_username=NEW_97 client_info= OS_username=oracle8 Machine_name=phoenix1 OS_terminal=ttyp3 OS_process_id=8004 OS_program name=sqlplus@phoenix1 (TNS V1-V3) 雖然其中信息已經很多了,但在我們的業務數據庫中,程序是通過相同的login_username登錄數據庫的,這樣單從上面的信息是很難判斷的。 不過我們注意到,因為公司應用服務器不是每個人都有權限在上面寫程序的,一般惡意程序都是直接通過他自己的PC連到數據庫的,這就需要一個準確的定位。 IP追蹤是我們首先想到的,并且也滿足我們的實際要求,因為公司內部IP地址分配是統一管理的,能追蹤到IP地址我們就可以準確定位了。但從面的 SESSION_INFO中我們并不能直接看到IP,不過我們還是有辦法的,因為這個SESSION_INFO里面的內容其實是日志從V$SESSION 視圖里提取的,我們可以在生產數據庫中創建一個追蹤客戶端IP地址的觸發器: create or replace trigger on_logon_trigger after logon on database begin dbms_application_info.set_client_info(sys_context('userenv', 'ip_address')); end; / 現在,我們就可以在V$SESSION視圖的CLIENT_INFO列中看到新登錄的客戶端IP地址了。那么上面的提出的問題就可以迎刃而解了。假如被更新的表名為HMLX,我們就可以通過下面的SQL來找到所需信息: SQL > select session_info ,sql_redo from v$logmnr_contents 2 where upper(operation) = 'UPDATE'??and upper(sql_redo) like '%HMLX%' 3 / SESSION_INFO ----------------------------------------- SQL_REDO ----------------------------------------- login_username=C client_info=10.16.98.26 OS_username=sz-xjs-chengyx Machine_name =GDTEL\SZ-XJS-CHENGYX update "C"."HMLX" set "NAME" = 'free' where "NAME" = 'ncn.cn' and ROWID = 'AAABhTAA FAAABRaAAE'; 好了,到此為止,這篇文章就要結束了,如果讀者朋友還有什么疑問,可以登錄我的個人網站(www.ncn.cn)來獲得最新消息,也可以通過MSN(gototop_ncn@hotmail.com)直接和我聯系。 六、參考資料: 1、Technical White Paper Oracle9i LogMiner 2、Metalink文檔:How to Setup LogMiner(文檔ID:111886.1)
文章來源:http://localhost/wp2/?p=50