Skip to content

packages tree.log__

Jan Kvetina edited this page Oct 10, 2020 · 7 revisions

tree.log__

Repository spec: tree.log__, body: tree.log__


Signature

FUNCTION log__ (
    in_action_name      logs.action_name%TYPE,
    in_flag             logs.flag%TYPE,
    in_arguments        logs.arguments%TYPE     := NULL,
    in_message          logs.message%TYPE       := NULL,
    in_parent_id        logs.log_parent%TYPE    := NULL
)
RETURN logs.log_id%TYPE
ACCESSIBLE BY (
    PACKAGE tree,
    PACKAGE tree_ut
);
Show code (146 lines)

FUNCTION log__ (
    in_action_name      logs.action_name%TYPE,
    in_flag             logs.flag%TYPE,
    in_arguments        logs.arguments%TYPE     := NULL,
    in_message          logs.message%TYPE       := NULL,
    in_parent_id        logs.log_parent%TYPE    := NULL
)
RETURN logs.log_id%TYPE
ACCESSIBLE BY (
    PACKAGE tree,
    PACKAGE tree_ut
) AS
    PRAGMA AUTONOMOUS_TRANSACTION;
    --
    rec                 logs%ROWTYPE;
    map_index           logs.module_name%TYPE;
    new_contexts        sessions.contexts%TYPE;
    --
    whitelisted         BOOLEAN := FALSE;   -- TRUE = log
    blacklisted         BOOLEAN := FALSE;   -- TRUE = dont log; whitelisted > blacklisted
BEGIN
    -- get caller info and parent id
    rec.log_id := log_id.NEXTVAL;
    --
    tree.get_caller__ (
        in_log_id           => rec.log_id,
        in_parent_id        => in_parent_id,
        in_flag             => in_flag,
        out_module_name     => rec.module_name,
        out_module_line     => rec.module_line,
        out_parent_id       => rec.log_parent
    );

    -- recover contexts for scheduler
    IF in_flag = tree.flag_scheduler AND in_parent_id IS NOT NULL THEN
        BEGIN
            SELECT e.user_id, s.contexts
            INTO rec.user_id, new_contexts
            FROM logs e
            JOIN sessions s
                ON s.session_id = e.session_id
            WHERE e.log_id      = in_parent_id;
        EXCEPTION
        WHEN NO_DATA_FOUND THEN
            RAISE_APPLICATION_ERROR(tree.app_exception_code, 'SCHEDULER_ROOT_MISSING ' || in_parent_id, TRUE);
        END;

        -- recover app context values from log and set user
        recent_log_id := rec.log_id;  -- to link SESS calls to proper branch
        sess.create_session (
            in_user_id      => rec.user_id,
            in_contexts     => new_contexts
        );
    END IF;

    -- get user and update session info
    rec.user_id         := COALESCE(rec.user_id, sess.get_user_id());
    rec.flag            := COALESCE(in_flag, '?');
    rec.module_line     := COALESCE(rec.module_line, 0);
    --
    tree.set_session (
        in_module_name  => rec.module_name,
        in_action_name  => COALESCE(in_action_name, rec.module_name || tree.splitter || rec.module_line)
    );

    -- override flag for SESS package calls
    IF rec.module_name LIKE trigger_sess AND rec.flag = tree.flag_module THEN
        rec.flag := tree.flag_session;
    END IF;

    -- force log errors
    IF SQLCODE != 0 OR rec.flag IN (tree.flag_error, tree.flag_warning) THEN
        whitelisted := TRUE;
    END IF;

    -- check whitelist first
    IF NOT whitelisted THEN
        whitelisted := tree.is_listed (
            in_list => rows_whitelist,
            in_row  => rec
        );
    END IF;

    -- check blacklist
    IF NOT whitelisted THEN
        blacklisted := tree.is_listed (
            in_list => rows_blacklist,
            in_row  => rec
        );
        --
        IF blacklisted THEN
            RETURN NULL;  -- exit function
        END IF;
    END IF;

    -- prepare record
    rec.app_id          := COALESCE(sess.get_app_id(),  0);  -- default to zero to match sessions table
    rec.page_id         := COALESCE(sess.get_page_id(), 0);
    rec.action_name     := SUBSTR(COALESCE(rec.action_name, in_action_name, tree.empty_action), 1, tree.length_action);
    rec.arguments       := SUBSTR(in_arguments, 1, tree.length_arguments);
    rec.message         := SUBSTR(in_message,   1, tree.length_message);  -- may be overwritten later
    rec.session_id      := sess.get_session_id();
    rec.created_at      := LOCALTIMESTAMP;

    -- add call stack
    IF SQLCODE != 0 OR INSTR(tree.track_callstack, rec.flag) > 0 OR tree.track_callstack = '%' OR in_parent_id IS NOT NULL THEN
        rec.message := SUBSTR(rec.message || tree.get_call_stack(), 1, tree.length_message);
    END IF;

    -- add error stack if available
    IF SQLCODE != 0 THEN
        rec.action_name := COALESCE(NULLIF(rec.action_name, tree.empty_action), 'UNKNOWN_ERROR');
        rec.message     := SUBSTR(rec.message || tree.get_error_stack(), 1, tree.length_message);
    END IF;

    -- finally store record in table
    INSERT INTO logs VALUES rec;
    COMMIT;
    --
    recent_log_id := rec.log_id;
    IF SQLCODE != 0 OR rec.flag = tree.flag_error THEN
        recent_error_id := rec.log_id;  -- save last error for easy access
    END IF;

    -- print message to console
    $IF $$OUTPUT_ENABLED $THEN
        DBMS_OUTPUT.PUT_LINE(
            rec.log_id || ' ^' || COALESCE(rec.log_parent, 0) || ' [' || rec.flag || ']: ' ||
            --RPAD(' ', (rec.module_depth - 1) * 2, ' ') ||
            rec.module_name || ' [' || rec.module_line || '] ' || NULLIF(rec.action_name, tree.empty_action) ||
            RTRIM(': ' || SUBSTR(in_arguments, 1, 40), ': ')
        );
    $END
    --
    RETURN rec.log_id;
EXCEPTION
WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('-- NOT LOGGED ERROR:');
    DBMS_OUTPUT.PUT_LINE(DBMS_UTILITY.FORMAT_ERROR_STACK);
    DBMS_OUTPUT.PUT_LINE(DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
    DBMS_OUTPUT.PUT_LINE(DBMS_UTILITY.FORMAT_CALL_STACK);
    DBMS_OUTPUT.PUT_LINE('-- ^');
    --
    COMMIT;
    RAISE_APPLICATION_ERROR(tree.app_exception_code, 'LOG_FAILED', TRUE);
END;

Clone this wiki locally