Olá.
Recentemente surgiu uma demanda aqui para criar logs de rastreio de ações do usuário.
Exemplos hipotéticos:
O administrador jhon@doe.com bloqueou o usuário stack@overflow.com O moderador
harry@rocky.net alterou o limite de user@gmail.com de 400 para 1200.
Nos exemplos hipotéticos, demonstrei casos muito simples, mas ao modificar uma entidade qualquer, pode ser necessário mostrar também todos os campos que foram alterados.
Como isto é comumente feito? É uma string literal salva no banco? Existe algum padrão para implementar tal coisa?
Veja o Log4j
Como mostra o site do projeto, você pode salvar os logs onde quiser e da forma que desejar, caso queria customizar, eh claro.
Amigo, agradeço a intenção. Aqui já usamos o Serilog.
A questão não é emitir log em string simples, mas sim ter um rastreamento das ações e dos dados que o usuário alterou.
Praticamente um “antes” e “depois” da alteração, mas sem ter que montar uma string, checando propriedade a propriedade pra saber se foi alterada pra então montar o log.
De forma geral, acredito que não haja um padrão para isto, por hora vou me contentar em gravar logs em string + informações adicionais, talvez serializar a entidade em campos como “oldValue” and “newValue”.
Pela minha experiência em grandes empresas, os DBAs costumam usar triggers. Assim é mais seguro, temos o log garantido independente de qual aplicação ou ferramenta que tenham acessado o banco.
Abaixo exemplo em SQL Server, com a instrução FOR XML PATH podemos sem esforço gravar o antes e depois de toda a linha em XML. Outros bancos nao tenho exemplo.
CREATE TRIGGER TR_TABELA on TABELA
for INSERT, UPDATE, DELETE
AS
BEGIN
SET NOCOUNT ON;
IF NOT EXISTS(SELECT 1 FROM deleted) AND NOT EXISTS(SELECT 1 FROM inserted)
RETURN;
declare @tablename varchar(100)
SELECT @tablename = OBJECT_NAME(parent_object_id)
FROM sys.objects
WHERE sys.objects.name = OBJECT_NAME(@@PROCID)
DECLARE @ActionType char(1)
IF EXISTS (SELECT * FROM inserted)
IF EXISTS (SELECT * FROM deleted)
SELECT @ActionType = 'U'
ELSE
SELECT @ActionType = 'I'
ELSE
SELECT @ActionType = 'D'
declare @inserted xml, @deleted xml
SET @inserted = (SELECT * FROM inserted FOR XML PATH)
SET @deleted = (SELECT * FROM deleted FOR XML PATH)
INSERT INTO LOG
(NOME_TABELA, ACAO, USUARIO, HOST, XML_ANTES, XML_DEPOIS)
VALUES
(@tablename, @ActionType, SUSER_SNAME(), HOST_NAME(),@deleted, @inserted)
END
1 curtida
Entendi. Isso é chamado “auditoria” em alguns lugares.
Se você usa JPA, o Hibernate tem esse recurso automático. Caso não usar, tens que implementar manualmente.
Isso é feito salvando Strings no banco mesmo, na mesma transação que alterou o registro. Um objeto pode ter sua versão 1,2,3 etc… com detalhes da alteração, e até com o objeto inteiro duplicado coma informação antiga.
Você pode normalizar as tabelas da forma que desejar, usando associações, caso queira economizar recursos. Porém tens que ter equilíbrio nessa decisão para manter a performance (se isso for um problema).
Basicamente você pode fazer o que quiser para atender os requisitos.