Библиотека предприятия RollingFlatFileTraceListenerData Формат файла JsonLogFormatter

Я ищу способ заставить RollingFlatFileTraceListenerData создать действительный документ JSON при использовании JsonLogFormatter. Как и анализатор XML, RollingFlatFileTraceListenerData добавляет только элементы, просто давая вам возможность добавить верхний и нижний колонтитулы элемента, но не заголовок файла более высокого уровня, нижний колонтитул и разделитель элементов. Я понимаю, что могу изменить файл после факта, но я бы предпочел сборку процесса с допустимым форматом. Открытие активного файла с помощью внешнего процесса было бы рискованным, поскольку он мог бы заблокировать процесс ведения журнала, если ему нужно было бы открыть файл для повторной регистрации.

Токовый выход:

{
  "Message": "Log entry created using the simplest overload.",
  "Categories": [
    "General"
  ],
  "Priority": -1,
  "EventId": 1,
  "Severity": 8,
  "LoggedSeverity": "Information",
  "Title": "",
  "TimeStamp": "2013-11-07T20:33:38.6537773Z",
  "MachineName": "Acme01",
  "AppDomainName": "Acme.TestDriver.vshost.exe",
  "ProcessId": "10348",
  "ProcessName": "C:\\dev\\Acme.TestDriver\\bin\\Debug\\Acme.TestDriver.vshost.exe",
  "ManagedThreadName": null,
  "Win32ThreadId": "11204",
  "ExtendedProperties": {},
  "TimeStampString": "11/7/2013 8:33:38 PM",
  "ActivityId": "00000000-0000-0000-0000-000000000000",
  "RelatedActivityId": null,
  "ErrorMessages": null,
  "ActivityIdString": "00000000-0000-0000-0000-000000000000",
  "CategoriesStrings": [
    "General"
  ]
}
{
  "Message": "Log entry with a single category.",
  "Categories": [
    "General"
  ],
  "Priority": -1,
  "EventId": 1,
  "Severity": 8,
  "LoggedSeverity": "Information",
  "Title": "",
  "TimeStamp": "2013-11-07T20:33:38.6537773Z",
  "MachineName": "Acme01",
  "AppDomainName": "Acme.TestDriver.vshost.exe",
  "ProcessId": "10348",
  "ProcessName": "C:\\dev\\Acme.TestDriver\\bin\\Debug\\Acme.TestDriver.vshost.exe",
  "ManagedThreadName": null,
  "Win32ThreadId": "11204",
  "ExtendedProperties": {},
  "TimeStampString": "11/7/2013 8:33:38 PM",
  "ActivityId": "00000000-0000-0000-0000-000000000000",
  "RelatedActivityId": null,
  "ErrorMessages": null,
  "ActivityIdString": "00000000-0000-0000-0000-000000000000",
  "CategoriesStrings": [
    "General"
  ]
}

Предпочтительно:

[
 {
      "Message": "Log entry created using the simplest overload.",
      "Categories": [
        "General"
      ],
      "Priority": -1,
      "EventId": 1,
      "Severity": 8,
      "LoggedSeverity": "Information",
      "Title": "",
      "TimeStamp": "2013-11-07T20:33:38.6537773Z",
      "MachineName": "Acme01",
      "AppDomainName": "Acme.TestDriver.vshost.exe",
      "ProcessId": "10348",
      "ProcessName": "C:\\dev\\Acme.TestDriver\\bin\\Debug\\Acme.TestDriver.vshost.exe",
      "ManagedThreadName": null,
      "Win32ThreadId": "11204",
      "ExtendedProperties": {},
      "TimeStampString": "11/7/2013 8:33:38 PM",
      "ActivityId": "00000000-0000-0000-0000-000000000000",
      "RelatedActivityId": null,
      "ErrorMessages": null,
      "ActivityIdString": "00000000-0000-0000-0000-000000000000",
      "CategoriesStrings": [
        "General"
      ]
    }
,
    {
      "Message": "Log entry with a single category.",
      "Categories": [
        "General"
      ],
      "Priority": -1,
      "EventId": 1,
      "Severity": 8,
      "LoggedSeverity": "Information",
      "Title": "",
      "TimeStamp": "2013-11-07T20:33:38.6537773Z",
      "MachineName": "Acme01",
      "AppDomainName": "Acme.TestDriver.vshost.exe",
      "ProcessId": "10348",
      "ProcessName": "C:\\dev\\Acme.TestDriver\\bin\\Debug\\Acme.TestDriver.vshost.exe",
      "ManagedThreadName": null,
      "Win32ThreadId": "11204",
      "ExtendedProperties": {},
      "TimeStampString": "11/7/2013 8:33:38 PM",
      "ActivityId": "00000000-0000-0000-0000-000000000000",
      "RelatedActivityId": null,
      "ErrorMessages": null,
      "ActivityIdString": "00000000-0000-0000-0000-000000000000",
      "CategoriesStrings": [
        "General"
      ]
    }
]

2 ответа

Я тоже пытался исправить вывод, но в конце концов сдался и обработал все на стороне потребления. Ниже приведен пример моей программы, которая спамит события, а затем пытается использовать их на основе кода с /questions/14551621/kak-pravilno-ispolzovat-jsonnet-dlya-analiza-potoka-obektov-json/14551624#14551624

Ключевые моменты:

  • RollingFlatFileTraceListener Верхний и нижний колонтитулы установлены на ""
  • При использовании журналов наш поток настроен на FileShare.ReadWrite поэтому мы не мешаем писать
  • JsonReader.SupportMultipleContent = true это то, что позволяет нам обрабатывать несколько объектов в файле, если они находятся в отдельных строках.

Это использует Microsoft Enterprise Logging Library v6 и Newtonsoft JSON v8.

static void Main(string[] args) {
  Thread producer = new Thread(new ThreadStart(Produce));
  Thread consumer = new Thread(new ThreadStart(Consume));
  producer.Start();
  consumer.Start();
  while (true)
    Thread.Sleep(1000);
}

public static void Produce() {
  RollingFlatFileTraceListener listener = new RollingFlatFileTraceListener(
    fileName: "jsontest",
    formatter: new JsonLogFormatter(),
    header: "",
    footer: "",
    rollSizeKB: 1024);
  LoggingConfiguration configuration = new LoggingConfiguration();
  configuration.Filters.Add(new CategoryFilter("Category Filter", new string[] { "none" }, CategoryFilterMode.AllowAllExceptDenied));
  configuration.AddLogSource("Any", SourceLevels.All, true, listener);
  LogWriter writer = new LogWriter(configuration);

  while (true)
    writer.Write(DateTime.Now);
}

public static void Consume() {
  while (true) {
    try {
      using (var fileStream = File.Open("jsontest", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
        LogEntry latestEntry = ReadJson<LogEntry>(fileStream).OrderBy(x => x.TimeStamp).FirstOrDefault();
        if (latestEntry == null)
          continue;
        Console.WriteLine("Consume\t" + latestEntry.Message);
      }
    } catch (FileNotFoundException) {
      Console.WriteLine("File Not Found");
    } catch (IOException) {
      Console.WriteLine("File Is Probably Busy");
    }
  }
}


public static IEnumerable<TResult> ReadJson<TResult>(Stream stream) {
  var serializer = new JsonSerializer();
  using (var reader = new StreamReader(stream))
  using (var jsonReader = new JsonTextReader(reader)) {
    jsonReader.SupportMultipleContent = true;
    while (jsonReader.Read()) {
      yield return serializer.Deserialize<TResult>(jsonReader);
    }
  }
}

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

Другие вопросы по тегам