Rem drv: Rem Rem $Header: trace_log_pkgbody.sql 03-aug-2006.22:59:14 sthiruna Exp $ Rem Rem trace_log_pkgbody.sql Rem Rem Copyright (c) 2004, 2006, Oracle. All rights reserved. Rem Rem NAME Rem trace_log_pkgbody.sql - Rem Rem DESCRIPTION Rem Rem Rem NOTES Rem Rem Rem MODIFIED (MM/DD/YY) Rem sthiruna 07/31/06 - Copying 10.2.0.3 Config Standard changes from Rem EMCORE_MAIN_LINUX Rem niramach 02/28/06 - Add get_context_type function to get the current Rem context type. Rem gsbhatia 07/01/05 - New repmgr header impl Rem jsadras 03/04/05 - purge procedure Rem jsadras 10/25/04 - Add 10G Error 12899 Rem rpinnama 08/02/04 - Log using autonomous txn Rem jsadras 02/26/04 - jsadras_trace_create Rem jsadras 02/26/04 - emdw_log pkg body Rem jsadras 02/26/04 - Created Rem CREATE OR REPLACE PACKAGE BODY EMDW_LOG AS -- -- Internal PROCEDURE to set the Boolean variables -- PROCEDURE set_boolean_variables IS BEGIN p_is_error_set := ( lerror <= p_ctx_arr.trace_level) ; p_is_warn_Set := ( lwarn <= p_ctx_arr.trace_level) ; p_is_info_set := ( linfo <= p_ctx_arr.trace_level) ; p_is_debug_set := ( ldebug <= p_ctx_arr.trace_level) ; p_is_tracing_set := p_is_error_set ; END ; -- -- Internal PROCEDURE to set Default context Values -- PROCEDURE set_default_context_values IS BEGIN p_ctx_arr.context_type_id := 0 ; p_ctx_arr.context_type := p_default_context_type ; p_ctx_arr.trace_level := LOFF ; END ; -- -- Internal procedure to get context id for the context type -- FUNCTION get_context_id(v_context_type IN VARCHAR2) RETURN NUMBER IS l_context_type_id NUMBER ; BEGIN SELECT context_type_id INTO l_context_type_id FROM emdw_trace_config WHERE context_type = upper(v_context_type ) ; RETURN(l_context_type_id) ; EXCEPTION WHEN OTHERS THEN RETURN (-1) ; END ; --Purpose : Returns the current context type. FUNCTION get_context_type RETURN VARCHAR2 IS BEGIN RETURN p_ctx_arr.context_type; END; -- -- PURPOSE: -- Sets the context type for current session to v_context_type, -- if v_context_type does not exist then default context is chosen -- Sets the trace level for session based on the values in emdw_trace_config table -- PROCEDURE set_context(v_context_type IN VARCHAR2 := p_default_context_type, v_context_identifier IN VARCHAR2 := null, v_oms_host IN VARCHAR2 := null ) IS BEGIN BEGIN p_refresh_enabled := TRUE ; SELECT context_type_id,context_type,trace_level,null,null INTO p_ctx_arr FROM emdw_trace_config WHERE context_type = upper(v_context_type ) ; EXCEPTION WHEN NO_DATA_FOUND THEN BEGIN SELECT context_type_id,context_type,trace_level,null,null INTO p_ctx_arr FROM emdw_trace_config WHERE context_type = p_default_context_type ; EXCEPTION WHEN OTHERS THEN set_default_context_values ; END ; WHEN OTHERS THEN set_default_context_values ; END ; set_boolean_variables ; p_ctx_arr.context_identifier := substr(v_context_identifier,1,30); p_ctx_arr.oms_host := substr(v_oms_host,1,100); EXCEPTION WHEN OTHERS THEN set_default_context_values ; set_boolean_variables ; END set_context; -- -- PURPOSE: -- Gets the trace level for current context from DB -- PROCEDURE refresh_context IS BEGIN IF p_refresh_enabled THEN set_context(p_ctx_arr.context_type,p_ctx_arr.context_identifier,p_ctx_arr.oms_host) ; END IF ; END refresh_context; -- -- PURPOSE -- Creates a record in emdw_trace_config table for the context type -- Errors are trapped -- Sets current context to v_context_type, this will be useful so developer -- can call create_context and then start logging without calling set_context -- if context_type already exists then the trace level is set for that. -- PROCEDURE create_context(v_context_type in VARCHAR2, v_trace_level in NUMBER := LOFF) IS BEGIN INSERT INTO emdw_trace_config (context_type_id,context_type,trace_level,create_date,last_update_date) VALUES (emdw_trace_context_type_id_seq.nextval, upper(v_context_type), v_trace_level, sysdate, sysdate ) ; set_context(v_context_type) ; EXCEPTION -- --It is possible the dup_val_on_index is due to context_type_id --which can be caused by some resetting the sequence --In this case no_data_found exception will be raised by set_trace_level --No need for elaborate logic to handle this rare situation -- WHEN dup_val_on_index THEN IF v_trace_level between LERROR and LDEBUG then set_trace_level(v_context_type,v_trace_level) ; END IF ; END ; -- --PURPOSE --Delete the trace data records for the context type --Delete the trace config record for the context type -- PROCEDURE delete_context(v_context_type in VARCHAR2) IS BEGIN --Stop Trace Generation for Future, --currently running programs will continue to --generate trace data for the context type set_trace_level(v_context_type,LOFF); -- Delete trace data for the context type purge(v_context_type) ; DELETE emdw_trace_config WHERE context_type = upper(v_context_type) ; COMMIT ; END ; -- --PURPOSE -- Set the trace level for the context type -- if context type is not specified, then the trace level is set for all -- context types -- PROCEDURE set_trace_level(v_context_type IN VARCHAR2 := NULL, v_trace_level IN NUMBER :=LOFF) IS BEGIN IF v_trace_level BETWEEN LOFF AND LDEBUG THEN UPDATE emdw_trace_config SET trace_level = v_trace_level, last_update_date = sysdate WHERE context_type = nvl(upper(v_context_type ),context_type) ; IF SQL%NOTFOUND THEN RAISE NO_DATA_FOUND ; END IF ; refresh_context ; ELSE RAISE subscript_outside_limit ; END IF ; END set_trace_level; -- --PURPOSE -- This procedure sets the trace level for current session only -- It disables refresh_context ,so table values will not be picked up -- by calls to refresh_context. The trace_level for current session -- can be changed only by calls to this procedure or set_context -- PROCEDURE set_session_trace_level(v_trace_level in NUMBER) IS BEGIN IF v_trace_level BETWEEN LOFF AND LDEBUG THEN p_ctx_arr.trace_level := v_trace_level ; set_boolean_variables ; p_refresh_enabled := FALSE ; END IF ; END ; -- --PURPOSE --Log the message into the trace_data table based on the following. --1.Messages are logged only if the log_level specified is less than or equal to the -- Current trace level. --2.Messages greater than 1000 Characters will be truncated and stored as seperate records --3.Error conditions are Logged under tracer context type, if they cannot be logged -- then they are ignored --4.Invalid log levels (<0 and >4) are ignored -- PROCEDURE log( v_log_level in NUMBER, v_log_message IN VARCHAR2, v_module IN VARCHAR2 := null ) IS PRAGMA AUTONOMOUS_TRANSACTION; bigstring_exception1 EXCEPTION ; PRAGMA exception_init(BigString_EXCEPTION1,-1401) ; bigstring_exception2 EXCEPTION ; PRAGMA exception_init(BigString_EXCEPTION2,-12899) ; l_string VARCHAR2(1000) ; l_full_length NUMBER := 0 ; l_iteration NUMBER := 0 ; BEGIN IF v_log_level <= p_ctx_arr.trace_level and (v_log_level between LERROR and LDEBUG) THEN BEGIN INSERT INTO emdw_trace_data (context_type_id,context_identifier, log_level, log_timestamp, log_message,module, oms_host) VALUES (p_ctx_arr.context_type_id,p_ctx_arr.context_identifier, v_log_level, systimestamp, v_log_message,substr(v_module,1,100), p_ctx_arr.Oms_Host) ; EXCEPTION WHEN bigstring_exception1 or bigstring_exception2 THEN l_full_length := length(v_log_message) ; WHILE ( l_iteration*1000 <= l_full_length) LOOP l_String := substr(v_log_message,l_iteration*1000+1,1000) ; l_iteration :=l_iteration+1 ; INSERT INTO emdw_trace_data (context_type_id,context_identifier, log_level, log_timestamp, log_message,module, oms_host) VALUES (p_ctx_arr.context_type_id,p_ctx_arr.context_identifier, v_log_level,systimestamp, l_string, substr(v_module,1,100), p_ctx_arr.oms_host) ; END LOOP ; -- BigString END ; COMMIT; END IF ; -- v_log_level <= p_ctx_arr.trace_level EXCEPTION -- This Exception would mostly be due to space issues, so the insert here -- would fail too and be caught by the exception when others in inner block -- One other possible condition is foreign key violation due to invalid -- context_type_id or 0 records in emdw_trace_config table. WHEN others THEN DECLARE l_trace_context_type_id NUMBER := 0 ; l_error_msg VARCHAR2(1000) ; BEGIN l_error_msg := substr(sqlerrm,1,1000) ; l_trace_context_type_id := get_context_id(p_tracer_context_type) ; IF l_trace_context_type_id > 0 THEN INSERT INTO emdw_trace_data (context_type_id,context_identifier, log_level,log_timestamp, log_message,module, oms_host) VALUES (l_trace_context_type_id,p_ctx_arr.context_identifier, LERROR,systimestamp, l_error_msg,substr(v_module,1,100), p_ctx_arr.oms_host) ; COMMIT; END IF ; EXCEPTION WHEN OTHERS THEN ROLLBACK ; END ; END log; -- --Log a error message -- PROCEDURE error( v_log_message IN VARCHAR2, v_module IN VARCHAR2 ) IS BEGIN log(LERROR,v_log_message,v_module) ; END error; -- --Log a debug message -- PROCEDURE debug(v_log_message IN VARCHAR2, v_module IN VARCHAR2 ) IS BEGIN log(LDEBUG,v_log_message,v_module) ; END debug; -- --Log a warning message -- PROCEDURE warn(v_log_message IN VARCHAR2, v_module IN VARCHAR2 ) IS BEGIN log(LWARN,v_log_message,v_module) ; END warn; -- --Log a Informational message -- PROCEDURE info(v_log_message IN VARCHAR2, v_module IN VARCHAR2 ) IS BEGIN log(LINFO,v_log_message,v_module) ; END info; -- -- Private procedure --PURPOSE -- Purge trace data for the context type (default =all) which were logged -- before specified purge date (default=all) -- See package Spec for more details -- The purge can be monitored by setting the trace level for TRACER context type -- to LINFO. Errors during purge can be logged by setting trace level to LERROR -- Info and Error Data will be logged into emdw_trace_data table -- PROCEDURE purge(v_context_type IN VARCHAR2 := null, v_purge_date IN DATE := sysdate+1, v_batch_size IN NUMBER := 100000, v_rows_purged OUT NUMBER ) is TYPE l_rowid_list_type IS TABLE OF UROWID INDEX BY BINARY_INTEGER; -- -- Full tablescan below, we could write seperate cursors for specific -- context, one for all contexts, but the maintenance overhead will be more. -- We should be purging globally most of the time -- We could also use dynamic cursors to avoid full table scan. -- Ordered by rowid to avoid 1555 or fetch out of sequence errors -- CURSOR purgerows_cursor( v_context_type_id IN NUMBER, v_purge_date IN DATE) IS SELECT ROWID FROM emdw_trace_data WHERE log_timestamp < v_purge_date AND context_type_id = nvl(v_context_type_id,context_type_id) ORDER BY ROWID ASC; l_rows_processed NUMBER := 0 ; l_instance VARCHAR2(20):= to_char(v_purge_date,'YYYYMMDD#HH24MISS'); l_rowid_list l_rowid_list_type ; l_batchsize NUMBER(10) ; l_maxbatchSize NUMBER(10) := 100000000 ; l_context_type_id NUMBER; BEGIN IF v_batch_size < 1 THEN l_batchsize :=1 ; ELSE l_batchsize:= least(v_batch_size,l_maxbatchsize) ; END IF ; IF v_context_type is null THEN open PurgeRows_Cursor(null,v_purge_date) ; ELSE l_context_type_id := get_context_id(v_context_type) ; -- IF the context_type_id does not exist, raise error -- do not catch exception to let it cascade up IF l_context_type_id <0 THEN RAISE no_data_found ; END IF ; OPEN purgerows_cursor(l_context_type_id,v_purge_date); END IF ; LOOP FETCH purgerows_cursor BULK COLLECT INTO l_rowid_list LIMIT l_batchsize ; EXIT WHEN l_rowid_list.count <=0 ; FORALL i IN l_rowid_list.FIRST..l_rowid_list.LAST DELETE emdw_trace_Data WHERE rowid = l_rowid_list(i) ; l_rows_processed := l_rows_processed + l_rowid_list.count ; IF p_is_debug_set THEN debug('emdw_log_purge:Total rows purged so far='|| to_char(l_rows_processed),p_module) ; END IF ; COMMIT ; l_rowid_list.delete ; END LOOP ; CLOSE PurgeRows_Cursor ; v_rows_purged := l_rows_processed ; EXCEPTION WHEN OTHERS THEN IF p_is_error_set THEN error(sqlerrm,p_module) ; END IF ; COMMIT ; IF PurgeRows_Cursor%isOpen THEN close PurgeRows_Cursor ; END IF ; RAISE ; END purge; -- -- Exposed purge procedure without out parameter ( v_rows_purged) -- PROCEDURE purge(v_context_type IN VARCHAR2 := null, v_purge_date IN DATE := sysdate+1, v_batch_size IN NUMBER := 100000 ) IS l_rows_purged NUMBER ; BEGIN purge(v_context_type=>v_context_type, v_purge_date=>v_purge_Date, v_batch_size=>v_batch_size, v_rows_purged=>l_rows_purged) ; END purge ; -- --Purpose : Background purge procedure called by Purge policy -- PROCEDURE purge(p_purge_params IN OUT NOCOPY MGMT_PURGE_CALLBACK_PARAMS) IS BEGIN IF EMDW_LOG.P_IS_INFO_SET THEN EMDW_LOG.INFO('emdw_log_purge:Enter,Purge Till:'|| to_char(p_purge_params.PURGE_UPTO_TIME,'DD-MON-YY HH24:MI'), p_module) ; END IF; purge(v_purge_date=>p_purge_params.purge_upto_time, v_batch_size=>50000, v_rows_purged=>p_purge_params.rows_processed) ; IF EMDW_LOG.P_IS_INFO_SET THEN EMDW_LOG.INFO('emdw_log_purge:Exit Normal,Rows Purged='|| p_purge_params.rows_processed,p_module) ; END IF; EXCEPTION WHEN OTHERS THEN IF EMDW_LOG.P_IS_INFO_SET THEN EMDW_LOG.INFO('emdw_log_purge:Exit Exception '||sqlerrm,p_module) ; END IF; -- it is expected that the calling purge logs this exception RAISE ; END purge ; BEGIN -- Set the context type to default on first call to this package in the session set_context(p_default_context_type) ; END ; / show errors