diff --git a/source/jobs/logger_unset_prefs_by_scope.sql b/source/jobs/logger_unset_prefs_by_scope.sql new file mode 100644 index 0000000..84a7939 --- /dev/null +++ b/source/jobs/logger_unset_prefs_by_scope.sql @@ -0,0 +1,22 @@ +declare + l_count pls_integer; + l_job_name user_scheduler_jobs.job_name%type := 'LOGGER_UNSET_PREFS_BY_SCOPE'; +begin + + select count(1) + into l_count + from user_scheduler_jobs + where job_name = l_job_name; + + if l_count = 0 then + dbms_scheduler.create_job( + job_name => l_job_name, + job_type => 'PLSQL_BLOCK', + job_action => 'begin logger.unset_scope_level; end; ', + start_date => systimestamp, + repeat_interval => 'FREQ=HOURLY; BYHOUR=1', + enabled => TRUE, + comments => 'Clears expired logger prefs by scope'); + end if; +end; +/ diff --git a/source/packages/logger.pkb b/source/packages/logger.pkb index 8826ab6..00f35e3 100644 --- a/source/packages/logger.pkb +++ b/source/packages/logger.pkb @@ -58,6 +58,7 @@ as gc_ctx_attr_level constant varchar2(5) := 'level'; gc_ctx_attr_include_call_stack constant varchar2(18) := 'include_call_stack'; + gc_ctx_attr_scope constant varchar2(5) := 'scope'; -- #46 Plugin context names gc_ctx_plugin_fn_log constant varchar2(30) := 'plugin_fn_log'; @@ -440,14 +441,14 @@ as * * @author Tyler Muth * @created ??? - * @param + * @param p_scope * @return If client level specified will return it, otherwise global level. */ - function get_level_number + function get_level_number(p_scope in varchar2 default null) -- PBA/MNU 201704 return number $if $$rac_lt_11_2 $then $if not dbms_db_version.ver_le_10_2 $then - result_cache relies_on (logger_prefs, logger_prefs_by_client_id) + result_cache relies_on (logger_prefs, logger_prefs_by_client_id, logger_prefs_by_scope) -- PBA/MNU 201704 $end $end is @@ -466,7 +467,8 @@ as dbms_output.put_line(l_scope || ': selecting logger_level'); $end - l_level := convert_level_char_to_num(logger.get_pref(logger.gc_pref_level)); + l_level := convert_level_char_to_num(logger.get_pref(p_pref_name => logger.gc_pref_level + ,p_scope => p_scope)); -- PBA/MNU 201704 return l_level; $end @@ -929,15 +931,17 @@ as * @created ??? * * @param p_level Level (number) + * @param p_scope * @return True of statement can be logged to LOGGER_LOGS */ - function ok_to_log(p_level in number) + function ok_to_log(p_level in number, + p_scope in varchar2 default null) return boolean $if 1=1 and $$rac_lt_11_2 and not dbms_db_version.ver_le_10_2 and ($$no_op is null or not $$no_op) $then - result_cache relies_on (logger_prefs, logger_prefs_by_client_id) + result_cache relies_on (logger_prefs, logger_prefs_by_client_id, logger_prefs_by_scope) -- PBA/MNU 201704 $end is l_level number; @@ -960,21 +964,31 @@ as $if $$logger_debug $then dbms_output.put_line(l_scope || ': calling get_level_number'); $end - l_level := get_level_number; + l_level := get_level_number(p_scope => p_scope); -- PBA/MNU 201704 $else - l_level := sys_context(g_context_name,gc_ctx_attr_level); + l_level := sys_context(g_context_name,gc_ctx_attr_level); + + -- PBA/MNU 201704 + -- if the current scope is different from the saved scope (context) then clear the level + -- (only applies to non-empty scopes) + if coalesce(sys_context(g_context_name,gc_ctx_attr_scope),'#^') <> coalesce(p_scope,'#^') then + l_level := null; + end if; if l_level is null then $if $$logger_debug $then dbms_output.put_line(l_scope || ': level was null, getting and setting in context'); $end - l_level := get_level_number; + l_level := get_level_number(p_scope => p_scope); -- PBA/MNU 201704 save_global_context( p_attribute => gc_ctx_attr_level, p_value => l_level, p_client_id => sys_context('userenv','client_identifier')); + save_global_context( + p_attribute => gc_ctx_attr_scope, + p_value => p_scope); end if; $end @@ -994,16 +1008,19 @@ as * @created 25-Jul-2013 * * @param p_level Level (DEBUG etc..) + * @param p_scope * @return True of log statements for that level or below will be logged */ - function ok_to_log(p_level in varchar2) + function ok_to_log(p_level in varchar2, + p_scope in varchar2 default null) return boolean as begin $if $$no_op $then return false; $else - return ok_to_log(p_level => convert_level_char_to_num(p_level => p_level)); + return ok_to_log(p_level => convert_level_char_to_num(p_level => p_level) + ,p_scope => p_scope); $end end ok_to_log; @@ -1182,7 +1199,8 @@ as $if $$no_op $then null; $else - if ok_to_log(logger.g_error) then +-- if ok_to_log(logger.g_error) then -- PBA 20190428 take the scope into account + if ok_to_log(logger.g_error, p_scope) then get_debug_info( p_callstack => dbms_utility.format_call_stack, o_unit => l_proc_name, @@ -1254,7 +1272,8 @@ as $if $$no_op $then null; $else - if ok_to_log(logger.g_permanent) then +-- if ok_to_log(logger.g_permanent) then -- PBA 20190428 take the scope into account + if ok_to_log(logger.g_permanent, p_scope) then log_internal( p_text => p_text, p_log_level => logger.g_permanent, @@ -1294,7 +1313,8 @@ as $if $$no_op $then null; $else - if ok_to_log(logger.g_warning) then +-- if ok_to_log(logger.g_warning) then -- PBA 20190428 take the scope into account + if ok_to_log(logger.g_warning, p_scope) then log_internal( p_text => p_text, p_log_level => logger.g_warning, @@ -1364,7 +1384,8 @@ as $if $$no_op $then null; $else - if ok_to_log(logger.g_information) then +-- if ok_to_log(logger.g_information) then -- PBA 20190428 take the scope into account + if ok_to_log(logger.g_information, p_scope) then log_internal( p_text => p_text, p_log_level => logger.g_information, @@ -1436,7 +1457,8 @@ as $if $$no_op $then null; $else - if ok_to_log(logger.g_debug) then +-- if ok_to_log(logger.g_debug) then -- PBA 20190428 take the scope into account + if ok_to_log(logger.g_debug, p_scope) then log_internal( p_text => p_text, p_log_level => logger.g_debug, @@ -1525,7 +1547,8 @@ as $if $$no_op $then null; $else - if ok_to_log(nvl(p_level, logger.g_debug)) then +-- if ok_to_log(nvl(p_level, logger.g_debug)) then -- PBA 20190428 take the scope into account + if ok_to_log(nvl(p_level, logger.g_debug), p_scope) then l_extra := get_sys_context( p_detail_level => p_detail_level, p_vertical => true, @@ -1566,7 +1589,8 @@ as $if $$no_op $then null; $else - if ok_to_log(nvl(p_level, logger.g_debug)) then +-- if ok_to_log(nvl(p_level, logger.g_debug)) then -- PBA 20190428 take the scope into account + if ok_to_log(nvl(p_level, logger.g_debug), p_scope) then l_extra := get_cgi_env(p_show_null => p_show_null); log_internal( p_text => 'CGI ENV values stored in the EXTRA column', @@ -1606,7 +1630,8 @@ as $if $$no_op $then null; $else - if ok_to_log(nvl(p_level, logger.g_debug)) then +-- if ok_to_log(nvl(p_level, logger.g_debug)) then -- PBA 20190428 take the scope into account + if ok_to_log(nvl(p_level, logger.g_debug), p_scope) then l_dump := get_character_codes(p_text,p_show_common_codes); log_internal( @@ -1651,7 +1676,8 @@ as $if $$no_op $then null; $else - if ok_to_log(nvl(p_level, logger.g_debug)) then +-- if ok_to_log(nvl(p_level, logger.g_debug)) then -- PBA 20190428 take the scope into account + if ok_to_log(nvl(p_level, logger.g_debug), p_scope) then $if $$apex $then -- Validate p_item_type @@ -1755,7 +1781,8 @@ as $if $$no_op $then null; $else - if ok_to_log(logger.g_debug) then +-- if ok_to_log(logger.g_debug) then + if ok_to_log(logger.g_debug, p_scope) then if g_proc_start_times.exists(p_unit) then if g_running_timers > 1 then @@ -1810,7 +1837,8 @@ as $if $$no_op $then null; $else - if ok_to_log(logger.g_debug) then +-- if ok_to_log(logger.g_debug) then -- PBA 20190428 take the scope into account + if ok_to_log(logger.g_debug, p_scope) then if g_proc_start_times.exists(p_unit) then l_time_string := rtrim(regexp_replace(localtimestamp - (g_proc_start_times(p_unit)),'.+?[[:space:]](.*)','\1',1,0),0); @@ -1866,7 +1894,8 @@ as $if $$no_op $then null; $else - if ok_to_log(logger.g_debug) then +-- if ok_to_log(logger.g_debug) then -- PBA 20190428 take the scope into account + if ok_to_log(logger.g_debug, p_scope) then if g_proc_start_times.exists(p_unit) then l_interval := localtimestamp - (g_proc_start_times(p_unit)); l_seconds := extract(day from l_interval) * 86400 + extract(hour from l_interval) * 3600 + extract(minute from l_interval) * 60 + extract(second from l_interval); @@ -1936,12 +1965,14 @@ as */ function get_pref( p_pref_name in logger_prefs.pref_name%type, - p_pref_type in logger_prefs.pref_type%type default logger.g_pref_type_logger) + p_pref_type in logger_prefs.pref_type%type default logger.g_pref_type_logger, + p_scope in varchar2 default null -- PBA/MNU 201704 + ) return varchar2 $if not dbms_db_version.ver_le_10_2 $then result_cache $if $$no_op is null or not $$no_op $then - relies_on (logger_prefs, logger_prefs_by_client_id) + relies_on (logger_prefs, logger_prefs_by_client_id, logger_prefs_by_scope) -- PBA/MNU 201704 $end $end is @@ -1950,6 +1981,10 @@ as l_client_id logger_prefs_by_client_id.client_id%type; l_pref_name logger_prefs.pref_name%type := upper(p_pref_name); l_pref_type logger_prefs.pref_type%type := upper(p_pref_type); + -- PBA/MNU 201704 + -- p_scope is entered as lowercase in the table so make the parameter lowercase here + -- l_scope is already used, so we use lp_scope + lp_scope logger_prefs_by_scope.logger_scope%type := lower(p_scope); begin $if $$no_op $then @@ -1966,6 +2001,18 @@ as from ( select pref_value, row_number () over (order by rank) rn from ( + -- Scope specific logger levels trump client specific AND system level loggel level + select pref_value + , 0 rank + from (select logger_level pref_value + from logger_prefs_by_scope + where 1 = 1 + and l_pref_name = logger.gc_pref_level + and lp_scope like logger_scope + order by length(logger_scope) desc) + where 1 = 1 + and rownum <= 1 + union all -- Client specific logger levels trump system level logger level select case @@ -2952,5 +2999,24 @@ as end if; end get_plugin_rec; + /** + * Unsets scope_level that are stale (i.e. past their expiry date) + * + * @author Patrick Barel/Milco Numan + * @created 18-Apr-2017 + */ + procedure unset_scope_level + as + begin + $if $$no_op $then + null; + $else + delete + from logger_prefs_by_scope + where sysdate > expiry_date + ; + commit; + $end + end unset_scope_level; end logger; / diff --git a/source/packages/logger.pks b/source/packages/logger.pks index a34a848..688cdeb 100644 --- a/source/packages/logger.pks +++ b/source/packages/logger.pks @@ -29,7 +29,9 @@ as -- TYPES type rec_param is record( name varchar2(255), - val varchar2(4000)); +-- val varchar2(4000)); + val varchar2(32767) -- PBA: This is enlarged, since it is stored in a CLOB anyway + ); type tab_param is table of rec_param index by binary_integer; @@ -40,16 +42,16 @@ as -- VARIABLES - g_logger_version constant varchar2(10) := 'x.x.x'; -- Don't change this. Build script will replace with right version number - g_context_name constant varchar2(35) := substr(sys_context('USERENV','CURRENT_SCHEMA'),1,23)||'_LOGCTX'; + g_logger_version constant varchar2(10) := 'x.x.x'; -- Don't change this. Build script will replace with right version number + g_context_name constant varchar2(35) := substr(sys_context('USERENV','CURRENT_SCHEMA'),1,23)||'_LOGCTX'; g_off constant number := 0; g_permanent constant number := 1; - g_error constant number := 2; - g_warning constant number := 4; - g_information constant number := 8; + g_error constant number := 2; + g_warning constant number := 4; + g_information constant number := 8; g_debug constant number := 16; - g_timing constant number := 32; + g_timing constant number := 32; g_sys_context constant number := 64; g_apex constant number := 128; @@ -107,8 +109,8 @@ as function admin_security_check return boolean; - function get_level_number - return number; +-- function get_level_number(p_scope in varchar2 default null) +-- return number; function include_call_stack return boolean; @@ -142,9 +144,9 @@ as function date_text_format (p_date in date) return varchar2; - function get_character_codes( - p_string in varchar2, - p_show_common_codes in boolean default true) + function get_character_codes( + p_string in varchar2, + p_show_common_codes in boolean default true) return varchar2; procedure log_error( @@ -190,8 +192,8 @@ as p_params in tab_param default logger.gc_empty_tab_param); function get_cgi_env( - p_show_null in boolean default false) - return clob; + p_show_null in boolean default false) + return clob; procedure log_userenv( p_detail_level in varchar2 default 'USER',-- ALL, NLS, USER, INSTANCE, @@ -217,12 +219,12 @@ as p_log_null_items in boolean default true, p_level in logger_logs.logger_level%type default null); - procedure time_start( - p_unit in varchar2, + procedure time_start( + p_unit in varchar2, p_log_in_table in boolean default true); - procedure time_stop( - p_unit in varchar2, + procedure time_stop( + p_unit in varchar2, p_scope in varchar2 default null); function time_stop( @@ -241,7 +243,8 @@ as function get_pref( p_pref_name in logger_prefs.pref_name%type, - p_pref_type in logger_prefs.pref_type%type default logger.g_pref_type_logger) + p_pref_type in logger_prefs.pref_type%type default logger.g_pref_type_logger, + p_scope in varchar2 default null) return varchar2 $if not dbms_db_version.ver_le_10_2 $then result_cache @@ -258,18 +261,18 @@ as p_pref_type in logger_prefs.pref_type%type, p_pref_name in logger_prefs.pref_name%type); - procedure purge( - p_purge_after_days in varchar2 default null, - p_purge_min_level in varchar2 default null); + procedure purge( + p_purge_after_days in varchar2 default null, + p_purge_min_level in varchar2 default null); procedure purge( p_purge_after_days in number default null, p_purge_min_level in number); - procedure purge_all; + procedure purge_all; - procedure status( - p_output_format in varchar2 default null); -- SQL-DEVELOPER | HTML | DBMS_OUPUT + procedure status( + p_output_format in varchar2 default null); -- SQL-DEVELOPER | HTML | DBMS_OUPUT procedure sqlplus_format; @@ -322,10 +325,12 @@ as p_name in varchar2, p_val in boolean); - function ok_to_log(p_level in number) + function ok_to_log(p_level in number, + p_scope in varchar2 default null) return boolean; - function ok_to_log(p_level in varchar2) + function ok_to_log(p_level in varchar2, + p_scope in varchar2 default null) return boolean; function tochar( @@ -381,5 +386,11 @@ as function get_plugin_rec( p_logger_level in logger_logs.logger_level%type) return logger.rec_logger_log; + + procedure unset_scope_level; + + -- PBA 20190414 062841 expose this function to be used in testing routine + function get_level_number(p_scope in varchar2 default null) + return number; end logger; / diff --git a/source/scripts/create_logger_public_synonyms.sql b/source/scripts/create_logger_public_synonyms.sql new file mode 100644 index 0000000..f3dae09 --- /dev/null +++ b/source/scripts/create_logger_public_synonyms.sql @@ -0,0 +1,23 @@ +-- Creates public synonyms from defined user for Logger objects + + +set define '&' +set verify off + +-- Parameters +define from_user=LOGGER_USER +accept from_user char default &from_user prompt 'Name of the logger schema [&from_user] :' + + +whenever sqlerror exit sql.sqlcode + +create or replace public synonym logger for &from_user..logger; +create or replace public synonym logger_logs for &from_user..logger_logs; +create or replace public synonym logger_logs_apex_items for &from_user..logger_logs_apex_items; +create or replace public synonym logger_prefs for &from_user..logger_prefs; +create or replace public synonym logger_prefs_by_client_id for &from_user..logger_prefs_by_client_id; +create or replace public synonym logger_logs_5_min for &from_user..logger_logs_5_min; +create or replace public synonym logger_logs_60_min for &from_user..logger_logs_60_min; +create or replace public synonym logger_logs_terse for &from_user..logger_logs_terse; +-- PBA/MNU 3.1.2 +create or replace public synonym logger_prefs_by_scope for &from_user..logger_prefs_by_scope; diff --git a/source/scripts/create_logger_synonyms.sql b/source/scripts/create_logger_synonyms.sql index 22caeab..317846b 100644 --- a/source/scripts/create_logger_synonyms.sql +++ b/source/scripts/create_logger_synonyms.sql @@ -15,3 +15,5 @@ create or replace synonym logger_prefs_by_client_id for &from_user..logger_prefs create or replace synonym logger_logs_5_min for &from_user..logger_logs_5_min; create or replace synonym logger_logs_60_min for &from_user..logger_logs_60_min; create or replace synonym logger_logs_terse for &from_user..logger_logs_terse; +-- PBA/MNU 3.1.2 +create or replace synonym logger_prefs_by_scope for &from_user..logger_prefs_by_scope; diff --git a/source/scripts/grant_logger_to_public.sql b/source/scripts/grant_logger_to_public.sql new file mode 100644 index 0000000..644ad39 --- /dev/null +++ b/source/scripts/grant_logger_to_public.sql @@ -0,0 +1,18 @@ +-- Grants privileges for logger objects from current user to public + + +-- Parameters +-- none + +whenever sqlerror exit sql.sqlcode + +grant execute on logger to public; +grant select, delete on logger_logs to public; +grant select on logger_logs_apex_items to public; +grant select, update on logger_prefs to public; +grant select on logger_prefs_by_client_id to public; +grant select on logger_logs_5_min to public; +grant select on logger_logs_60_min to public; +grant select on logger_logs_terse to public; +-- PBA/MNU 3.1.2 +grant select, insert, update, delete on logger_prefs_by_scope to public; diff --git a/source/scripts/grant_logger_to_user.sql b/source/scripts/grant_logger_to_user.sql index 813447d..0e12ee0 100644 --- a/source/scripts/grant_logger_to_user.sql +++ b/source/scripts/grant_logger_to_user.sql @@ -15,3 +15,6 @@ grant select on logger_prefs_by_client_id to &to_user; grant select on logger_logs_5_min to &to_user; grant select on logger_logs_60_min to &to_user; grant select on logger_logs_terse to &to_user; +-- PBA/MNU 3.1.2 +grant select, insert, update, delete on logger_prefs_by_scope to &to_user; + diff --git a/source/tables/logger_prefs_by_scope.sql b/source/tables/logger_prefs_by_scope.sql new file mode 100644 index 0000000..8e50f8e --- /dev/null +++ b/source/tables/logger_prefs_by_scope.sql @@ -0,0 +1,44 @@ +-- Initial table script built from 3.1.2 +declare + l_count pls_integer; + +begin + -- Create Table + select count(1) + into l_count + from user_tables + where table_name = 'LOGGER_PREFS_BY_SCOPE'; + + if l_count = 0 then + execute immediate q'! +create table logger_prefs_by_scope( + logger_scope varchar2(512) not null, + logger_level varchar2(20) not null, + created_date date default sysdate not null, + expiry_date date default sysdate+1/24 not null, + constraint logger_prefs_by_scope_pk primary key (logger_scope) enable, + constraint logger_prefs_by_scope_ck1 check (logger_level in ('OFF','PERMANENT','ERROR','WARNING','INFORMATION','DEBUG','TIMING', 'APEX', 'SYS_CONTEXT')), + constraint logger_prefs_by_scope_ck2 check (expiry_date >= created_date) +)!'; + end if; + +-- Add comments to the table + execute immediate q'!comment on table LOGGER_PREFS_BY_SCOPE is 'Scope specific logger levels. Only active scopes/logger_levels will be maintained in this table'!'; +-- Add comments to the columns + execute immediate q'!comment on column LOGGER_PREFS_BY_SCOPE.LOGGER_SCOPE is 'Scope. Wildcards allowed. Interpreted as LIKE pattern'!'; + execute immediate q'!comment on column LOGGER_PREFS_BY_SCOPE.LOGGER_LEVEL is 'Logger level. Must be OFF, PERMANENT, ERROR, WARNING, INFORMATION, DEBUG, TIMING'!'; + execute immediate q'!comment on column LOGGER_PREFS_BY_SCOPE.CREATED_DATE is 'Date that entry was created on'!'; + execute immediate q'!comment on column LOGGER_PREFS_BY_SCOPE.expiry_date is 'After the given expiry date the logger_level will be disabled for the specific client_id. Unless sepcifically removed from this table a job will clean up old entries'!'; +end; +/ +create or replace trigger biu_logger_prefs_by_scope + before insert or update on logger_prefs_by_scope + for each row +begin + $if $$logger_no_op_install $then + null; + $else + :new.logger_scope := lower(:new.logger_scope); + $end +end biu_logger_prefs_by_scope; +/