In PIT
, a context is a small collection of four parameters:
- Log level (
10, 20, .. 70
) orpit.level_off .. pit.level_debug
- Trace level (
10, 20, .. 50
) orpit.trace_off .. pit.trace_detailed
- Trace timing flag (
Y|N
) - List of output modules (
PIT_TABLE:PIT_APEX
...)
You may have any number of contexts defined for your application. To define a context, you create a parameter with the naming convention CONTEXT_<Name>
and a string value of the four beforementioned parameters, separated by pipe signs (|). Package pit_admin
provides methods named pit_admin.create_named_context
to help you create these parameters. The methods are overloaded and give you the choice of passing the four parameters in separately or as a preformatted settings string. Using these methods has the advantage of cross checking the values and giving you exceptions if you define values that are not supported.
Please respect the ranges defined above for log and trace level. Also keep in mind that the list of output modules must be provided as a colon-separated list. All packages check input to assure that no undefined values are used.
One special context is called CONTEXT_DEFAULT
. It serves as the basic setting for your logging. You may define it differently on development and production systems, but you should make sure that it's always present. If you want to switch off logging completely, you can pass in 10|10|N|
to indicate this, but PIT
will throw fatal and error log levels anyway. If you don't paramterize at least one output module, danger is that errors may get lost undocumented.
One context name called CONTEXT_ACTIVE
is reserved and therefore can't be used by you. The active context is used as an alternative to default logging. This makes it possible to log during a certain time period or certain sessions without affecting the log settings for other sessions or the need to adjust the default settings. Any named context you define may be switched active, overwritten by another named context or reset which enables default logging again.
Logging is controlled by the default context basically. If you simply start your code with PIT
being installed, the default settings apply. Which options you have in regard to controlling your logging depends on the initial parameters you have set if the PIT
package initializes.
Log settings need to be stored in a place where any session running PIT
is able to see it. If the settings were set in a package variable, only the session setting the variables could see the changes. So if you change the log settings in one session, other sessions wouldn't be able to see those changes.
There are basically two places within the database every session has access to: Tables and SGA. I decided to persist all parameters in a parameter table but to copy some of the more important parameters to the SGA. Reason is that I wanted to be able not only to switch logging for a given session on and off without affecting other sessions, but to trace and log activities of a given application user, even if she uses different sessions while working on her application. This in turns makes it necessary to define the focus of visibility of these parameters. Luckily, Oracle provides a structure to maintain those settings on a fine granularity in the SGA: A globally accessed context.
DISCLAIMER: The use of globally accessible contexts require that you have the necessary privileges to create such a context or you need to ask your database administrator to create one for you. If you don't have these rights and can't get them (fi in a cloud environment), PIT
will install without this functionality. In certain environments, such as APEX, it is nevertheless possible to trace user activities across database sessions. This is possible as APEX switches tracing debugging and tracing on and off and PIT
follows these settings.
A context is a memory structure where SQL as well as PL/SQL have access to without environment switches. This makes access to context information very fast and convenient. On the other side, contexts are limited to short key value pairs of type varchar2
only. Another downside of a context is that they store their values in the PGA normally, granting access to the actual values to the active session only. This makes them less interesting for inter session purposes. A globally accessed context on the other hand stores it's values in SGA and therefore makes them accessible to all session. Plus, these contexts allow to control the visibility of the information: A parameter value may be visible by certain users only or it may be visible to a broader scope based on how you store the value in the context. Because of this, PIT
stores all it's cross-session information in a global context.
Changing settings means that all other sessions are aware of these changes immediately without any action. To make this work, PIT
won't copy these settings into local memory but simply »outsource« it's knowledge upon context status to the context. Changing parameters in the database on the other hand means that you have to re-initialize PIT
to make it aware of the parameter changes. This can be achieved by calling pit.initialize
. All parameters that are stored in the context are made visible for all other instances of PIT
at the same time, but some parameter changes may not be known to any PIT
instance.
As per Oracle standard, a context may contain information that is visible to every user, to a specific database user only or to a session that has a specific client identifier set. As a matter of fact, these options are not too intuitive to use when using a context out of the box. Fi, it would be highly appreciated to have a »fallback« for a given parameter: If a user does not have a matching client identifier, it would be nice if this user could instead see the more widely visible parameter of the same name. Unfortunately, this is not possible. To allow for this, PIT
wrapps the usage of the globally accessed context in a helper package called utl_context
.
UTL_CONTEXT
is not only interesting for PIT
but for other uses as well which can accept that this package writes to the context. UTL_CONTEXT
offers different types of globally accessed contexts to control how the context should behave. Here is a list of the different context modes UTL_CONTEXT
provides:
utl_context.c_global
: ... for any user and any session, no possibility to restrict access based on user or sessionutl_context.c_force_user
: ... for any session, but only if database username matchesutl_context.c_force_client_id
: ... only if client_identifier matchesutl_context.c_force_user_client_id
: ... only if user AND client_identifier matchesutl_context.c_prefer_client_id
: ... if a matching value for that client_identifier exists, it is visible, otherwise a default value is providedutl_context.c_prefer_user_client_id
: ... if a matching value for that user AND client_identifier exists, it is visible, otherwise a default value is providedutl_context.c_session
: ... only within the session that set the value (pseduo local context)
Of the modes offered, the C_PREFER_...
options are special as they allow for a fallback solution. The idea is that if a specific setting for a combination of user and client identifier is avaiable, this will be chosen. If not, it »falls back« to a setting for the user if a value exists that has got no dependency to a client identifier. This makes it possible to have a specific log setting which applies to any user which can be overwritten by a specific setting if the client identifier matches. To use one of those context types, you simply choose the constant value as value for PIT
parameter PIT_CTX_TYPE
. In an environment with client server connections, you may opt for a FORCE_USER
if your application users are proxy or database users. If, on the other side, you work in a connection pool environment, you may choose PREFER_CLIENT_ID
to control logging on a per user basis, even if they utilize different sessions per call. PIT
defaults to utl_context.c_prefer_client_id
.
Now that we understand that the memory of PIT
is the globally accessed context, we need to understand what options we have to control these settings.
If you want to change the actual log settings, a best practice is to create a named context using the pit_admin.create_named_context
method and switch to it. This is achieved by calling pit.set_context(<NAME_OF_CONTEXT>);
, This will work immediately and across all sessions that can see the global context value. Another option is convenient during testing: You can call the overloaded version ot pit.set_context
which allows you to set all log parameters directly without the need to create a named context upfront. Here's a code snippet to show you how to do it:
begin
pit.set_context('DEBUG');
-- Alternatively:
pit.set_context(
p_log_level => pit.level_all,
p_trace_level => pit.trace_all,
p_trace_timing => true,
p_module_list => 'PIT_CONSOLE:PIT_TEST');
...
end;
How and when this method is called is up to you. You may bind it to an external toggle or call a script to switch it, as soon as you call the method, it gets switched. What the focus of this switch will be depends on the kind of context you have. There is one exception to this rule: The session adapter, responsible for retrieving session id and username, also has an option to control logging. It may pass the name of a context back and PIT
will immediately switch to this context. This is useful if you need a way to detect whether the calling environment is set to debug mode and you want PIT
. Take APEX as an example: You can switch on logging of an APEX application by providing a switch within the URL. The APEX session adapter shipped with the PIT_APEX
output module will detect this and switch to a context called CONTEXT_APEX
that contains parameterizable logging settings for APEX. This way, PIT
can be remotely switched on simply by setting APEX to debug mode.
Another option to control the log session is to switch logging on and of for a given list of methods or packages. Idea is that you may have packages that are well maintained and tested, whereas other packages need testing and logging. In this case, you can provide a »white list« to switch logging on or a »black list« to switch logging off. You may have any number of toggle switches. Normally, you may provide on toggle per named context you want to toggle to. Assure that this named context is available before creating a toggle to prevent assertion errors.
To enable this option, a global PIT
parameter called ALLOW_TOGGLE
needs to be set to TRUE
. Named contexts to switch to need to be defined and a list of parameters with the naming convention TOGGLE_<NAME>
need to be generated. Let's make things clearer by providing an example. In an application, packages UTIL
and method MAIL.SEND
shall not be traced, whereas packages BL_FORM
, BL_MODE
and method BL_ORDER.SUBMIT
shall be traced. Parameter ALLOW_TOGGLE
is set to true.
The following named contexts are defined (by calling pit_admin.create_named_context(...)
):
CONTEXT_LOG_ALL
, settings:70|50|Y|PIT_CONSOLE
CONTEXT_LOG_OFF
, settings:10|10|N|
Now, two parameters to toggle the settings are defined (by calling pit_admin.create_context_toggle(...)
):
TOGGLE_ON
, string value:BL_FORM:BL_MODE:BL_ORDER.SUBMIT|CONTEXT_LOG_ALL
TOGGLE_OFF
, string value:UTIL:MAIL.SEND|CONTEXT_LOG_OFF
Now, your code enters method FOO
. As no setting is defined for this package, CONTEXT_DEFAULT
is used. FOO
calls BL_FORM
. The context toggles to CONTEXT_LOG_ALL
and logs anything to output module PIT_CONSOLE
. Now, BL_FORM
calls another package FOO2
. As this does not change the settings, CONTEXT_LOG_ALL
remains active. If MAIL.SEND
is called, logging is switched off. But if you leave MAIL.SEND
, Logging resumes to the last setting that was active before MAIL.SEND
was called, so in our example it resumes CONTEXT_LOG_ALL
and logging continues. If you leave BL_FORM
, logging switches back to CONTEXT_DEFAULT
, as no active context was active before BL_FORM
was called.
Switching parameter ALLOW_TOGGLE
to TRUE
forces PIT
to maintain minimal tracing information to gather information about whether a context should be switched or not. Therefore, if you don't need the toggle functionality, switch parameter ALLOW_TOGGLE
to FALSE
again to avoid unnecessary work and speed up PIT
.
As you can see throughout this page, pit_admin
is used to create parameters, whereas pit
is used to switch between existing parameters. This is by design. it allows to grant execute rights to pit
only without the grantee having the possibility to call pit_admin
methods. Nevertheless, pit_admin
is required on production systems, even if you don't plan to call it there: As a enhanced possibility to speed up PIT
on production system, it's possible to adjust installation flags within package pit_admin
. If you don't implement pit_admin
on production, these flags are not present and compilation errors will occur. See Performance tuning of PIT
for details on this.
PIT
also offers a method called pit.set_context_value
. The use case is different, as this method does not aim to maintaining the internal PIT
memory but to set values in the global context that offer the same possibilities as the other context values, namely being accessible across sessions while at the same time being private per (logical) session. This method allows to set any value within that global context. This comes in handy if you want to set a test flag or if you need to adjust the time for automatic testing. Whatever use case you may have in mind can be achieved within the limits of a global context. These limits are that you can store only alphanumeric values up to 4000 Byte in length. By calling this method and providing a NULL
value to its p_value
parameter, the attribute gets deleted from the global context.
If you want to read the content, the official way to do this is to call sys_context
with the name of the global context and the name of the parameter. Using this method, you can access this information from both SQL and PL/SQL without an environment switch which makes this approach very appealing. Keep in mind though that the optimizer will not be able to select a proper execution plan based on a call to sys_context
as it is not known at compile time what the value will be. Another disadvantage of this approach is that you need to know the name of the global context PIT
uses. The name can be deducted, as it is composed of PIT_CTX_<Onwer of PIT>
, so if the owner of PIT
is UTILS
, the context name is PIT_CTX_UTILS
.
If you can accept calling a PL/SQL method, there is a method called pit.get_context_value
that expects the attribute name and returns the parameter value. Using this method you don't need to know the context name and it may fit nicely into a PL/SQL program. And even from within SQL you may use this method, but you should wrap the call into a scalar subquery (select pit.get_context_value('MY_ATTIRUBTE') from dual
) to prevent unnecessary context switches.