рд╕рднреА рдХреЛ рдирдорд╕реНрдХрд╛рд░!
рд▓реЗрдЦ рдореЗрдВ, рдореИрдВ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд▓реЙрдЧрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдПрдХ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░рдирд╛ рдЪрд╛рд╣реВрдВрдЧрд╛, рдЬрд┐рд╕рдиреЗ рдореБрдЭреЗ рдФрд░ рдореЗрд░реЗ рд╕рд╣рдпреЛрдЧрд┐рдпреЛрдВ рдХреЛ рдбрд┐рдмрдЧрд┐рдВрдЧ, рд╕рдорд╕реНрдпрд╛ рдирд┐рд╡рд╛рд░рдг рдФрд░ рдкреНрд░рджрд░реНрд╢рди рд╕рдорд╕реНрдпрд╛рдУрдВ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рдиреЗ рдореЗрдВ рдмрд╣реБрдд рдорджрдж рдХреАред Habr├й рдкрд░ рд▓реЙрдЧрд┐рдВрдЧ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╣реБрдд рд╕рд╛рд░реЗ рдЕрдЪреНрдЫреЗ рд▓реЗрдЦ рд▓рд┐рдЦреЗ рдЧрдП рдереЗ, рдЗрд╕рд▓рд┐рдП, рдпрд╣рд╛рдБ рджреЛрд╣рд░рд╛рдиреЗ рдХреА рдмрд╣реБрдд рдмрд╛рдд рдирд╣реАрдВ рд╣реИред рдореИрдВрдиреЗ рдУрд░реЗрдХрд▓ рдХреЗ рд╕рд╛рде рдЕрдкрдирд╛ рдЖрдИрдЯреА рдХрд░рд┐рдпрд░ рд╢реБрд░реВ рдХрд┐рдпрд╛ рдФрд░ рдореБрдЦреНрдп рд╡рд┐рд╢реЗрд╖рдЬреНрдЮ - рдЯреЙрдо рдХрд╛рдЗрдЯ рдХреА рдкреБрд╕реНрддрдХреЛрдВ рд╕реЗ рдЗрд╕ рдбреЗрдЯрд╛рдмреЗрд╕ рдХрд╛ рдЕрдзреНрдпрдпрди рдХрд┐рдпрд╛ред рдореБрдЭреЗ рдпрд╛рдж рд╣реИ рдХрд┐ "рдкреНрд░рднрд╛рд╡реА рдУрд░реЗрдХрд▓ рдмрд╛рдп рдбрд┐рдЬрд╛рдЗрди" рдкреБрд╕реНрддрдХ рд╕реЗ рд▓реЙрдЧрд┐рдВрдЧ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЙрдирдХрд╛ рд╡рд╛рдХреНрдпрд╛рдВрд╢:
рдЗрдВрд╕реНрдЯреНрд░реВрдореЗрдВрдЯреЗрд╢рди рдУрд╡рд░рд╣реЗрдб рдирд╣реАрдВ рд╣реИред рдУрд╡рд░рд╣реЗрдб рдПрдХ рдРрд╕реА рдЪреАрдЬ рд╣реИ рдЬрд┐рд╕реЗ рдЖрдк рдмрд┐рдирд╛ рдЬреНрдпрд╛рджрд╛ рдлрд╛рдпрджрд╛ рдЦреЛрдП рдирд┐рдХрд╛рд▓ рд╕рдХрддреЗ рд╣реИрдВред рд╣рдЯрд╛рдиреЗ (рдпрд╛ рдирд╣реАрдВ) рдЗрдВрд╕реНрдЯреНрд░реВрдореЗрдВрдЯреЗрд╢рди рдХрд╛рдлреА рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХреЛ рджреВрд░ рд▓реЗ рдЬрд╛рддрд╛ рд╣реИред рдЖрдкрдХреЛ рдпрд╣ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реЛрдЧреА рдпрджрд┐ рдЖрдкрдХреЗ рд╕рд┐рд╕реНрдЯрдо рдХрднреА рдирд╣реАрдВ рдЯреВрдЯреЗрдВрдЧреЗ, рдХрднреА рдирд┐рджрд╛рди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реЛрдЧреА, рдФрд░ рдкреНрд░рджрд░реНрд╢рди рдХреЗ рдореБрджреНрджреЛрдВ рд╕реЗ рдХрднреА рднреА рдкреАрдбрд╝рд┐рдд рдирд╣реАрдВ рд╣реЛрдВрдЧреЗред рдпрджрд┐ рдпрд╣ рд╕рдЪ рд╣реИ, рддреЛ рдЖрдкрдХреЛ рдЕрдкрдиреЗ рд╕рд┐рд╕реНрдЯрдо рдХреЛ (рдФрд░ рдореБрдЭреЗ рдЕрдкрдирд╛ рдИрдореЗрд▓ рдкрддрд╛ рднреЗрдЬрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдореЗрд░реЗ рдкрд╛рд╕ рдЖрдкрдХреЗ рд▓рд┐рдП рдиреМрдХрд░реА рдХрд╛ рдкреНрд░рд╕реНрддрд╛рд╡ рд╣реИ)ред
рдУрд░реЗрдХрд▓ рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдкрд░ рдХрд╛рдо рдХреЗ рд╕рд╛рде, рдпрд╣ рд╕рдм рд╢реБрд░реВ рд╣реБрдЖред
рдУрд░реЗрдХрд▓ рдореЗрдВ рдкрджрд╛рдиреБрдХреНрд░рдо рд▓реЙрдЧрд┐рдВрдЧ
рдХреБрдЫ рд╕рдордп рдкрд╣рд▓реЗ рдореИрдВ рдУрд░реЗрдХрд▓ рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рдкрд░ рдПрдХ рдмрдбрд╝рд╛ рдбреЗрдЯрд╛ рд╡реЗрдпрд░рд╣рд╛рдЙрд╕ рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдиреЗ рдХреА рдкрд░рд┐рдпреЛрдЬрдирд╛ рдкрд░ рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рдерд╛ред рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдкреАрдПрд▓ / рдПрд╕рдХреНрдпреВрдПрд▓ рдореЗрдВ рдбреЗрдЯрд╛ рд▓реЛрдб рдХрд░рдиреЗ, рдЬрд╛рдВрдЪрдиреЗ, рд╕рдореГрджреНрдз рдХрд░рдиреЗ рдХрд╛ рддрд░реНрдХ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред рд▓реЙрдЧрд┐рдВрдЧ рдХреЗ рд╕рдВрдмрдВрдз рдореЗрдВ, рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╡рд┐рдЪрд╛рд░ рдкреНрд░рд╕реНрддрд╛рд╡рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред рдпрджрд┐ рдЖрдк рдХрд┐рд╕реА рднреА рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рд╡рд┐рд╢реНрд╡ рд╕реНрддрд░ рдкрд░ рджреЗрдЦрддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рдлрд╝рдВрдХреНрд╢рди / рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ (рд╡рд┐рдзрд┐рдпреЛрдВ) рдХреЗ рд▓рд┐рдП рдХреЙрд▓ рдХрд╛ рдПрдХ рдкреЗрдбрд╝ рд╣реИред рдЙрд╕реА рд╕рдордп, рдЕрдкрдиреЗ рдЖрдк рдореЗрдВ рдПрдХ рд╡рд┐рдзрд┐ рдХрдИ рдмрд╛рд▓ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рдХреЙрд▓ рдХрд░ рд╕рдХрддреА рд╣реИ, рд▓реЗрдХрд┐рди рдЗрд╕рдХреА рдХреЙрд▓ рдПрдХ рдореВрд▓ рд╡рд┐рдзрд┐ рд╕реЗ рд╣реЛрддреА рд╣реИред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдо рддрд░реАрдХреЗ (рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ /) рд╣реИ, рдЬреЛ рд╕реНрд╡рд╛рднрд╛рд╡рд┐рдХ рд░реВрдк рд╕реЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдореЙрдбрд▓рд┐рдВрдЧ рдХреА рд╣реИ рдХреЗ рдмреАрдЪ рдорд╛рддрд╛ рдкрд┐рддрд╛ / рдмрдЪреНрдЪреЗ рдкрджрд╛рдиреБрдХреНрд░рдо рдорд┐рд▓ рдЖрдИрдбреА , PARENT_ID рдХреНрд╖реЗрддреНрд░реЛрдВ , рдЬрд╣рд╛рдВ PARENT_ID рдкрд░ рд╡рд┐рджреЗрд╢реА рдХреБрдВрдЬреА рд╣реИ рдЖрдИрдбреА рдХреНрд╖реЗрддреНрд░ред рдпрд╣ рдареАрдХ рд╡реИрд╕рд╛ рд╣реА рд╕рдВрдмрдВрдз рд╣реИ рдЬреИрд╕рд╛ рдХрд┐ рдХрд░реНрдордЪрд╛рд░рд┐рдпреЛрдВ рдФрд░ рдЙрдирдХреЗ рдкреНрд░рдмрдВрдзрдХреЛрдВ рдХреЗ рд╕рд╛рде рдХреНрд▓рд╛рд╕рд┐рдХ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ (рдПрдХ рдХрд░реНрдордЪрд╛рд░реА рдореЗрдВ рдХреЗрд╡рд▓ рдПрдХ рдкреНрд░рдмрдВрдзрдХ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рдПрдХ рдкреНрд░рдмрдВрдзрдХ рдХреЗ рдкрд╛рд╕ рдХрдИ рдХрд░реНрдордЪрд╛рд░реА рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ)ред рд▓реЙрдЧрд┐рдВрдЧ рдпреЛрдЬрдирд╛ рдХреЛ рдирд┐рдореНрдирд╛рдиреБрд╕рд╛рд░ рд╡рд░реНрдгрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:
create table log_instances (
start_log_id number(16) not null
, log_instance_name varchar2(100) not null
, start_ts timestamp(6) not null
, end_ts timestamp(6)
, status varchar2(1) not null
, log_date date not null,
, constraint log_instances_pk primary key(start_log_id))
/
create index log_instances_name_idx on log_instances(log_instance_name)
/
create table log_table (
action_name varchar2(64) not null,
log_id NUMBER(16) not null,
parent_log_id NUMBER(16),
start_ts timestamp(6) not null,
end_ts timestamp(6),
status varchar2(1) not null,
comments varchar2(4000),
exception_message varchar2(4000),
large_text CLOB,
log_date date not null,
constraint log_table_status_chck check (status in ('C', 'R', 'F'))
)
partition by range (log_date)
interval(NUMTODSINTERVAL(7,'day'))
(partition p_fst_day_of_week values less than (date '...'))
/
create index log_table_log_id_idx on log_table(log_id) local
/
create index log_table_parent_id_idx on log_table(parent_log_id) local
/
create index log_table_action_name_idx on log_table(action_name) local
/
рдкрд╣рд▓реЗ log_instances рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдкреНрд░рд╛рд░рдВрдн рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рд╣реЛрддреА рд╣реИ:
- log_instance_name - рдирд╛рдо, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, "sample_app_20200501"
- start_ts / end_ts - рд▓реЙрдЧрд┐рдВрдЧ рдХрд╛ рдкреНрд░рд╛рд░рдВрдн рдФрд░ рд╕рдорд╛рдкреНрддрд┐ рд╕рдордп ( рдпрджрд┐ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╡рд░реНрддрдорд╛рди рдореЗрдВ рдЪрд▓ рд░рд╣рд╛ рд╣реИ рддреЛ end_ts рдЦрд╛рд▓реА рд╣реИ)
- рд╕реНрдерд┐рддрд┐ - 'рд╕реА' (рдкреВрд░реНрдг) - рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЗ рдмрд┐рдирд╛ рд╕рдорд╛рдкреНрдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдЖрд╡реЗрджрди, 'рдЖрд░' (рдЪрд▓ рд░рд╣рд╛ рд╣реИ) - рдЖрд╡реЗрджрди рдЪрд▓ рд░рд╣рд╛ рд╣реИ, 'рдПрдл' (рд╡рд┐рдлрд▓) - рдЖрд╡реЗрджрди рдПрдХ рддреНрд░реБрдЯрд┐ рдХреЗ рд╕рд╛рде рд╕рдорд╛рдкреНрдд рд╣реБрдЖред
- start_log_id рдХреЙрд▓ рдкрджрд╛рдиреБрдХреНрд░рдо рдореЗрдВ рд░реВрдЯ рдЖрдИрдбреА рд╣реИред
log_table .
- action_name тАФ
- start_ts/end_ts тАФ /
- status тАФ 'C' (completed) тАФ , 'R'(running) тАФ , 'F'(failed) тАФ .
- exception_message тАФ , error stack trace ,
API ( Oracle API / ). :
- PROCEDURE start_logging(instance_name) тАФ , , log_instances
- PROCEDURE open_next_level(action_name, comments, clob_text) тАФ . log_table
- PROCEDURE close_level_success тАФ 'C'
- PROCEDURE close_level_fail тАФ 'F'
- PROCEDURE stop_log_success тАФ 'C'
- PROCEDURE stop_log_fail тАФ 'F'
( Oracle ):
- id
- id, INSERT/UPDATE log_table
- id log_table ,
pk_util_log . API :
-info тАФ open_level close_level. - logger.info Java.
-resume_logging (parent_log_id) тАФ . id log_table.
DECLARE
PROCEDURE b(p_name_in IN VARCHAR2) IS
v_dummy_cnt PLS_INTEGER;
BEGIN
pk_util_log.open_next_level(p_action_name_in => 'In procedure b()',
p_comments_in => 'procedure B(), line: ' || $$PLSQL_LINE || chr(13) || chr(10) ||
'p_name_in: ' || p_name_in);
dbms_lock.sleep(3);
pk_util_log.close_level_success;
EXCEPTION
WHEN OTHERS THEN
pk_util_log.close_level_fail;
RAISE;
END;
PROCEDURE a(p_name_in IN VARCHAR2) IS
BEGIN
pk_util_log.open_next_level(p_action_name_in => 'In procedure a()',
p_comments_in => 'procedure A(), line: ' || $$PLSQL_LINE || chr(13) || chr(10) ||
'p_name_in: ' || p_name_in);
b('dummy_b');
dbms_lock.sleep(2);
pk_util_log.close_level_success;
EXCEPTION
WHEN OTHERS THEN
pk_util_log.close_level_fail;
RAISE;
END;
BEGIN
pk_util_log.start_logging('sample_app_20200501');
dbms_output.put_line(pk_util_log.get_start_log_id);
a('dummy_a');
pk_util_log.stop_log_success;
exception
when others then
pk_util_log.stop_log_fail;
raise;
END;
/
start_log_id:
select start_log_id from log_instances where log_instance_name = 'sample_app_20200501';
start_log_id :
SELECT
LPAD (' ', 2* (LEVEL- 1)) || l.action_name as action_name,
l.status,
l.start_ts,
l.end_ts,
l.comments
FROM
tech_log_table l
START WITH l.log_id = 204
CONNECT BY
l.parent_log_id = PRIOR l.log_id
ORDER SIBLINGS BY
l.log_id ASC;
, a(p_name_in) b(p_name_in).
- , , , .
- , , . : , .
- , , . SQL . email id .
:
- DML log_table (log_id). log_id sequence Oracle, . sequence .
- log_table , . Oracle , . , .
Oracle , Java. Java API.
Java
, , . PostgreSql Oracle Open Source.
, Connection , Connection Pool ( HikariCP).
. Java thread'. ThreadLocal, InheritableThreadLocal, thread .
API
:
- public static void startLog(final String logInstanceName)
- public static void openNextLevel(final String actionName, final String comments)
- public static void stopLogSuccess()
- public static void stopLogFail(final Exception exception)
- public static void closeLevelSuccess()
- public static void closeLevelFail(final Exception exception)
:
public class A {
public static void main(String[] args) {
try {
LogUtils.startLog("sample_app_20200501");
A a = new A();
a.method1("some string");
LogUtils.stopLogSuccess();
} catch (Exception e) {
LogUtils.stopLogFail(e);
throw new RuntimeException(e);
}
}
private String method1(String s) {
try {
LogUtils.openNextLevel("method1", "Arguments: " + s);
method2(1, 2);
LogUtils.closeLevelSuccess();
return s;
} catch (Exception e) {
LogUtils.closeLevelFail(e);
throw new RuntimeException(e);
}
}
private long method2(int i1, int i2) {
try {
LogUtils.openNextLevel("method2", "Arguments: " + i1 + ", " + i2);
LogUtils.closeLevelSuccess();
return i1 + i2;
} catch (Exception e) {
LogUtils.closeLevelFail(e);
throw new RuntimeException(e);
}
}
}
, log_instances id (start_log_id) . PostgreSql RECURSIVE WITH:
WITH RECURSIVE log AS (
SELECT 1 as level,
ARRAY [l.log_id] AS path,
l.log_id,
l.action_name,
l.parent_log_id,
l.start_ts,
l.end_ts,
l.status,
l.comments,
l.exception_message
FROM log_table l
WHERE l.log_id = ...
UNION ALL
SELECT l.level + 1 as level,
path || l1.log_id,
l1.log_id,
l1.action_name,
l1.parent_log_id,
l1.start_ts,
l1.end_ts,
l1.status,
l1.comments,
l1.exception_message
FROM log_table l1
INNER JOIN log l ON l.log_id = l1.parent_log_id
)
SELECT
lpad(' ', (l.level - 1) * 2) || l.log_id as log_id,
l.action_name,
l.start_ts,
l.end_ts,
l.end_ts - l.start_ts as duration,
l.status,
l.comments,
l.exception_message
FROM log l
order by l.path, l.start_ts;
Boilerplate Aspect Oriented Programming
, , , exception :
try {
LogUtils.openNextLevel(...);
...
LogUtils.closeLevelSuccess();
} catch (Exception e) {
LogUtils.closeLevelFail(e);
throw new RuntimeException(e);
}
"" , . code templates, IDE . : Aspect Oriented Programming (AOP). , , AOP тАФ , (cross-cutting concerns). , , . AOP (advice) , (pointcut). pointcut advice . , . (weave) : compile-time, post-compile, load-time. compile-time weaving, AOP AspectJ.
, @LogToDb, , . :
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogToDb {
boolean suppressLogArgs() default false;
boolean suppressLogResult() default false;
}
:
@Aspect
public class LogToDbAspect {
@Pointcut("@annotation(logToDb) && execution(* *.*(..))")
public void logToDbPointcut(LogToDb logToDb) {
}
@Around(value = "logToDbPointcut(logToDb)")
public Object around(ProceedingJoinPoint pjp, LogToDb logToDb) throws Throwable {
try {
LogUtils.openNextLevel(pjp.getSignature().toShortString(),
logToDb.suppressLogArgs() ? null : AspectUtils.getArgsString(pjp.getArgs()));
Object result = pjp.proceed();
if (!logToDb.suppressLogResult()) {
LogUtils.addComments("\nResult: " + result.toString());
}
LogUtils.closeLevelSuccess();
return result;
} catch (Exception e) {
LogUtils.closeLevelFail(e);
throw new RuntimeException(e);
}
}
}
boilerplate :
private String method1(String s) {
try {
LogUtils.openNextLevel("method1", "Arguments: " + s);
LogUtils.addComments("\nResult: " + s);
LogUtils.closeLevelSuccess();
return s;
} catch (Exception e) {
LogUtils.closeLevelFail(e);
throw new RuntimeException(e);
}
}
:
@LogToDb
private String method1(String s) {
return s;
}
:
- compile-time weaving aspectjc.
- aspectjc , . aspectjc Lombok. :
[WARNING] You aren't using a compiler supported by lombok, so lombok will not work and has been disabled.
Your processor is: org.aspectj.org.eclipse.jdt.internal.compiler.apt.dispatch.BatchProcessingEnvImpl
Lombok supports: sun/apple javac 1.6, ECJ
lombok-maven-plugin, aspectjc lombok.
:
- :
- exception
- parent/child (/)
- :
- :
- Java :
- . DevOps .
- boilerplate AOP, ( , runtime).
- , . Connection pool, , , тАФ . . DML .
GitHub:
рдУрд░реЗрдХрд▓ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди:
- https://github.com/nikita-mospan/plsql-liquibase-utplsql/blob/master/src/main/resources/oracle/tech_user/packages/pk_util_log.pks
- https://github.com/nikita-mospan/plsql-liquibase-utplsql/blob/master/src/main/resources/oracle/tech_user/packages/pk_util_log.pkb
рдЬрд╛рд╡рд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди:
- https://github.com/nikita-mospan/log-to-db