Compartilhar via


Советы по ведению журналов ULS, часть 2

Советы по ведению журналов ULS, часть 2

В 1-й части советов по ведению журналов ULS (https://blogs.msdn.com/b/sharepoint_ru/archive/2011/03/21/uls.aspx) я представил код для добавления настраиваемой области ведения журналов ULS и показал, как использовать его в проекте. После работы с этим кодом я заметил несколько вещей:

1. В предыдущей части был код, который не соответствовал последнему пакету SDK, — по сути, некоторые фрагменты кода, реализованные в соответствии с SDK, оказались излишними, а кое-что из сделанного отличалось от примера в SDK (который, кстати, следует обновить — я поработаю над этим отдельно).

2. Ведение журнала осуществляется только в случае, если задать для TraceSeverity значение "Medium"; другого эффективного способа на других уровнях трассировки не было.

3. Больше всего раздражало, что когда я пытался вызвать свой класс, необходимый для настраиваемой области, он выполнялся с ошибкой, если ведение журнала происходило во время действий, связанных с запросом POST. Код вызывал знакомую ошибку — невозможность обновить SPWeb во время запроса POST, если для значение свойства AllowUnsafeUpdates не было задано значение true. Задание этого значения в SPWeb во время события журнала, чтобы оно работало, казалось безрассудной идеей (приношу мои извинения всем безрассудным людям). Поэтому я решил, что есть метод получше.

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

1. Улучшенный класс для настраиваемой области — в этой версии произведены некоторые сокращения.

2. Интеграция с настройкой средств сбора данных диагностики в разделе "Мониторинг" центра администрирования. Эта интеграция позволит в дальнейшем обеспечить поддержку настройки уровней трассировки в настраиваемой области и категории.

3. Сведения о регистрации — очень простой способ регистрировать и отменять регистрацию настраиваемого класса ведения журнала ULS, поэтому его можно интегрировать с центром администрирования и можно удалить из центра администрирования.

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

    [Guid("833B687D-0DD1-4F17-BF6A-B64FBC1AC6A8")]

    public class SteveDiagnosticService : SPDiagnosticsServiceBase

    {

        private const string LOG_AREA = "Steve Area";

        public enum LogCategories

        {

            SteveCategory

        }

        public SteveDiagnosticService()

        {

        }

        public SteveDiagnosticService(string name, SPFarm parent)

            : base(name, parent)

        {

        }

        public static SteveDiagnosticService Local

        {

            get

            {

                return SPDiagnosticsServiceBase.GetLocal<SteveDiagnosticService>();

            }

        }

        public void LogMessage(ushort id, LogCategories LogCategory,

TraceSeverity traceSeverity, string message,

params object[] data)

        {

            if (traceSeverity != TraceSeverity.None)

            {

                SPDiagnosticsCategory category

                 = Local.Areas[LOG_AREA].Categories[LogCategory.ToString()];

                Local.WriteTrace(id, category, traceSeverity, message, data);

            }

     }

        protected override IEnumerable<SPDiagnosticsArea> ProvideAreas()

        {

yield return new SPDiagnosticsArea(LOG_AREA, 0, 0, false,

new List<SPDiagnosticsCategory>()

{

new

SPDiagnosticsCategory(LogCategories.AzureConfig.ToString(),

                     TraceSeverity.Medium, EventSeverity.Information, 1,

                     Log.LOG_ID)

                });

        }

    }

 

Вот важные изменения по сравнению с первой версией:

1.  Атрибут Guid добавлен в класс:

[Guid("833B687D-0DD1-4F17-BF6A-B64FBC1AC6A8")]

 

Я добавил атрибут Guid в класс, так как он требуется SharePoint для его уникальной идентификации в базе данных конфигурации.

2. Изменен конструктор по умолчанию:

        public SteveDiagnosticService()

        {

        }

 

Теперь это просто стандартный пустой конструктор. Раньше я вызывал другую перегрузку конструктора, который принимает имя службы и параметр SPFarm. Просто стало меньше кода, что хорошо.

3. Удалена перегрузка метода HasAdditionalUpdateAccess. Опять же, я фактически не использовал эту перегрузку, поэтому, следуя девизу "меньше, но лучше", я удалил ее.

 

4. Значительно укорочен метод ProvideAreas; теперь он соответствует шаблону, который используется в пакете SDK:

 

yield return new SPDiagnosticsArea(LOG_AREA, 0, 0, false,

new List<SPDiagnosticsCategory>()

{

new

SPDiagnosticsCategory(LogCategories.AzureConfig.ToString(),

                     TraceSeverity.Medium, EventSeverity.Information, 1,

                     Log.LOG_ID)

                });

Это решило 1-ю проблему, описанную выше — теперь мой код стал немного понятнее. Другие проблемы (отсутствие уровней трассировки, вызов исключения при ведении журнала во время запроса POST и интеграция с центром администрирования) были устранены дальнейшим улучшением и регистрацией кода. Пример в пакете SDK, касающиеся этой области, довольно слаб, но мне удалось заставить его делать, что нам нужно. Для простоты я создал новый компонент для моей сборки с настраиваемым классом ULS, описанным выше. Я добавил приемник компонентов, регистрирую настраиваемую сборку ULS в течение события FeatureInstalled и отменяю ее регистрацию в течение события FeatureUninstalling. Это довольно хорошее решение в моем случае, так как я сделал свой компонент компонентом в области фермы, поэтому он автоматически активируется при добавлении и развертывании решения. Как оказалось, код для регистрации и отмены регистрации неприлично прост:

public override void FeatureInstalled(SPFeatureReceiverProperties properties)

{

try

       {

SteveDiagnosticsService.Local.Update();

}

catch (Exception ex)

       {

throw new Exception("Error installing feature: " + ex.Message);

}

}

public override void FeatureUninstalling(SPFeatureReceiverProperties properties)

{

try

       {

SteveDiagnosticsService.Local.Delete();

}

catch (Exception ex)

{

throw new Exception("Error uninstalling feature: " + ex.Message);

}

}

Еще один момент, который я хотел бы отметить, состоит в том, что мне удалось указать ссылку на "SteveDiagnosticService", потому что я: а) добавил ссылку на сборку с моим настраиваемым классом в проект, в котором размещен компонент; и б) я добавил оператор using в класс приемника компонентов для сборки с моим настраиваемым классом ведения журнала.

Регистрируя свой настраиваемый класс ведения журнала ULS, я получаю множество преимуществ:

· Ошибки, связанные с проблемами обновления SPWeb при записи в журнал ULS во время запроса POST, больше не возникают.

· Настраиваемая область и категория ведения журнала отображаются в центре администрирования, поэтому я могу зайти в раздел "Настройка средств сбора данных диагностики" и изменить уровень трассировки и событий. Например, если по умолчанию задан средний уровень трассировки, все операции записи в журнал с параметром TracingSeverity.Medium записываются в журнал, но операции с параметром TracingSeverity.Verbose не записываются. Если мне нужно записывать записи с уровнем TracingSeverity.Verbose в журнал, я просто захожу в раздел "Настройка средств сбора данных диагностики" и изменяю уровень трассировки на "Подробно".

Итоговое решение получилось проще и функциональнее. Я думаю, что это одна из тех беспроигрышных штук, о которых я все время слышу.

П. С. Я хочу заявить свой протест относительно Ламаркуса Олдриджа из команды Портланд Трейлблейзерс. То, что он не попал в команду всех звезд западной конференции НБА, трагическая нелепость. Ладно, достаточно личных комментариев, я знаю, что вам всем нужны по-настоящему полезные сведения. Надеюсь, эта статья вам пригодится.

Это локализованная запись блога. Исходная статья доступна по адресу Tips for ULS Logging Part 2