Over 10 years we help companies reach their financial and branding goals. Engitech is a values-driven technology agency dedicated.

Gallery

Contacts

411 University St, Seattle, USA

engitech@oceanthemes.net

+1 -800-456-478-23

Query

Utilizando o Trace Default do SQL Server

Neste artigo, vamos explorar a aplicação do trace padrão com um enfoque específico em eventos cruciais, tais como “Object:Created”, “Object:Altered” e “Object:Deleted”. Para otimizar essa análise, sugerimos a criação de um job dedicado à interpretação desses dados. Esse processo possibilita a identificação dos responsáveis por operações críticas, como a exclusão de uma tabela, além de determinar quando tais ações foram realizadas. O melhor aspecto é que essa análise pode ser conduzida sem a necessidade de ativar a auditoria, apenas realizando a leitura de informações já coletadas pelo trace padrão do SQL Server.

Para localizar o arquivo do trace padrão, utilize a consulta abaixo.

SELECT * FROM sys.traces WHERE is_default = 1

Com a query abaixo podemos obter quais são os 34 eventos que são coletados neste trace default. A query foi extraida do blog do Dirceu Resende .

DECLARE @id INT = ( SELECT id FROM sys.traces WHERE is_default = 1 )

SELECT DISTINCT
       eventid,
       name
FROM fn_trace_geteventinfo(@id) EI
    JOIN sys.trace_events TE ON EI.eventid = TE.trace_event_id;

Neste caso irei criar um job com o foco em eventos específicos como “Object:Created”, “Object:Altered” e “Object:Deleted” para que seja rastreado.

O Job é composto de 3 steps sendo eles:

  • Criação de um database com o nome de DBA
  • Criação de uma tabela com o nome de LogAuditDefault
  • Inserindo dados na tabela LogAuditDefault

O script utilizado para obter as informações foi encontrado no link SQLServerCentral – Identify who deleted your database or table , porém fiz uns ajuste para atender a minha necessidade e também o ajuste de qual arquivo “TRC” ser lido na hora da execução do job.

Fica ao seu critério configurar o schedule de execução do job, de acordo com a sua necessidade. Pois a cada execução do job ele irá acrescentar na tabela LogAuditDefault a diferença de dados que foram gerados desde da última execução do job.

No exemplo abaixo, é possível ver que o login “dev_jose” realizou uma operação de “Object:Deleted” no Object Name = Password, que possui o ObjectType = 8277-U, indicando que uma tabela foi deletada. Além disso, há também a operação de “Object:Created” no Object Name = v_erro, com o object type igual a 8278-V, indicando a criação de uma view.

A lista com todos os Object Type pode ser visualizada no site da documentação da Microsoft em ObjectType Trace Event Column .

Este job foi desenvolvido com o propósito de facilitar a identificação do login responsável por criar, alterar ou excluir objetos no banco de dados. É uma ferramenta valiosa para rastrear atividades cruciais dentro do sistema.

É crucial ressaltar a importância de realizar testes rigorosos em um ambiente de homologação antes de implementar o job em produção. Este procedimento garante que o job esteja funcionando conforme o esperado e que não haja interrupções inesperadas no ambiente de produção.

Segue abaixo o script completo do job.

USE [msdb]
GO

/****** Object:  Job [Coletando Informações do Trace Default]    Script Date: 29/09/2023 17:30:00 ******/
BEGIN TRANSACTION
DECLARE @ReturnCode INT
SELECT @ReturnCode = 0
/****** Object:  JobCategory [Data Collector]    Script Date: 29/09/2023 17:30:00 ******/
IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'Data Collector' AND category_class=1)
BEGIN
EXEC @ReturnCode = msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=N'Data Collector'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback

END

DECLARE @jobId BINARY(16)
EXEC @ReturnCode =  msdb.dbo.sp_add_job @job_name=N'Coletando Informações do Trace Default', 
		@enabled=1, 
		@notify_level_eventlog=0, 
		@notify_level_email=0, 
		@notify_level_netsend=0, 
		@notify_level_page=0, 
		@delete_level=0, 
		@description=N'Job de coleta do trace default habilitado na instância SQL Server capturando os eventos de Create, Delete, Altered', 
		@category_name=N'Data Collector', 
		@owner_login_name=N'sa', @job_id = @jobId OUTPUT
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [Criação Banco de dados DBA]    Script Date: 29/09/2023 17:30:00 ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Criação Banco de dados DBA', 
		@step_id=1, 
		@cmdexec_success_code=0, 
		@on_success_action=3, 
		@on_success_step_id=0, 
		@on_fail_action=2, 
		@on_fail_step_id=0, 
		@retry_attempts=0, 
		@retry_interval=0, 
		@os_run_priority=0, @subsystem=N'TSQL', 
		@command=N'--Criação Banco de dados DBA
 
USE [master]
IF  NOT EXISTS (SELECT name,* FROM sys.databases WHERE name = ''DBA'')
 
BEGIN
 
CREATE DATABASE [DBA]
 
END
 
GO', 
		@database_name=N'master', 
		@flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [Criação_da_Tabela_LogAuditDefault]    Script Date: 29/09/2023 17:30:00 ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Criação_da_Tabela_LogAuditDefault', 
		@step_id=2, 
		@cmdexec_success_code=0, 
		@on_success_action=3, 
		@on_success_step_id=0, 
		@on_fail_action=2, 
		@on_fail_step_id=0, 
		@retry_attempts=0, 
		@retry_interval=0, 
		@os_run_priority=0, @subsystem=N'TSQL', 
		@command=N'--Criação Tabela LogAuditDefault
USE [DBA]
IF  NOT EXISTS (SELECT * FROM sys.objects
WHERE object_id = OBJECT_ID(N''[dbo].[LogAuditDefault]'') AND type in (N''U''))
BEGIN
 
use [DBA]
 
CREATE  TABLE [LogAuditDefault]
(   [ID] INT IDENTITY,
    [name] NVARCHAR(128),
    [ApplicationName] NVARCHAR(256),
    [BigintData1] BIGINT,
    [ClientProcessID] INT,
    [ColumnPermissions] INT,
    [DatabaseID] INT,
    [DatabaseName] NVARCHAR(256),
    [DBUserName] NVARCHAR(256),
    [Duration] BIGINT,
    [EndTime] DATETIME,
    [Error] INT,
    [EventSequence] BIGINT ,
    [EventSubClass] NVARCHAR(139),
    [FileName] NVARCHAR(256),
    [HostName] NVARCHAR(256),
    [IndexID] INT,
    [IntegerData] INT,
    [IsSystem] INT,
    [LineNumber] INT,
    [LoginName] NVARCHAR(256),
    [LoginSid] IMAGE,
    [NestLevel] INT,
    [NTDomainName] NVARCHAR(256),
    [NTUserName] NVARCHAR(256),
    [ObjectID] INT,
    [ObjectID2] BIGINT,
    [ObjectName] NVARCHAR(256),
    [ObjectType] NVARCHAR(139),
    [OwnerName] NVARCHAR(256),
    [ParentName] NVARCHAR(256),
    [Permissions] BIGINT,
    [RequestID] INT,
    [RoleName] NVARCHAR(256),
    [ServerName] NVARCHAR(256),
    [SessionLoginName] NVARCHAR(256),
    [Severity] INT,
    [SPID] INT,
    [StartTime] DATETIME,
    [State] INT,
    [Success] INT,
    [TargetLoginName] NVARCHAR(256),
    [TargetLoginSid] IMAGE,
    [TargetUserName] NVARCHAR(256),
    [TextData] NTEXT,
    [TransactionID] BIGINT,
    [Type] INT,
    [XactSequence] BIGINT
);
 
 
END', 
		@database_name=N'master', 
		@flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [Inserindo_dados_LogAuditDefault]    Script Date: 29/09/2023 17:30:00 ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Inserindo_dados_LogAuditDefault', 
		@step_id=3, 
		@cmdexec_success_code=0, 
		@on_success_action=1, 
		@on_success_step_id=0, 
		@on_fail_action=2, 
		@on_fail_step_id=0, 
		@retry_attempts=0, 
		@retry_interval=0, 
		@os_run_priority=0, @subsystem=N'TSQL', 
		@command=N'use [DBA]
 
DECLARE @path VARCHAR(MAX) = (SELECT [path] FROM sys.traces WHERE is_default = 1);
 
WITH cteObjectTypes AS
(
    SELECT
        TSV.trace_event_id,
        TSV.subclass_name,
        TSV.subclass_value
    FROM
        sys.trace_subclass_values AS TSV JOIN
        sys.trace_columns AS TC ON
            TSV.trace_column_id = TC.trace_column_id
    WHERE
        TC.[name] = ''ObjectType''
),
cteEventSubClasses AS
(
    SELECT
        TSV.trace_event_id,
        TSV.subclass_name,
        TSV.subclass_value
    FROM
        sys.trace_subclass_values AS TSV JOIN
        sys.trace_columns AS TC ON
            TSV.trace_column_id = TC.trace_column_id
    WHERE
        TC.[name] = ''EventSubClass''
)
 
INSERT INTO LogAuditDefault
SELECT
    TE.[name],
    I.ApplicationName,
    I.BigintData1,
    I.ClientProcessID,
    I.ColumnPermissions,
    I.DatabaseID,
    I.DatabaseName,
    I.DBUserName,
    I.Duration,
    I.EndTime,
    I.Error,
    I.EventSequence,
    CONVERT(NVARCHAR(10), I.EventSubClass) + N''-'' + ESC.subclass_name AS EventSubClass,
    I.FileName,
    I.HostName,
    I.IndexID,
    I.IntegerData,
    I.IsSystem,
    I.LineNumber,
    I.LoginName,
    I.LoginSid,
    I.NestLevel,
    I.NTDomainName,
    I.NTUserName,
    I.ObjectID,
    I.ObjectID2,
    I.ObjectName,
    CONVERT(NVARCHAR(10), I.ObjectType) + N''-'' + OT.subclass_name AS ObjectType,
    I.OwnerName,
    I.ParentName,
    I.Permissions,
    I.RequestID,
    I.RoleName,
    I.ServerName,
    I.SessionLoginName,
    I.Severity,
    I.SPID,
    I.StartTime,
    I.State,
    I.Success,
    I.TargetLoginName,
    I.TargetLoginSid,
    I.TargetUserName,
    I.TextData,
    I.TransactionID,
    I.Type,
    I.XactSequence
FROM
    sys.traces T CROSS APPLY
    sys.fn_trace_gettable (@path, DEFAULT)
     I JOIN
    sys.trace_events AS TE ON
        I.EventClass = TE.trace_event_id LEFT JOIN
    cteEventSubClasses AS ESC ON
        TE.trace_event_id = ESC.trace_event_id AND
        I.EventSubClass = ESC.subclass_value LEFT JOIN
    cteObjectTypes AS OT ON
        TE.trace_event_id = OT.trace_event_id AND
        I.ObjectType = OT.subclass_value
WHERE
    T.is_default = 1 AND
    TE.NAME IN (''Object:Deleted'', ''Object:Altered'', ''Object:Created'') AND
    NOT EXISTS (
        SELECT 1
          FROM LogAuditDefault LD
         WHERE LD.StartTime = I.StartTime
      AND LD.EventSequence = I.EventSequence
    )
    and I.ApplicationName not in (''godapp'',''SQLServerCEIP'')
    AND I.DatabaseName not in (''tempdb'',''DBA'')
ORDER BY I.StartTime DESC;', 
		@database_name=N'master', 
		@flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_add_jobschedule @job_id=@jobId, @name=N'Coleta_a_cada_30_minutos', 
		@enabled=1, 
		@freq_type=4, 
		@freq_interval=1, 
		@freq_subday_type=4, 
		@freq_subday_interval=30, 
		@freq_relative_interval=0, 
		@freq_recurrence_factor=0, 
		@active_start_date=20230926, 
		@active_end_date=99991231, 
		@active_start_time=0, 
		@active_end_time=235959, 
		@schedule_uid=N'1c6aa8e7-fe08-4262-9a71-7fa3c64025c0'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
COMMIT TRANSACTION
GOTO EndSave
QuitWithRollback:
    IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION
EndSave:
GO

Author

Wesley Cardoso