Вагиф Абилов (object) wrote,
Вагиф Абилов
object

Category:

Роемся в коде Майкрософта - TextWriterTraceListener

Мои серверные приложения используют функции записи лога из Microsoft Enterprise Library (с добавленным Rolling File Trace Listener, написанным голландцем Эрвином ван дер Меером из Logica CMG). Одна из претензий файлам лога - неудобные имена. Если доступ к файлу "abc.log" закрыт другим процессом, логгер создает файл с именем типа "0EA25685-05B1-415d-9363-F76388C185D1-abc.log", т.е. добавляет к НАЧАЛУ имени файла гвид (GUID). Подобная практика делает абсолютно бессмысленной сортировку файлов в каталоге, а файлов с логами на сервере накапливается много.


Вначале я решил, что это проблема Enterprise Library, а значит код можно было бы поправить самому. Однако, дело оказалось более серьезным. Соответствующий класс из Enterprise Library наследует от TextWriterTraceListener, который находится в System.Diagnostics, а значит доступа к нему для модификации нет.

Вытащенный с помощью рефлектора код из System.Diagnostics навел на метод EnsureWriter, который пытается получить доступ к файлу с заданным именем, и если это не удается, пробует имя с приставкой в виде гвида. Код выглядит так:

bool createdFile = false;
string fileName = this.FileName;
for (int count = 0; count < 2; count++)
{
 try
 {
  this.writer = new StreamWriter(fileName, true, encoding, 0x1000);
  createdFile = true;
  break;
 }
 catch (IOException)
 {
  fileName = Guid.NewGuid().ToString() + fileName;
 }
 catch (UnauthorizedAccessException)
 {
  break;
 }
 catch (Exception)
 {
  break;
 }
}
if (!createdFile)
{
 this.fileName = null;
}

Честно говоря, так бы я код не написал. Несколько замечаний:

1. Использование цикла для двух попыток выглядит стилистически коряво. Итерации цикла стоит составлять из однородных, семантически равнозначных операций. Если же итераций всего две и вторая требует переделки исходных данных, я бы цикл заменил последовательным кодом.

2 (несущественное). Обратите внимание на "this.FileName" в начале и "this.fileName" в нижней части кода. Программист стал жертвой функции Visual Studio Intellisense, которая позволяет не печатать переменные вручную, а выбирать из списка имеющихся. В первом случае программист выбрал public propery, во втором - private variable. Семантически равнозначо в данном случае, но еще раз наводит на мысль о необходимости использования префикса в именах внутренних переменных классов.

3 (существенное). При образовании нового имени гвид используется как приставка. Программист просто выбрал первый попавшийся вариант. Использование гвида в качестве суффикса ничем не хуже, но дает преимущества при сортировке файлов.

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

5. Излишние локальные переменные. Без fileName и createdFile можно было обойтись.

Ну и чтобы не быть голословным - моя версия того же кода:

try
{
 try
 {
  this.writer = new StreamWriter(this.fileName, true, encoding, 0x1000);
 }
 catch (IOException)
 {
  this.writer = new StreamWriter(this.fileName + "-" + Guid.NewGuid().ToString(), true, encoding, 0x1000);
 }
}
catch (Exception)
{
 this.fileName = null;
}

Впрочем, и здесь есть немного смущающая деталь: дважды повторенный new StreamWriter(...) с почти что одинаковыми аргументами. Можно бы и вынести:

internal StreamWriter CreateStreamWriter(string fileName)
{
 return new StreamWriter(fileName, true, encoding, 0x1000);
}

Тогда изначальный код будет выглядеть так:

try
{
 try
 {
  this.writer = CreateStreamWriter(this.fileName);
 }
 catch (IOException)
 {
  this.writer = CreateStreamWriter(this.fileName + "-" + Guid.NewGuid().ToString());
 }
}
catch (Exception)
{
 this.fileName = null;
}

К сожалению, код метода EnsureWriter встроен в класс TextWriterTraceListener и модификации не поддается. Однако, поскольку мы пользуемся не самим TextWriterTraceListener, а производной от него (RollingFileTraceListener), удалось модифицировать исходный код нашего класс, добившись желаемого эффекта.
Subscribe
  • Post a new comment

    Error

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 4 comments