2016-01-26 5 views
3

Я использую Log4net (v2.0.50727) в веб-сервисе C#, который я написал. Он настроен на создание 2 приложений. Первый - это общий файл отладки, который я отслеживаю, чтобы убедиться, что служба работает правильно, вторая - отчет, который я отправляю на клиента с различными интервалами (вручную, но может быть автоматизирован).Log4net xml appender не создает корневой элемент

<log4net> 
    <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender"> 
    <file value="..\logs\Service.log.xml"/> 
    <appendToFile value="true"/> 
    <rollingStyle value="Size"/> 
    <maxSizeRollBackups value="20"/> 
    <maximumFileSize value="10000KB"/> 
    <staticLogFileName value="true"/> 
    <preserveLogFileNameExtension value="true" /> 
    <layout type="log4net.Layout.XmlLayoutSchemaLog4j"> 
     <conversionPattern value="%utcdate [%thread] %-5level %logger [%property{NDC}] - %message%newline"/> 
    </layout> 
    </appender> 
    <appender name="CustomerReportAppender" type="log4net.Appender.RollingFileAppender"> 
     <file value="..\logs\Customer.Report.xml"/> 
     <appendToFile value="true"/> 
     <rollingStyle value="Size"/> 
     <maxSizeRollBackups value="20"/> 
     <maximumFileSize value="10000KB"/> 
     <staticLogFileName value="true"/> 
     <preserveLogFileNameExtension value="true" /> 
     <layout type="log4net.Layout.XmlLayoutSchemaLog4j"> 
     <conversionPattern value="%utcdate [%thread] %-5level %logger [%property{NDC}] - %message%newline"/> 
     </layout> 
    </appender> 
    <root> 
    <level value="DEBUG"/> 
    <appender-ref ref="RollingFileAppender"/> 
    </root> 
    <logger name="CustomerReport"> 
    <level value="ALL" /> 
    <appender-ref ref="CustomerReportAppender" /> 
    </logger> 
</log4net> 

Запись в оба файла работает нормально. Проблема в том, что если я отправлю файл Customer.Report.xml моему клиенту, он не откроется в Excel как недействительный XML. Файл состоит из нескольких строк элементов событий -

<event logger="CustomerReport" timestamp="1453717399436" level="INFO" thread="8"> 
<message>Customer Info</message> 
<properties> 
<data name="UserName" value="IIS APPPOOL\Customer Service" /> 
<data name="log4jmachinename" value="MyServer" /> 
<data name="log4japp" value="/LM/W3SVC/3/ROOT-2-130981905203581113" /> 
<data name="HostName" value="MyServer" /> 
</properties> 
</event> 

Я предполагаю, что Excel жалуется, как он не имеет 1 корневой элемент. Если я завершу весь файл в поле:

<Report> 
.... 
</Report> 

затем Excel загружает его в порядке. Можно ли заставить Log4net генерировать это для меня? Или можно сделать Excel для его обработки? Спасибо.

+0

Вы можете добавить элементы верхнего и нижнего колонтитула в макет (обратите внимание, что ваш шаблон преобразования игнорируется, поскольку [XmlLayoutSchemaLog4j не имеет такого свойства] (http://logging.apache.org/log4net/log4net-1.2.12/release/ sdk/log4net.Layout.XmlLayoutSchemaLog4jMembers.html)) - или у вас есть различные опции, чтобы получить больший контроль над процессом, например пользовательский appender или настраиваемый макет, – stuartd

+0

Log4net не может справиться с этим сам по себе, потому что у RollingFileAppender нет определенного конца. Он не может знать, когда закрыть корневой тег xml. Вы можете справиться с этим из Excel с помощью VBA, если это приемлемо для ваших пользователей (вы получаете эти предупреждения от вирусов), или вам придется вмешаться с каким-то специальным кодом. –

ответ

1

PowerShell - отличный инструмент для быстрого решения подобных задач.

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

Так ниже скрипт попросит вас выбрать файл, а затем автоматически помещает его содержимое XML внутри корневого элемента, который вы указываете:

[CmdletBinding()] 
Param(
    [Parameter(ValueFromPipeline=$true)] 
    [ValidateScript({Test-Path $_ -PathType Container})] 
    [string] 
    $InitialDirectory, 

    [ValidateNotNullOrEmpty()] 
    [string] 
    $RootElementName = 'Report' 
) 

[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null 

$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog 
$OpenFileDialog.InitialDirectory = $InitialDirectory 
$OpenFileDialog.Filter = "XML (*.xml)| *.xml" 
$OpenFileDialog.ShowDialog() | Out-Null 

$FileName = $OpenFileDialog.FileName 
$FileContent = Get-Content $FileName 

$FileContentXml = [Xml]$FileContent 

[XML.XMLDocument]$XMLDocument = New-Object System.XML.XMLDocument 
[XML.XMLElement]$XMLRoot = $XMLDocument.CreateElement($RootElementName) 
$XMLRoot.InnerXml = $FileContentXml.OuterXml 
$XMLDocument.AppendChild($XMLRoot) 

$XMLDocument.Save($FileName) 

Вы могли бы использовать его, сохраняя этот сценарий в новый файл , например D:\Add-RootXmlElement.ps1, а затем вы можете запустить его из CMD строки следующим образом:

@powershell D:\Add-RootXmlElement.ps1 -InitialDirectory "D:\Logs" -RootElementName "Report"

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

Это решение проблемы?

EDIT:

Конечно, если вы хотите автоматизировать этот процесс, и вы знаете имя файла в то время, вы звоните сценарий, просто опустить всю $InitialDirectory и $OpenFileDialog частей, а просто установить $FileName путь к файлу журнала, к которому вы хотите добавить корневой элемент.

Смежные вопросы