Журналирование (логирование) результатов операций в СУБД

Журналирование результатов операций в СУБД необходимо в двух случаях.

  • Чтобы обеспечить журналирование операций внутри транзакции, т.е. запись в журнале (лог)е формируется только в случае реального изменения основной операцией базы данных;

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

Структура таблицы журналирования

/** Логирование */
CREATE TABLE Log
(
    id             VARCHAR(50) NOT NULL PRIMARY KEY,
    /** Тип действия: login, logout, update_user_info, create_qt, create_mt, finish_qt, finish_mt, change_roles, login_on_behalf */
    type           VARCHAR(30) NOT NULL,
    /** Дополнительное описание события */
    description    TEXT,
    /** Идентификатор объекта, с которым происходит событие */
    object_id      VARCHAR(100),
    /** Базовый инициатор операции */
    originator_sid VARCHAR(100) NOT NULL,
    /** Пользователь, от имени которого и с правами которого выполняется действие */
    user_sid       VARCHAR(100) NOT NULL,
    /** Дата и время совершения действия */
    timestamp      DATETIME    NOT NULL DEFAULT GETDATE(),
    /** Успешность операции */
    result         BIT                  DEFAULT TRUE
);

Процедура логирования

public static void writeDbLog(@NotNull CallContext context, @NotNull UserInfo userInfo, @NotNull Action action,
                              @NotNull String objectId, String description, @NotNull boolean result) {
    try (LogCursor logCursor = new LogCursor(context)) {
        logCursor
                .setId(UUID.randomUUID().toString())
                .setType(action.label)
                .setOriginatorSid(userInfo.getSid())
                .setUserSid(userInfo.getSid())
                .setOriginatorSid(userInfo.getOriginatorSid())
                .setObjectId(objectId)
                .setDescription(description)
                .setTimestamp(new Date())
                .setResult(result)
                .insert();
        log.info(description);
    } catch (CelestaException e) {
        log.error(e);
    }
}
Примеры видов действий
public enum Action {
    LOGIN("Login"),
    LOGOUT("Logout"),
    UPDATE_USER_INFO("Update user info"),
    DELETE_USER_INFO("Delete user info"),
    CHANGE_ROLES("Change roles"),
    LOGIN_ON_BEHALF("Login on behalf"),

    public final String label;

    Action(String label) {
        this.label = label;
    }
}

Вызов журналирования

if (userCursor.tryUpdate()) {
    Logger.writeDbLog(context, userInfo, Action.UPDATE_USER_INFO, (userSid != null ? userSid : userInfo.getSid()), "Обновление данных пользователя", true);
    return getUser(context, userInfo, (userSid != null ? userSid : userInfo.getSid()));
} else {
    throw new St2ApiException("Could not update user data");
}