Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / аудит [TCL] / 10 сообщений из 10, страница 1 из 1
23.08.2007, 16:16
    #34748428
Rastafarra
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аудит [TCL]
я в свое время нашел достаточно скудное описание того, как это надо делать, поэтому вот мой велосипед. может кому пригодится :)

основная идея заключается в том, что работать оно будет по 3-м таблицам: таблица, в которой будем держать имена таблиц для аудирования.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
CREATE TABLE t_audit_tables
(
  id serial NOT NULL, -- первичный ключ
  table_name character varying NOT NULL, -- название таблицы
  CONSTRAINT t_audit_tables_id PRIMARY KEY (id),
  CONSTRAINT "u_t_audit_tables->table_name" UNIQUE (table_name)
) 

таблица, в которой будет держать имена полей для аудирования.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
CREATE TABLE t_audit_table_fields
(
  id serial NOT NULL, -- первичный ключ
  table_id integer NOT NULL, -- таблица, к поторой это поле привязано.
  field_name character varying( 100 ) NOT NULL, -- название поля в таблице
  CONSTRAINT t_audit_table_fields_id PRIMARY KEY (id),
  CONSTRAINT fk_t_audit_table_fields FOREIGN KEY (table_id)
      REFERENCES t_audit_tables (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE CASCADE,
  CONSTRAINT "u_t_audit_table_fields->uniq" UNIQUE (table_id, field_name)
) 

и собсно таблица значений :)
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
CREATE TABLE t_audit_field_values
(
  id serial NOT NULL,
  field_id integer NOT NULL, -- поле, значение которого хранится
  field_value text, -- хранимое значение
  user_name text NOT NULL, -- пользователь, внесший изменение
  date_rec timestamp without time zone NOT NULL, -- дата записи.
  record_id integer NOT NULL DEFAULT  0 , -- номер строки, для которой ведем логи. надо для того, чтобы потом (скажем при инсерте) можно было собрать одну строку.
  ip inet DEFAULT inet_client_addr(), -- адрес, с которого было внесено изменение
  CONSTRAINT pk_audit_field_values PRIMARY KEY (id),
  CONSTRAINT fk_audit_field_values FOREIGN KEY (field_id)
      REFERENCES t_audit_table_fields (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
) 

и вот такой вот триггерок можно вешать сразу на все таблицы в базе. если логи по таблцие вести не надо, он их вести не будет. с другой стороны можно сделать админку, которой можно выставлять что надо вести в логах, а что нет.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
CREATE OR REPLACE FUNCTION audit_biu()
  RETURNS "trigger" AS
$BODY$
# --------------- by Rastafarra

# --------------- проверили чтобы не войти в рекурсию. ну мало ли? просто на всякий случай...
if {[string equal -nocase $TG_table_name "audit_field_values"]} then {
	return OK;
}

# --------------- посмотрели, надо ли вообще эту таблицку пихать в логи.
spi_exec -array log_array "select atf.field_name as field_name, atf.id as field_id from t_audit_table_fields atf
			inner join t_audit_tables at on at.id=atf.table_id
			where 
				at.table_name='$TG_table_name'"
if {[array size log_array] == "0"} then {
	return OK
}

--------------- эта штука выбирает имя primary key для произвольной таблицы.
set pk_name ""
spi_exec "SELECT a.attname AS pk_name FROM pg_class c, pg_attribute a, pg_index i
	WHERE c.relname = '$TG_table_name'
	AND c.oid=i.indrelid
	AND a.attnum > 0
	AND a.attrelid = i.indexrelid
	AND i.indisprimary='t'"

 --------------- эта штука выбирает для primary key произвольной таблицы собсно значение этого primary key
set pk_value ""
foreach field $TG_relatts {
	if {[string equal -nocase [lindex [array get NEW $field]  0 ] $pk_name]} {
		set pk_value [lindex [array get NEW $field]  1 ]
		break;
	}
}

switch $TG_op {
	INSERT {
		# начитали список полей для логов. может быть можно это сделать краше, но я не нашел пока как.
		spi_exec -array C "select atf.field_name as atf_field_name, atf.id as atf_id from t_audit_table_fields atf
					inner join t_audit_tables at on at.id=atf.table_id
					where 
						at.table_name='$TG_table_name'" {
			foreach field_name $TG_relatts {
				if {$C(atf_field_name) == $field_name} then {
					set field_value [string trim [lindex [array get NEW $field_name]  1 ]]
					set field_id $C(atf_id)
					spi_exec "insert into t_audit_field_values (field_value, field_id, user_name, date_rec, record_id)
						values ('$field_value', $field_id, user, CURRENT_TIMESTAMP, $pk_value)"
				}
			}
		}
	}
	UPDATE {
		# начитали список полей для логов. может быть можно это сделать краше, но я не нашел пока как.
		spi_exec -array C "select atf.field_name as atf_field_name, atf.id as atf_id from t_audit_table_fields atf
					inner join t_audit_tables at on at.id=atf.table_id
					where 
						at.table_name='$TG_table_name'" {
			foreach field_name $TG_relatts {
				if {$C(atf_field_name) == $field_name} then {
					set new_val [string trim [lindex [array get NEW $field_name]  1 ]]
					set old_val [string trim [lindex [array get OLD $field_name]  1 ]]
					if {$new_val != $old_val} then {
						set field_id $C(atf_id)
						spi_exec "insert into t_audit_field_values (field_value, field_id, user_name, date_rec, record_id)
							values ('$new_val', $field_id, user, CURRENT_TIMESTAMP, $pk_value)"
					}
				}
			}
		}
	}
	default { return OK }
}
return [array get NEW]
$BODY$
  LANGUAGE 'pltcl' VOLATILE;

комментарии приветствуются :)
...
Рейтинг: 0 / 0
23.08.2007, 16:19
    #34748435
Rastafarra
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аудит [TCL]
у меня есть даже замечание:

Код: plaintext
1.
2.
3.
# --------------- проверили чтобы не войти в рекурсию. ну мало ли? просто на всякий случай...
if {[string equal -nocase $TG_table_name "audit_field_values"]} then {
	return OK;
}

должно быть
Код: plaintext
1.
2.
3.
4.
# --------------- проверили чтобы не войти в рекурсию. ну мало ли? просто на всякий случай...
if {[string equal -nocase $TG_table_name "t_audit_field_values"]} then {
	return OK;
}

модераторы, поправьте :)
...
Рейтинг: 0 / 0
23.08.2007, 19:18
    #34749073
Ёш
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аудит [TCL]
я делал практически тоже самое, только чуть по другому. вместо общей audit_biu у меня были отдельные функции-тригеры для каждой наблюдаемой таблицы которые генерировались автоматически при помощи функции на plperl. вместо общей таблицы со значениями у меня были отдельные таблицы для каждой наблюдаемой, создавались по create table history.log_$table as select * from $table where false; + потом добавлялись служебные поля log_user_id log_transac_time и т.п.
наблюдались все поля, но впринципе можно было бы сделать ещё один параметр для той функции на plperl со списком полей.
так имхо получается быстрее, чем постоянно производить поиск списка полей в конфигурационных таблицах аудита.

--
„Истина — это вовсе не то, что можно убедительно доказать, это то, что
делает всё проще и понятнее“ — Антуан де Сент-Экзюпери
...
Рейтинг: 0 / 0
23.08.2007, 20:49
    #34749225
Rastafarra
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аудит [TCL]
а как потом админку добавить?
...
Рейтинг: 0 / 0
24.08.2007, 00:11
    #34749452
Taerix
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аудит [TCL]
А зачем все это делать на экзотическом PL/pgTCL?
...
Рейтинг: 0 / 0
24.08.2007, 07:07
    #34749562
Rastafarra
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аудит [TCL]
1. в нем экзотики не больше, чем в любом другом языке.
2. питон надо собирать особым образом (с тредами), чтобы можно было привернуть к постгресу, что есть лишнее и не всегда возможное телодвижение.
...
Рейтинг: 0 / 0
24.08.2007, 09:38
    #34749717
Ёш
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аудит [TCL]
Rastafarraа как потом админку добавить?например сделать табличку:
Код: plaintext
1.
2.
3.
4.
create table audit_cfg (
    tbl_name text,
    is_enabled boolean
);
повесить на неё триггер в котором удалять/добавлять триггеры на таблицы данных, но это только если не изменяются определения таблиц данных. если у таблиц с данными удаляются/добавляются колонки или меняются их типы данных то не получится, так как пока нельзя повесить триггер на DDL, придётся вручную вызвать функцию обновления.
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
22.07.2015, 09:47
    #39013015
max aka max
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аудит [TCL]
Rastafarraя в свое время нашел достаточно скудное описание того, как это надо делать, поэтому вот мой велосипед. может кому пригодится :)
комментарии приветствуются :)

А если ли что нибудь новое с учетом что версия PG уже 9,4
...
Рейтинг: 0 / 0
22.07.2015, 10:29
    #39013083
qwwq
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аудит [TCL]
max aka max,

ну можно hstore (спасибо олегу с теодором) приспособить -- чтобы всего вот этого "про конструкции" не хранить. и обойтись одной таблицей с hkeys -- hstore ,hbody--hstore

но там тоже плясать приходится при восстановлении типов-по-имени из pg_attribute.


hint: dblink содержит хорошую (быструю с-ную) ф-ю получения массива ключевых полей по имени таблицы. у меня она была быстрее запроса к pg_index[indisprimary] JOIN pg_attributes [ON indkey<->attnum] -- на случай разных ключей, а не токмо суррогатов (хотя лучше унифицировать и не связываться)
...
Рейтинг: 0 / 0
23.10.2015, 18:40
    #39085261
Нет меня
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
аудит [TCL]
max aka maxА если ли что нибудь новое с учетом что версия PG уже 9,4

Ну разве что, такое .
...
Рейтинг: 0 / 0
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / аудит [TCL] / 10 сообщений из 10, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]