Introdução
Muitas vezes, há a necessidade de informar de alguma forma os administradores sobre os problemas com um servidor. As notificações são geralmente divididas em 2 tipos:
1) notificações em tempo real, ou seja, aquelas que devem vir imediatamente quando ocorre um problema
2) notificações atrasadas, ou seja, aquelas que chegam depois de um tempo bastante longo (mais de 1 hora) após a ocorrência de um problema.
No meu trabalho, foi necessário estender a funcionalidade do SQL Server Database Mail normal.
Neste artigo, consideraremos um exemplo de como gerar notificações em tabelas HTML e enviá-las aos administradores.
Solução
1. Configurar correio de banco de dados
2. Crie uma tabela para destinatários:
[expandir título =”Código”]
USE [DATABASE_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [srv].[Recipient]( [Recipient_GUID] [uniqueidentifier] ROWGUIDCOL NOT NULL, [Recipient_Name] [nvarchar](255) NOT NULL, // um e-mail primário do destinatário [ Recipient_Code] [nvarchar](10) NOT NULL, // código do destinatário [IsDeleted] [bit] NOT NULL, // um indicador de exclusão (se um destinatário é usado ou não) [InsertUTCDate] [datetime] NOT NULL, CONSTRAINT [PK_Recipient ] PRIMARY KEY CLUSTERED ( [Recipient_GUID] ASC)WITH (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF, IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON [PRIMARY], CONSTRAINT [AK_Recipient_Code] UNIQUE NONCLUSTERED ( [Recipient_Code] ASC)WITH (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF, IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON [PRIMARY], CONSTRAINT [AK_Recipient_Name] UNIQUE NONCLUSTERED ([Recipient_Name] ASC)WITH (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OF F, IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON [PRIMARY]) ON [PRIMARY] GOALTER TABLE [srv].[Recipient] ADD CONSTRAINT [DF_Recipient_Recipient_GUID] DEFAULT (newsequentialid()) FOR [Recipient_GUID]GOALTER TABLE [ srv].[Recipient] ADICIONAR CONSTRAINT [DF_Recipient_IsDeleted] DEFAULT ((0)) FOR [IsDeleted]GOALTER TABLE [srv].[Recipient] ADICIONAR CONSTRAINT [DF_Recipient_InsertUTCDate] DEFAULT (getutcdate()) FOR [InsertUTCDate]GO
[/expand]
3. Crie uma tabela para endereços dos destinatários:
[expandir título =”Código”]
USE [DATABASE_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [srv].[Address]( [Address_GUID] [uniqueidentifier] ROWGUIDCOL NOT NULL, [Recipient_GUID] [uniqueidentifier] NOT NULL, // destinatário [Address] [nvarchar]( 255) NOT NULL, // email [IsDeleted] [bit] NOT NULL, // indicador de exclusão (se o email é usado ou não) [InsertUTCDate] [datetime] NOT NULL, CONSTRAINT [PK_Address] PRIMARY KEY CLUSTERED ( [Address_GUID] ASC )WITH (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF, IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON [PRIMARY], CONSTRAINT [AK_Address] UNIQUE NONCLUSTERED ( [Recipient_GUID] ASC, [Address] ASC)WITH (PAD_INDEX =OFF , STATISTICS_NORECOMPUTE =OFF, IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON [PRIMARY]) ON [PRIMARY]GOALTER TABLE [srv].[Address] ADD CONSTRAINT [DF_Address_Address_GUID] DEFAULT (newsequentialid()) FOR [Address_GUID] TABELA DE GOALTER [ srv].[Address] ADICIONAR CONSTRAINT [DF_Address_IsDeleted] DEFAULT ((0)) PARA [IsDeleted]GOALTER TABLE [srv].[Address] ADICIONAR CONSTRAINT [DF_Address_InsertUTCDate] DEFAULT (getutcdate()) FOR [InsertUTCDate]GO
[/expand]
4. Crie uma tabela para uma fila de mensagens:
[expandir título =”Código”]
USE [DATABASE_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [srv].[ErrorInfo]( [ErrorInfo_GUID] [uniqueidentifier] NOT NULL, [ERROR_TITLE] [nvarchar](max) NULL, // title [ERROR_PRED_MESSAGE] [nvarchar] (max) NULL, // informações preliminares [ERROR_NUMBER] [nvarchar](max) NULL, // código da mensagem (erro) [ERROR_MESSAGE] [nvarchar](max) NULL, // mensagem [ERROR_LINE] [nvarchar](max) NULL, // número da linha [ERROR_PROCEDURE] [nvarchar](max) NULL, // procedimento armazenado [ERROR_POST_MESSAGE] [nvarchar](max) NULL, // informações explicativas [RECIPIENTS] [nvarchar](max) NULL, // destinatários separados por ';' [InsertDate] [datetime] NOT NULL, [StartDate] [datetime] NOT NULL, // data e hora de início [FinishDate] [datetime] NOT NULL, // data e hora de término [Count] [int] NOT NULL, // número de vezes [UpdateDate] [dat etime] NOT NULL, [IsRealTime] [bit] NOT NULL, // indicador de tempo real [InsertUTCDate] [datetime] NULL, CONSTRAINT [PK_ErrorInfo] PRIMARY KEY CLUSTERED ( [ErrorInfo_GUID] ASC)WITH (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF, IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON [PRIMARY]) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]GOALTER TABLE [srv].[ErrorInfo] ADD CONSTRAINT [DF_ErrorInfo_ErrorInfo_GUID] DEFAULT (newid()) PARA [ErrorInfo_GUID]GOALTER TABLE [srv].[ErrorInfo] ADICIONAR CONSTRAINT [DF_ErrorInfo_InsertDate] DEFAULT (getdate()) PARA [InsertDate]GOALTER TABLE [srv].[ErrorInfo] ADICIONAR CONSTRAINT [DF_ErrorInfo_StartDate] DEFAULT (getdate()) FOR [StartDate]GOALTER TABLE [ srv].[ErrorInfo] ADICIONAR CONSTRAINT [DF_ErrorInfo_FinishDate] DEFAULT (getdate()) PARA [FinishDate]GOALTER TABLE [srv].[ErrorInfo] ADICIONAR CONSTRAINT [DF_ErrorInfo_Count] DEFAULT ((1)) FOR [Count]GOALTER TABLE [srv] .[ErrorInfo] ADICIONAR CONSTRAINT [DF__ErrorInfo__Updat__5FFEE747] DEFAU LT (getdate()) FOR [UpdateDate]GOALTER TABLE [srv].[ErrorInfo] ADICIONAR CONSTRAINT [DF_ErrorInfo_IsRealTime] DEFAULT ((0)) FOR [IsRealTime]GOALTER TABLE [srv].[ErrorInfo] ADICIONAR CONSTRAINT [DF_ErrorInfo_InsertUTCDate] DEFAULT ( getutcdate()) PARA [InserirUTCDate]GO
[/expand]
5. Crie uma tabela de arquivamento para mensagens enviadas da fila de mensagens:
[expandir título =”Código”]
USE [DATABASE_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [srv].[ErrorInfoArchive]( [ErrorInfo_GUID] [uniqueidentifier] ROWGUIDCOL NOT NULL, [ERROR_TITLE] [nvarchar](max) NULL, [ERROR_PRED_MESSAGE] [nvarchar](max ) NULL, [ERROR_NUMBER] [nvarchar](max) NULL, [ERROR_MESSAGE] [nvarchar](max) NULL, [ERROR_LINE] [nvarchar](max) NULL, [ERROR_PROCEDURE] [nvarchar](max) NULL, [ERROR_POST_MESSAGE] [nvarchar](max) NULL, [RECIPIENTS] [nvarchar](max) NULL, [InsertDate] [datetime] NOT NULL, [StartDate] [datetime] NOT NULL, [FinishDate] [datetime] NOT NULL, [Count] [ int] NOT NULL, [UpdateDate] [datetime] NOT NULL, [IsRealTime] [bit] NOT NULL, [InsertUTCDate] [datetime] NULL, CONSTRAINT [PK_ArchiveErrorInfo] PRIMARY KEY CLUSTERED ( [ErrorInfo_GUID] ASC)WITH (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF, IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON [PRIMARY]) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]GOALTE R TABLE [srv].[ErrorInfoArchive] ADICIONAR CONSTRAINT [DF_ErrorInfoArchive_ErrorInfo_GUID] DEFAULT (newsequentialid()) PARA [ErrorInfo_GUID]GOALTER TABLE [srv].[ErrorInfoArchive] ADICIONAR CONSTRAINT [DF_ArchiveErrorInfo_InsertDate] DEFAULT (getdate()) PARA [InsertDate]GOALTER TABLE [srv].[ErrorInfoArchive] ADICIONAR CONSTRAINT [DF_ErrorInfoArchive_StartDate] DEFAULT (getdate()) PARA [StartDate]GOALTER TABLE [srv].[ErrorInfoArchive] ADICIONAR CONSTRAINT [DF_ErrorInfoArchive_FinishDate] DEFAULT (getdate()) PARA [FinishDate]GOALTER TABLE [srv ].[ErrorInfoArchive] ADICIONAR CONSTRAINT [DF_ErrorInfoArchive_Count] DEFAULT ((1)) PARA [Count]GOALTER TABLE [srv].[ErrorInfoArchive] ADICIONAR CONSTRAINT [DF_ErrorInfoArchive_UpdateDate] DEFAULT (getdate()) FOR [UpdateDate]GOALTER TABLE [srv]. [ErrorInfoArchive] ADICIONAR CONSTRAINT [DF_ErrorInfoArchive_IsRealTime] DEFAULT ((0)) PARA [IsRealTime] GOALTER TABLE [srv].[ErrorInfoArchive] ADICIONAR CONSTRAINT [DF_ErrorInfoArchive_InsertUTCDate] DEFAULT (getutcdate()) PARA [InsertUTCDate]GO[/expand]
Esta informação é necessária para o histórico. Além disso, esta tabela precisa ser limpa de dados muito antigos (por exemplo, com mais de um mês).
6. Crie um procedimento armazenado que registre uma nova mensagem na fila de mensagens:
[expandir título =”Código”]
USE [DATABASE_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE PROCEDURE [srv].[ErrorInfoIncUpd] @ERROR_TITLE nvarchar(max), @ERROR_PRED_MESSAGE nvarchar(max), @ERROR_NUMBER nvarchar(max), @ERROR_MESSAGE nvarchar(max), @ERROR_LINE nvarchar(max), @ERROR_PROCEDURE nvarchar(max), @ERROR_POST_MESSAGE nvarchar(max), @RECIPIENTS nvarchar(max), @StartDate datetime=null, @FinishDate datetime=null, @IsRealTime bit =0ASBEGIN /* Erro ao registrar o erro tabela a ser enviada por e-mail caso a tabela já possua uma entrada com o mesmo título, conteúdo e remetente, a data final do erro, a data da atualização do registro, bem como o número de erros serão alterados */ SET NOCOUNT EM; declare @ErrorInfo_GUID identificador exclusivo; selecione top 1 @ErrorInfo_GUID=ErrorInfo_GUID de srv.ErrorInfo onde ([email protected]_TITLE ou @ERROR_TITLE é nulo) e [email protected] e ([email protected]_MESSAGE ou @ERROR_MESSAGE é nulo) e ([email protected]_PRED_MESSAGE ou @ERROR_PRED_MESSAGE é nulo) e ([email protected]_POST_MESSAGE ou @ERROR_POST_MESSAGE é nulo) e ([email protected] ou @IsRealTime é nulo); if(@ErrorInfo_GUID is null) begin insert into srv.ErrorInfo ( ERROR_TITLE ,ERROR_PRED_MESSAGE ,ERROR_NUMBER ,ERROR_MESSAGE ,ERROR_LINE ,ERROR_PROCEDURE ,ERROR_POST_MESSAGE ,RECIPIENTS ,IsRealTime ,StartDate ,FinishDate ) select @ERROR_TITLE ,@ERROR_PRED_MESSAGE ,@ERROR_NUMBER ,@ERROR_MESSAGE ,@ ERROR_LINE ,@ERROR_PROCEDURE ,@ERROR_POST_MESSAGE ,@RECIPIENTS ,@IsRealTime ,isnull(@StartDate, getdate()) ,isnull(@FinishDate,getdate()) end else begin update srv.ErrorInfo set FinishDate=getdate(), [Count]=[Count]+1, UpdateDate=getdate() onde [email protected]_GUID; endENDGO[/expand]
7. Crie um procedimento armazenado que retorne uma string dos endereços pelo código ou o endereço de e-mail principal de um destinatário:
[expandir título =”Código”]
USE [DATABASE_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE PROCEDURE [srv].[GetRecipients]@Recipient_Name nvarchar(255)=NULL,@Recipient_Code nvarchar(10)=NULL,@Recipients nvarchar(max) out/* O procedimento para criando notificações por e-mail*/ASBEGIN SET NOCOUNT ON; definir @Destinatários=''; selecione @[email protected]+d.[Endereço]+';' de srv.Recipient como r inner join srv.[Address] como d em r.Recipient_GUID=d.Recipient_GUID onde ([email protected]_Name ou @Recipient_Name IS NULL) e ([email protected]_Code ou @Recipient_Code IS NULL) e r.IsDeleted=0 e d.IsDeleted=0; --order by r.InsertUTCDate desc, d.InsertUTCDate desc; if(len(@Recipients)>0) set @Recipients=substring(@Recipients,1,len(@Recipients)-1);ENDGO[/expand]
8. Crie as funções necessárias para trabalhar com datas e horas:
[expandir título =”Código”]
USE [DATABASE_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE FUNCTION [rep].[GetDateFormat] ( @dt datetime, // data de entrada @format int=0 // formato predefinido)RETURNS nvarchar(255)AS/* Retorna a data como uma string de acordo com o formato especificado e a data de entrada Insere zeros quando necessário:formato da data de entrada resultado 0 17.4.2014 "17.04.2014" 1 17.4.2014 "04.2014" 1 8.11.2014 "11.2014" 2 17.04.2014 "2014" */BEGIN DECLARE @res nvarchar(255); DECLARE @dia int=DAY(@dt); DECLARE @mês int=MÊS(@dt); DECLARE @ano int=ANO(@dt); if(@format=0) start set @res=IIF(@day<10,'0'+cast(@day as nvarchar(1)), cast(@day as nvarchar(2)))+'.'; set @[email protected]+IIF(@mês<10,'0'+cast(@mês como nvarchar(1)), cast(@mês como nvarchar(2)))+'.'; set @[email protected]+cast(@ano como nvarchar(255)); end else if(@format=1) start set @res=IIF(@month<10,'0'+cast(@month as nvarchar(1)), cast(@month as nvarchar(2)))+'. '; set @[email protected]+cast(@ano como nvarchar(255)); end else if(@format=2) start set @res=cast(@year as nvarchar(255)); end RETURN @res;ENDGOUSE [DATABASE_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE FUNCTION [rep].[GetTimeFormat] ( @dt datetime, // tempo de entrada @format int=0 // formato predefinido)RETURNS nvarchar(255)AS/* Retorna hora como uma string de acordo com o formato especificado e a hora de entrada Insere zeros quando necessário:formato de entrada hora resultado 0 17:04 "17:04:00" 1 17:04 "17:04" 1 8:04 "08:04 " 2 17:04 "17"*/BEGIN DECLARE @res nvarchar(255); DECLARE @hora int=DATEPART(HORA, @dt); DECLARE @min int=DATEPART(MINUTE, @dt); DECLARE @sec int=DATEPART(SECOND, @dt); if(@format=0) start set @res=IIF(@hour<10,'0'+cast(@hour as nvarchar(1)), cast(@hour as nvarchar(2)))+':'; set @[email protected]+IIF(@min<10,'0'+cast(@min as nvarchar(1)), cast(@min as nvarchar(2)))+':'; set @[email protected]+IIF(@sec<10,'0'+cast(@sec as nvarchar(1)), cast(@sec as nvarchar(2))); end else if(@format=1) start set @res=IIF(@hour<10,'0'+cast(@hour as nvarchar(1)), cast(@hour as nvarchar(2)))+':'; set @[email protected]+IIF(@min<10,'0'+cast(@min como nvarchar(1)), cast(@min como nvarchar(2))); end else if(@format=2) start set @res=IIF(@hour<10,'0'+cast(@hour as nvarchar(1)), cast(@hour as nvarchar(2))); end RETURN @res;ENDGO[/expand]
9. Crie um procedimento armazenado que crie um relatório HTML em mensagens na forma de uma tabela:
[expandir título =”Código”]
USE [DATABASE_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE PROCEDURE [srv].[GetHTMLTable] @recipients nvarchar(max) ,@dt datetime // até qual data lerASBEGIN /* gera código HTML para a tabela */ SET NOCOUNT ON; declare @body nvarchar(max); declare @tbl table(ID int identity(1,1) ,[ERROR_TITLE] nvarchar(max) ,[ERROR_PRED_MESSAGE] nvarchar(max) ,[ERROR_NUMBER] nvarchar(max) ,[ERROR_MESSAGE] nvarchar(max) ,[ERROR_LINE] nvarchar (max) ,[ERROR_PROCEDURE] nvarchar(max) ,[ERROR_POST_MESSAGE] nvarchar(max) ,[InsertDate] datetime ,[StartDate] datetime ,[FinishDate] datetime ,[Count] int ); declare @ID int ,@ERROR_TITLE nvarchar(max) ,@ERROR_PRED_MESSAGE nvarchar(max) ,@ERROR_NUMBER nvarchar(max) ,@ERROR_MESSAGE nvarchar(max) ,@ERROR_LINE nvarchar(max) ,@ERROR_PROCEDURE nvarchar(max) ,@ERROR_POST_MESSAGE nvarchar (max) ,@InsertDate datetime ,@StartDate datetime ,@FinishDate datetime ,@Count int insert in @tbl( [ERROR_TITLE],[ERROR_PRED_MESSAGE],[ERROR_NUMBER],[ERROR_MESSAGE],[ERROR_LINE],[ERROR_PROCEDURE],[ERROR_POST_MESSAGE] ] ,[InsertDate],[StartDate],[FinishDate],[Count]) selecione os 100 principais [ERROR_TITLE],[ERROR_PRED_MESSAGE],[ERROR_NUMBER] ,[ERROR_MESSAGE],[ERROR_LINE],[ERROR_PROCEDURE],[ERROR_POST_MESSAGE],[InsertDate],[StartDate],[FinishDate],[Count] from [srv].[ErrorInfo] onde ([RECIPIENTS][email protected] ) ou (@recipients IS NULL) e InsertDate'; set @example@sqldat.com+' '; set @[email protected]+' '; while((selecione top 1 1 de @tbl)>0) start set @[email protected]+''; set @[email protected]+'№ п/п'; set @[email protected]+' '; set @[email protected]+''; set @[email protected]+'DATA'; set @[email protected]+' '; set @[email protected]+''; set @[email protected]+'ERRO'; set @[email protected]+' '; set @[email protected]+''; set @[email protected]+'DESCRIPTION'; set @[email protected]+' '; set @[email protected]+''; set @[email protected]+'CÓDIGO DE ERRO'; set @[email protected]+' '; set @[email protected]+''; set @[email protected]+'MESSAGE'; set @[email protected]+' '; set @[email protected]+''; set @[email protected]+'START'; set @[email protected]+' '; set @[email protected]+''; set @[email protected]+'FINISH'; set @[email protected]+' '; set @[email protected]+''; set @[email protected]+'NUMBER'; set @[email protected]+' '; set @[email protected]+''; set @[email protected]+'LINE NUMBER'; set @[email protected]+' '; set @[email protected]+''; set @[email protected]+'PROCEDURE'; set @[email protected]+' '; set @[email protected]+''; set @[email protected]+'NOTA'; set @[email protected]+' '; set @[email protected]+''; selecione os 1 primeiros @ID =[ID] ,@ERROR_TITLE =[ERROR_TITLE] ,@ERROR_PRED_MESSAGE=[ERROR_PRED_MESSAGE],@ERROR_NUMBER =[ERROR_NUMBER] ,@ERROR_MESSAGE =[ERROR_MESSAGE],@ERROR_LINE =[ERROR_LINE],@ERROR_PROCEDURE =[ERROR_PROCEDURE =[ERROR_PROCEDURE] ] ,@ERROR_POST_MESSAGE=[ERROR_POST_MESSAGE] ,@InsertDate =[InsertDate] ,@StartDate =[StartDate] ,@FinishDate =[FinishDate] ,@Count =[Count] da ordem @tbl por InsertDate asc; set @[email protected]+' '; end set @[email protected]+''; selecione @body;ENDGO'; set @[email protected]+cast(@ID as nvarchar(max)); set @[email protected]+' '; set @[email protected]+''; set @[email protected]+rep.GetDateFormat(@InsertDate, default)+' '+rep.GetTimeFormat(@InsertDate, default); // cast(@InsertDate as nvarchar(max)); set @[email protected]+' '; set @[email protected]+''; set @[email protected]+isnull(@ERROR_TITLE,''); set @[email protected]+' '; set @[email protected]+''; set @[email protected]+isnull(@ERROR_PRED_MESSAGE,''); set @[email protected]+' '; set @[email protected]+''; set @[email protected]+isnull(@ERROR_NUMBER,''); set @[email protected]+' '; set @[email protected]+''; set @[email protected]+isnull(@ERROR_MESSAGE,''); set @[email protected]+' '; set @[email protected]+''; set @[email protected]+rep.GetDateFormat(@StartDate, default)+' '+rep.GetTimeFormat(@StartDate, default); //cast(@StartDate as nvarchar(max)); set @[email protected]+' '; set @[email protected]+''; set @[email protected]+rep.GetDateFormat(@FinishDate, default)+' '+rep.GetTimeFormat(@FinishDate, default); //cast(@FinishDate as nvarchar(max)); set @[email protected]+' '; set @[email protected]+''; set @[email protected]+cast(@Count as nvarchar(max)); set @[email protected]+' '; set @[email protected]+''; set @[email protected]+isnull(@ERROR_LINE,''); set @[email protected]+' '; set @[email protected]+''; set @[email protected]+isnull(@ERROR_PROCEDURE,''); set @[email protected]+' '; set @[email protected]+''; set @[email protected]+isnull(@ERROR_POST_MESSAGE,''); set @[email protected]+' '; delete de @tbl onde [email protected]; set @[email protected]+'[/expand]
10. Crie um procedimento armazenado que envie mensagens:
[expandir título =”Código”]
USE [DATABAE_NAME]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE PROCEDURE [srv].[RunErrorInfoProc] @IsRealTime bit =0 // modo de envio (1-tempo real)ASBEGIN /* envia notificações de erro com o modo especificado */ SET NOCOUNT ON; declare @dt datetime=getdate(); declare @tbl table(Destinatários nvarchar(max)); declare @recipients nvarchar(max); declare @recipient nvarchar(255); declare @result nvarchar(max)=''; declare @recp nvarchar(max); declare @ind int; declare @recipients_key nvarchar(max); // receba todas as mensagens necessárias insira em @tbl(Recipients) selecione [RECIPIENTS] de srv.ErrorInfo onde InsertDate0) begin //recebe destinatários selecione top (1) @recipients=Destinatários de @tbl; set @[email protected]; definir @resultado=''; // para cada destinatário while(len(@recipients)>0) start set @ind=CHARINDEX(';', @recipients); if(@ind>0) start set @recipient=substring(@recipients,1, @ind-1); set @recipients=substring(@recipients,@ind+1,len(@recipients)[email protected]); end else begin set @[email protected]; definir @destinatários=''; fim; // recebe emails de destinatários exec [srv].[GetRecipients] @[email protected], @[email protected] out; if(len(@recp)=0) begin exec [srv].[GetRecipients] @[email protected], @[email protected] out; if(len(@recp)=0) set @[email protected]; end // separado pelo símbolo ';' set @[email protected]@sqldat.com+';'; end set @result=substring(@result,1,len(@result)-1); set @[email protected]; // recebe o relatório HTML com os destinatários especificados e inserção de data em @rec_body(Body) exec srv.GetHTMLTable @[email protected]_key, @[email protected]; // recebe o relatório HTML select top (1) @body=Body de @rec_body; // o EXEC de envio real msdb.dbo.sp_send_dbmail // perfil de administrador de e-mail que criamos @profile_name ='ALARM', // e-mail do destinatário @recipients =@recipients, // texto de uma mensagem @body =@body, // Assunto @subject =N'INFORMATION ON EXECUTION ERRORS', @body_format='HTML'--, // Por exemplo, vamos adicionar os resultados de uma consulta SQL aleatória à mensagem [email protected] =@query--'SELECT TOP 10 nome de sys.objects'; delete de @tbl onde [email protected]_key; delete de @rec_body; end // arquiva as mensagens enviadas INSERT INTO [srv].[ErrorInfoArchive] ([ErrorInfo_GUID] ,[ERROR_TITLE] ,[ERROR_PRED_MESSAGE] ,[ERROR_NUMBER] ,[ERROR_MESSAGE] ,[ERROR_LINE] ,[ERROR_PROCEDURE],[ERROR_POST_MESSAGE] ,[ RECIPIENTS] ,[StartDate],[FinishDate],[Count],IsRealTime) SELECT [ErrorInfo_GUID],[ERROR_TITLE],[ERROR_PRED_MESSAGE],[ERROR_NUMBER],[ERROR_MESSAGE],[ERROR_LINE],[ERROR_PROCEDURE],[ERROR_POST_MESSAGE],[ERROR_POST_MESSAGE], [RECIPIENTS] ,[StartDate] ,[FinishDate] ,[Count] ,IsRealTime FROM [srv].[ErrorInfo] onde [email protected] e InsertDate [/expand]
Este procedimento armazenado pega cada mensagem da fila de mensagens e a envolve em um relatório HTML na forma de uma tabela. Para destinatários, com base em seu código ou endereço de e-mail principal, ele cria uma string composta por endereços de e-mail, para os quais uma mensagem é enviada. Desta forma, todas as mensagens selecionadas são processadas. Aqui, o procedimento armazenado msdb.dbo.sp_send_dbmail é usado.
11. Crie duas tarefas no Agente (a primeira é para notificações em tempo real (agende 1 vez por minuto), a segunda é para notificações simples (agenda 1 vez por hora)). Adicione o seguinte ao código da tarefa:
EXECUTAR [DATABASE_NAME].[srv].[RunErrorInfoProc] @IsRealTime=0; // 0 - para mensagens simples e 1 - para mensagens em tempo real
Aqui está um exemplo de relatório de erros:
[expandir título=”Código”]
começar try exec [DATABASE_NAME].[srv].[KillFullOldConnect];end trybegin catch declarar @str_mess nvarchar(max)=ERROR_MESSAGE(), @str_num nvarchar(max)=cast(ERROR_NUMBER() as nvarchar(max) ), @str_line nvarchar(max)=cast(ERROR_LINE() as nvarchar(max)), @str_proc nvarchar(max)=ERROR_PROCEDURE(), @str_title nvarchar(max)='EXCLUINDO PROCESSOS NÃO RESPONDIDOS NO SERVIDOR 'exemplo @sqldat.com@servername, @str_pred_mess nvarchar(max)='OCORREU ERRO DE EXCLUSÃO DE PROCESSOS NÃO RESPONDENTES NO SERVIDOR '[email protected]@servername+'; exec [DATABASE_NAME].srv.ErrorInfoIncUpd @ERROR_TITLE =@str_title, @ERROR_PRED_MESSAGE =@str_pred_mess, @ERROR_NUMBER =@str_num, @ERROR_MESSAGE =@str_mess, @ERROR_LINE =@str_line, @ERROR_PROCEDURE =@str_proc, @ERROR_POST_MESSAGE =NULL, @ DESTINATÁRIOS ='DESTINATÁRIO1;DESTINATÁRIO2'; declare @err [email protected]@error; raiserror(@str_mess,16,1);end catch[/expand]
Aqui, o procedimento armazenado svr.KillFullOldConnect é usado.
Resultado
Este artigo inclui um exemplo de extensão da funcionalidade de um Database Mail normal e um exemplo de como gerar notificações em tabelas HTML e enviá-las por e-mail aos administradores. Essa abordagem permite notificar os administradores sobre diferentes problemas em tempo real ou após um determinado tempo, minimizando assim a ocorrência de um problema crítico e falha do SGBD e do servidor, o que por sua vez protege a produção contra atrasos no fluxo de trabalho.
Referências:
- Sp_send_dbmail
- Correio de banco de dados
- Srv.KillFullOldConnect