xp_logevent2

by Alexey Knyazev 5. октября 2010 23:34

В SQL Server есть интересная расширенная хранимая процедура xp_logevent. Процедура заносит определенное пользователем сообщение в файл журнала SQL Server и в средство просмотра событий Windows Event Viewer. Появилась идея немного расширить возможности этой процедуры, для этого я написал небольшую CLR-сборку, с помощью которой можно работать с журналом ошибок Windows.

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

Записи будут заноситься в отдельный журнал SQLServerLog. Сообщения могут быть одним из 5 типов:

  • Error
  • FailureAudit
  • Information
  • SuccessAudit
  • Warning

Код сборки:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Collections;


public class xp_logevent
{

//Выводим записи из журнала в виде таблицы
    [SqlFunction(FillRowMethodName = "FillRow", TableDefinition = "Type nvarchar(20), DateTyme nvarchar(20), Source nvarchar(20), Category nvarchar(10), Event nvarchar(10), User nvarchar(50), Computer nvarchar(50), Message nvarchar(max)")]
    public static IEnumerable xp_logevent2View()
    {
        ArrayList rows = new ArrayList();
        if (System.Diagnostics.EventLog.SourceExists("SQLSource"))
        {
            System.Diagnostics.EventLog.DeleteEventSource("SQLSource");
        }
        System.Diagnostics.EventLog.CreateEventSource("SQLSource", "SQLServerLog");

        System.Diagnostics.EventLog SQLServerLog = new System.Diagnostics.EventLog();

        SQLServerLog.Log = "SQLServerLog";
        SQLServerLog.Source = "SQLSource";
        if (SQLServerLog.Entries.Count > 0)
        {
            foreach (System.Diagnostics.EventLogEntry entry in SQLServerLog.Entries)
            {
                rows.Add(new object[] {   entry.EntryType.ToString() 
                                        , entry.TimeWritten.ToString() 
                                        , entry.Source.ToString() 
                                        , entry.Category.ToString() 
                                        , entry.EventID.ToString() 
                                        , entry.UserName 
                                        , entry.MachineName 
                                        , entry.Message   
                                      }
 
                        );
            }

        }
        else
        {
            rows.Add(new object[] { "Information" , DateTime.Now.Date.ToLongDateString() 
            , "SQLSource" 
            , "None" 
            ,"-" 
            , "-" 
            , "-" 
            , "Журнал пуст" });
        }

        SQLServerLog.Close();
        return rows;
    }

    public static void FillRow(Object row, out string Type
                                         , out string DateTime
                                         , out string Source
                                         , out string Category
                                         , out string Event
                                         , out string User
                                         , out string Computer
                                         , out string Message
                              )
    {
        object[] xrow = (object[])row;
        Type = (string)xrow[0];
        DateTime = (string)xrow[1];
        Source = (string)xrow[2];
        Category = (string)xrow[3];
        Event = (string)xrow[4];
        User = (string)xrow[5];
        Computer = (string)xrow[6];
        Message = (string)xrow[7];
    } 

//Заносим сообщение в журнал
    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void xp_logevent2(int error_number, string message, string severity)
    {
        if (System.Diagnostics.EventLog.SourceExists("SQLSource"))
        {
            System.Diagnostics.EventLog.DeleteEventSource("SQLSource");
        }
        System.Diagnostics.EventLog.CreateEventSource("SQLSource", "SQLServerLog");

        System.Diagnostics.EventLog SQLServerLog = new System.Diagnostics.EventLog();

        SQLServerLog.Log = "SQLServerLog";
        SQLServerLog.Source = "SQLSource";
        switch (severity)
        {
            case "Error":
                SQLServerLog.WriteEntry(message, System.Diagnostics.EventLogEntryType.Error, error_number);
                break;
            case "FailureAudit":
                SQLServerLog.WriteEntry(message, System.Diagnostics.EventLogEntryType.FailureAudit, error_number);
                break;
            case "Information":
                SQLServerLog.WriteEntry(message, System.Diagnostics.EventLogEntryType.Information, error_number);
                break;
            case "SuccessAudit":
                SQLServerLog.WriteEntry(message, System.Diagnostics.EventLogEntryType.SuccessAudit, error_number);
                break;
            case "Warning":
                SQLServerLog.WriteEntry(message, System.Diagnostics.EventLogEntryType.Warning, error_number);
                break;
            default:
                SQLServerLog.WriteEntry(message);
                break;
        }
        SQLServerLog.Close();
    }

//Очистка журнала
    public static void xp_logevent2Clear()
    {
        if (System.Diagnostics.EventLog.SourceExists("SQLSource"))
        {
            System.Diagnostics.EventLog.DeleteEventSource("SQLSource");
        }
        System.Diagnostics.EventLog.CreateEventSource("SQLSource", "SQLServerLog");

        System.Diagnostics.EventLog SQLServerLog = new System.Diagnostics.EventLog();

        SQLServerLog.Log = "SQLServerLog";
        SQLServerLog.Source = "SQLSource";
        SQLServerLog.Clear();
        SQLServerLog.Close();
    }

};


После компиляции получаем нашу библиотеку xp_logevent2.dll
Сборку зарегистрируем в контексте БД master:

alter database [master] set trustworthy on
go
use master
go
create assembly xp_logevent2
from 'C:\xp_logevent2\xp_logevent2.dll'
with permission_set = external_access;
go


Для работы с журналом создадим 2 процедуры:

  • xp_logevent2 - заносит запись в журнал
  • xp_logevent2Clear - очищает журнал
--Основная процедура, заносит сообщение в журнал
create procedure xp_logevent2
(
   @error_number int --Номер пользовательской ошибки
 , @message nvarchar(max) --Символьная строка 
 , @severity nvarchar(20) -- Один из 5 типов сообщения
) 
as 
external name xp_logevent2.xp_logevent.xp_logevent2
go
--Очистка журнала
create procedure xp_logevent2Clear 
as 
external name xp_logevent2.xp_logevent.xp_logevent2Clear
go


И функция xp_logevent2View(), для просмотра журнала в виде таблицы:

create function xp_logevent2View()
returns table
(
  [Type] nvarchar(20)
, [DateTime] nvarchar(20)  
, [Source] nvarchar(20) 
, [Category] nvarchar(10) 
, [Event] nvarchar(10) 
, [User] nvarchar(50) 
, [Computer] nvarchar(50) 
, [Message] nvarchar(max)
)
external name xp_logevent2.xp_logevent.xp_logevent2View;

А теперь демонстрация работы:
Добавим одно сообщение в журнал
 exec xp_logevent2 50001, 'Первое тестовое сообщение', 'Information';
После этого в Event Viewer`е появится наш журнал:

Очистить журнал можно с помощью 2ой нашей процедуры:
 exec xp_logevent2Clear;
Для демонстрации функции, добавим несколько сообщений и запустим нажу функцию
 select * from xp_logevent2View()




А так эти сообщения выглядат в журнале Windows



Если кому-то лень компилировать сборку, то выложу xp_logevent2.dll тут.

Tags: ,

SQL Server

Комментарии (1) -

Denis A
Denis A Russia
04.11.2011 10:46:51 #

отличная статья, большое спасибо, долго не мог подступиться к сборкам.
для себя как полный 0 в этом скажу что недопонимание возникло
- какой проект создавать в VS - но сразу допёр - Visual C# SQL CLR database project
- код пишется в properties->assemblyInfo.cs
- не сразу проканала сборка в SQL, надо было поставить в свойствах проекта нужную версию Framework
- покопался по поводу - разрешения запуска clr сборок.
      RECONFIGURE
      GO
      sp_configure 'clr enabled', 1;
      GO
      RECONFIGURE
      GO
ну это совсем ламерские штуки, просто пишу вдруг пригодится )
еще спасибо, перехожу к смс-clr Smile

Reply

Добавить комментарий

  Country flag

biuquote
  • Комментарий
  • Предпросмотр
Loading