MySQL (почти) полный аудит - PullRequest
       18

MySQL (почти) полный аудит

3 голосов
/ 29 сентября 2010

Я ищу способ сделать простой журнал событий для моих таблиц. У меня есть несколько таблиц, которые могут быть изменены различными пользователями, и я хочу отслеживать:

- who made the change
- when 
- what was before update
- what is the new value
- which table and which record & column

что-то вроде будет здорово:

20:00:00 | john | update | products | 113 | product_name | "xbox" | "xbox 360"
20:00:10 | jim  | update | products | 113 | product_name | "xbox 360" | ""
20:01:00 | jim  | delete | products | 113

Итак, я прочитал, что триггеры могут быть ответом, но насколько я читаю, мне кажется, что мне нужна полная таблица для каждого столбца, который я хочу отслеживать. Триггеры не идеально подходят для этой работы также потому, что я хочу записать, кто внес изменение, и из того, что я прочитал, это невозможно.

Я подумал о создании 3 различных функций для CRUD (вставка, обновление, удаление) и непосредственно перед выполнением запроса, чтобы проверить, что изменилось, и создать журнал, а затем выполнить запрос. Но отсюда это кажется очень медленным и сложным.

Есть ли другой лучший способ?

Спасибо


Хорошо, я снова проверил триггеры, и это не то, что я искал, поэтому я написал простые функции, которые будут проверять для каждого запроса, который вы хотите регистрировать, если новые значения различны, и если так - он регистрирует его.

Основная проблема в том, что я ее не измерял, но она явно медленнее.

сначала вам нужно создать новую таблицу mysql следующим образом:

  • id (a_i, основной)
  • дата создания (дата / время)
  • user_id (int)
  • table_name (tinytext)
  • record_id (int)
  • имя_ ячейки (tinytext)
  • action_type (tinytext)
  • old_value (текст)
  • новое_значение (текст)

после этого напишите функции. Я еще не писал разделы «INSERT» и «DELETE», но думаю, мне должно быть намного легче.

function log_query($action_type, $table, $values, $parameters){

if ($action_type == 'UPDATE'){

    log_updates($action_type, $table, $values, $parameters);

    $query = "UPDATE $table SET ";
    foreach ($values as $key => $value){
        $query .= $key."='";
        $query .= $value."', ";
    }
    unset($value);

    $query = substr($query, 0, -2);

    $query .= ' WHERE ';

    foreach ($parameters as $key => $value){
        $query .= $key."='";
        $query .= $value."' AND ";
    }
    unset($value);

    $query = substr($query, 0, -4);

    $result = mysql_query($query);

    }
} 

и:

function log_updates($action_type, $table, $values, $parameters){
$where = " WHERE ";
$user_id = '1234'; //example
foreach ($parameters as $key => $value){
        $where .= $key."='";
        $where .= $value."' AND ";
}
unset($value);

$where = substr($where, 0, -4);

foreach ($values as $key => $value){
    $result = mysql_query("SELECT $key, id FROM $table $where");

    $row = mysql_fetch_row($result);
    $old_value = $row[0];
    $record_id = $row[1];

    if ($action_type == 'UPDATE'){
        if ($old_value != $value){
            $logger = mysql_query("INSERT INTO auditing (event_date, action_type, user_id, table_name, record_id, cell_name, old_value, new_value)
                                    VALUES (NOW(), '$action_type', $user_id, '$table', '$record_id', '$key', '$old_value', '$value')");
            if (!$logger) echo mysql_error();
        }
    } 


    }
    unset($value);

}

для вызова функций вам нужно сначала упорядочить параметры, чтобы найти конкретную строку, и новые значения в массивах, а после этого вызвать функцию log_query:

$update = Array('name' => 'barbara', 'description' => 'new name');
$parameters = Array('id' => '1', 'name' => 'barbi');
log_query('UPDATE', 'checktable', $update, $parameters);

Это действительно проверит, изменилось ли «имя» и изменилось ли описание. для каждого, если он изменится, он вставит новую запись в таблицу «аудита», указав точное изменение. после регистрации изменений будет запущен запрос на обновление. в нашем примере:

UPDATE checktable SET name='barbara', description='new name' WHERE id='1' AND name='barbi'

надеюсь, это помогает. Это проверено на данный момент и работает. Если будут обновления - выложу здесь.

audit - after the change

1 Ответ

1 голос
/ 29 сентября 2010

Хм, я тоже думал об этом.

  • Наличие таблицы для каждой таблицы для сохраняемых ревизий не будет такой большой проблемой для меня лично, но, эй.
  • Имя пользователя может быть сохранено с пользовательскими переменнымиЯ полагаю, (после начала сеанса выдайте что-то вроде SET @user='someone' и используйте это.
  • Пока есть триггеры после INSERT, UPDATE и DELETE, получение предыдущих / следующих значений - простой запрос, яЯ буду хранить только старые значения.

Короче говоря, для таблицы с столбцами (a, b, c) я бы создал таблицу со столбцами (user_id, modtime, a, b, c).).

Основные недостатки:

  • пакетные обновления медленные (поэтому выбирайте свои таблицы, чтобы тщательно следить за изменениями)
  • Дублирование данных люксу вас / у меня должно быть достаточно места для хранения
  • «связанные» данные не вызывают ревизию (то есть: изменение таблицы group_members на самом деле не изменяет таблицу groups, в то время какВы можете сохранить это как момент времени для groups, а не углубляться в group_members изменения.

В целом мне это кажется выгодным, но, как я редко видел на практике, там должны быть вескими причинами, почему это плохо, поэтому я будужду этих ответов.

...