Большая часть кода, написанного для SharePoint работает в крайне непредсказуемой среде.Полностью отлаженный на компьютере разработчика код может совершенно “необъяснимо” падать в целевой среде. В этой ситуации очень важно логировать происходящее в вашем коде.

Тема логирования очень любима многими разработчиками. Одни предпочитают писать свои велосипеды, другие пользуются готовыми фрейморками, третье используют возможности ОС.

Если вы разрабатываете решения для SharePoint, то вам необходимо придерживаться следующих правил:

0. Не используйте фреймворки

Даже если вы очень любите log4net, или NLog, или EventLog, или System.Diagnostics.Trace, или пишете свой велосипед, то никогда не используйте ничего из вышеперечисленного.

В SharePoint существует своя система логирования, называемая Unified Logging System (ULS). Если у вас возникает вопрос чем ULS лучше чем <подставьте сюда свой любимый фреймворк>, то вот основные причины:

  • ULS уже используется компонентами SharePoint, используя другую систему вам придется собирать логи в нескольких местах
  • ULS гибко настраивается из Central Administration и PowerShell
  • ULS умеет писать в Windows Event Log, не требуя при этом привилегий
  • ULS обеспечивает сжатие текстовых логов на диске
  • ULS не требует правки web.config (что очень важно для многосерверной фермы)
  • SharePoint умеет собирать логи ULS (и не только их) со многих серверов в одну базу
1.  В простых случаях не делайте ничего

SharePoint сделан так, что необработанные исключения внутри процессов SharePoint попадают в ULS.  В случае возникновения ошибки очень легко будет в ULS найти stack trace, а если включить уровень логированя VerboseEx, то и все запросы к базе со статистикой.

Для просмотра логов удобнее всего применять утилиту UlsViewer, для русской версии Windows Server может понадобиться патч.

Есть одно исключение из этого правила – веб-части. Если веб-часть в full trust падает с ошибкой, то пользователь увидит только страницу ошибки. Причем если ошибка вызвана персонализированными свойствами, то ошибку будет сложно устранить. Хорошим тоном при разработке веб-частей является не вывод исключения, а  отображение информации как ошибку исправить.

2. Используйте SPMonitoredScope везде

Класс SPMonitoredScope очень прост в использовании:

using (new SPMonitoredScope("My Monitored Scope"))
{
    // Do Stuff...
}

В лог пишутся сообщение при входе в scope и при выходе из него, также записывается время выполнения scope. По умолчанию сообщения от SPMonitoredScope  имеют уровень Verbose.

С помощью SPMonitoredScope  также можно логировать и другие параметры быстродействия и потребления ресурсов

using (new SPMonitoredScope("My Scope Name",1000,
   new SPRequestUsageCounter(3),
   new SPSqlQueryCounter(10)))
{
    //Do Stuff...
}

Если внутри scope время выполнения превысит 1000мс, или количество объектов SPRequest (SPWeb и SPSite) превысит 3, или количество запросов к базе превысит 10, то уровень логирования повысится до High. Кроме того в лог попадут фактические значения этих параметров, а также места создания объектов SPSite\SPWeb в виде stack trace и места где происходили запросы к БД.

Но самое важное заключается в том, что SPMonitoredScope попадает в Developer Dashboard.

Если написать такой код:

using (new SPMonitoredScope("My Monitored Scope")) 
{                
    using (new SPMonitoredScope("My Sub-Monitored Scope")) 
    { 
        using (new SPMonitoredScope("My Sub-Sub-Monitored Scope")) 
        { 
        }

        using (new SPMonitoredScope("Another deep scope")) 
        { 
        } 
    } 
}
То в Developer Dashboard можно увидеть следующую картину:

image_4_204207CF

3. Используйте SPDiagnosticsService для записи в лог

Непосредственно в ULS можно писать с помощью класса SPDiagnosticsService.

Запись в Trace Log:

SPDiagnosticsService diagSvc = SPDiagnosticsService.Local; 
diagSvc.WriteTrace(0, 
    new SPDiagnosticsCategory("My Category", 
        TraceSeverity.Monitorable, 
        EventSeverity.Error), 
    TraceSeverity.Monitorable, 
    "An exception occurred: {0}", 
    new object[] {ex}); 

В ULS для каждой записи указывается Area и Category. При таком вызове Area будет равна Unknown.

Также можно писать сразу в Event log:

SPDiagnosticsService diagSvc = SPDiagnosticsService.Local; 
diagSvc.WriteEvent(0, 
        new SPDiagnosticsCategory("My Category", 
            TraceSeverity.Monitorable, 
            EventSeverity.Warning), 
        EventSeverity.Error, 
        "Exception occured {0}", new object[] {ex}); 
4. Наследуйтесь от SPDiagnosticsServiceBase для гибкой настройки логирования

Если вы создаете большой компонент для SharePoint, то имеет смысл создать свой сервис логирования (наследник класса SPDiagnosticsServiceBase). В нем можно определить свои Area и Category, а также более легковесные методы для логирования. В Central Administration и PowerShell можно будет задать уровень логирования для каждой категории или Area.

public class LoggingService : SPDiagnosticsServiceBase
{
    public static string DiagnosticAreaName = "My";
    private static LoggingService _Current;
    public static LoggingService Current
    {
        get
        {
            if (_Current == null)
            {
                _Current = new LoggingService();
            }
 
            return _Current;
        }
    }
 
    private LoggingService()
        : base("My Logging Service", SPFarm.Local)
    {
 
    }
 
    protected override IEnumerable<SPDiagnosticsArea> ProvideAreas()
    {
        List<SPDiagnosticsArea> areas = new List<SPDiagnosticsArea>
        {
            new SPDiagnosticsArea(DiagnosticAreaName, new List<SPDiagnosticsCategory>
            {
                new SPDiagnosticsCategory("WebParts", TraceSeverity.Unexpected, EventSeverity.Error)
            })
        };
 
        return areas;
    }
 
    public static void LogError(string categoryName, string errorMessage)
    {
        SPDiagnosticsCategory category = LoggingService.Current.Areas[DiagnosticAreaName].Categories[categoryName];
        LoggingService.Current.WriteTrace(0, category, TraceSeverity.Unexpected, errorMessage);
    }
}

Дальше просто:

LoggingService.LogError("WebParts", ex.ToString);
5. Используйте сервис диагностики для клиентских приложений

В SharePoint есть веб-сервис /_vti_bin/diagnostics.asmx. Он содержит всего один метод, который пишет данные в ULS в категорию SharePoint Foundation –> Unified Logging Service  с уровнем Verbose.

Если вы создаете приложение на Silverlight или Javascript, то другим образом довольно сложно обеспечить логирование, доступное разработчику и администратору.

В библиотеках javascript, предоставляемых SharePoint, есть функции
ULSOnError(msg, url, line) и ULSSendException(ex). Но просто вызвать их не получится. Перед каждым вызовом функции необходимо присвоить ULS.enable значение true.

ULS.enable = true;
ULSOnError("Hello trace", document.location.href, 0);

 

PS. Не забывайте что ULS создан для разработчиков и администраторов. Для пользователей иногда тоже надо хранить и показывать некоторый журнал того что происходило. В этом случае лучше всего работают списки.

PPS. Правил действительно 6, но число 6 в заголовке смотрелось бы гораздо хуже.

Теги : SharePoint