Szymon Kobalczyk's Blog

A Developer's Notebook

  Home  |   Contact  |   Syndication    |   Login
  106 Posts | 6 Stories | 579 Comments | 365 Trackbacks

News

View Szymon Kobalczyk's profile on LinkedIn

Twitter












Tag Cloud


Article Categories

Archives

Post Categories

Blogs I Read

Tools I Use

Download XmlLogger files from MSDN Code Galery 

 

Using the XmlLogger

To use additional logger with MSBuild you use the /logger switch. It requires the fully qualified class name of the logger (including namespace) and assembly name separated with coma. You can also pass additional parameters to the logger after a semicolon. My logger takes only one parameter, and it is the output filename. If this parameter is opmitted output will be directed to console.

To use the XmlLogger when building your project execute following command line:

 MSBuild.exe yourproject /logger:Kobush.Build.Logging.XmlLogger,Kobush.MSBuild.dll;buildresult.xml

 

Where yourproject can be a Visual Studio solution file (.sln), a language specific project file (.csproj or .vbproj) or a custom build file.

You can also add following switches to stop all output to the console:

 /nologo /noconsolelogger

 

The output verbosity level can be specified using /verbosity parameter (short form /v). The available verbosity levels are: q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic]. I tried to make my logger produce the same output on various levels as the default console logger.

Using the XmlLogger with CruiseControl.NET

CruiseControl.NET is an automated continuous integration server, implemented using the Microsoft .NET Framework. In another words it's a server that monitors your source repository and upon detecting any changes runs the build script and can perform additional tests to ensure the code is integrated correctly. 

Starting from 1.0 RC1 version CC.NET adds direct support for building MSBuild projects with addition of the <msbuild /> task. For instructions on how to use MSBuild with earlier versions see Michael Swanson's blog. Here is an example of using the new task: 

<msbuild>
<executable>C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MSBuild.exe</executable>
<workingDirectory>C:\dev\project</workingDirectory>
<projectFile>yourproject</projectFile>
<buildArgs>/nologo /noconsolelogger /p:Configuration=Debug /v:diag</buildArgs>
<targets>Build;Test</targets>
<timeout>15</timeout>
<logger>Kobush.Build.Logging.XmlLogger,Kobush.MSBuild.dll</logger>
</msbuild>

 

The important part here is to specify the correct working directory for your project and to place the logger assembly in that directory. By default the <msbuild /> task will instruct the logger to output results to file called msbuild-output.xml and will automatically include the contents of this file in your build results.

Using the XmlLogger with NAnt

Personally I don't invoke MSBuild directly from CC.NET and instead have a NAnt build file that executes additional tasks (like generating version information to shared AssemblyInfo.cs file and packaging the build artifacts into a distributable package) before and after compiling my Visual Studio solution.

To invoke MSBuild from NAnt you should use the <exec /> task. Here is the full example:

 <target name="compile">
<exec program="C:\Windows\Microsoft.NET\Framework\v2.0.50727\MSBuild.exe">
<arg line="yourproject" />
<arg line="/logger:Kobush.Build.Logging.XmlLogger,Kobush.Build.dll;msbuild-output.xml" />
</exec>
</target>

Then in CC.NET the project is executed using the <nant /> task. This time the MSBuild results are written to separate file so you need to add a <merge /> publisher to include the contents of this file in your build resutls.

Displaying build results with XSL stylesheets 

I've included two XSL stylesheets for CC.NET Web Dashboard that can format the msbuild results. The compile-msbuild.xsl creates additonal summary section on the build report page, and the msbuild.xsl is used to configure additonal link in left sidebar showing full formatted output from the msbuild log.

To use these files put them in the xsl subfolder of CCNET web dashboard and add following lines (bold) in your dashbard.config file:

<dashboard>
<buildPlugins>
<buildReportBuildPlugin>
<xslFileNames>
...
<xslFile>xsl\compile-msbuild.xsl</xslFile>  ...
</xslFileNames>
</buildReportBuildPlugin>
...
<xslReportBuildPlugin description="MSBuild Output" actionName="MSBuildOutputBuildReport"
xslFileName="xsl\msbuild.xsl" />
...

Version history

The first version working with .NET 2.0 Beta 1 was created for my internal use, but later I posted it to the CC.NET JIRA. In Beta 2 you can notice that console output was colored but I still haven't found any XmlLogger as part of the MSBuild framework. In that version MSBuild API changed slightly (now each type of build event has different signature) so I published updated version on this blog. This is the version that is distributed with CCNET.

Although the same code works also with the final version of .NET 2.0, I took the opportunity to clear things a bit. The major change is that now I write directly to XmlTextWriter instead of using XmlDocument. This allows me to write output imadiettly as it comes, so now you can observe the progress of your build by watching as the file grows. And if anything goes wrong and MSBuild just stops you at least have some partial log of that. Besides it should be less memory consuming. This required a slight change to the XML format, as now the build duration is written in separate element. The XSL files were updated to reflect this change. Here are other minor fixes: 

  • Fixed: Rounding error when loging TimeSpans (thanks to Morten Teinum)
  • Fixed: DateTime.Parse error in non en-US cultures (thanks to Charles Crichton)
posted on Saturday, January 14, 2006 9:51 AM

Feedback

# re: XmlLogger for MSBuild 1/15/2006 10:54 PM neredera
There is a little error in compile-msbuild.xls:
<xsl:variable name="warnings" select="//msbuild/warning" />
insted of
<xsl:variable name="warnings" select="//msbuild//warning" />
Without this correction no warnings are shown.

# re: XmlLogger for MSBuild 1/16/2006 6:08 AM Szymon
Thanks for letting me know. I've just uploaded fixed version.

# re: XmlLogger for MSBuild 3/23/2006 1:02 PM Teo
I am getting the following Exception:
MSBUILD : error MSB4017: The build was aborted because of an unexpected logger failure.

Any ideas? Thanks.

------------------------------
System.InvalidOperationException: Token StartAttri
bute in state Content would result in an invalid XML document.
at System.Xml.XmlTextWriter.AutoComplete(Token
token)
at System.Xml.XmlTextWriter.WriteStartAttribute
(String prefix, String localName, String ns)
at System.Xml.XmlWriter.WriteAttributeString(St
ring localName, String value)
at Kobush.Build.Logging.XmlLogger.SetAttribute(
String name, Object value) in C:\Temp\Cruise Control\MSBuild Logger\Kobush.Build
.Logging.XmlLogger\src\XmlLogger.cs:line 326
at Kobush.Build.Logging.XmlLogger.LogStageStart
ed(String elementName, String stageName, String file, DateTime timeStamp) in C:\
Temp\Cruise Control\MSBuild Logger\Kobush.Build.Logging.XmlLogger\src\XmlLogger.
cs:line 227
at Kobush.Build.Logging.XmlLogger.eventSource_B
uildStartedHandler(Object sender, BuildStartedEventArgs e) in C:\Temp\Cruise Con
trol\MSBuild Logger\Kobush.Build.Logging.XmlLogger\src\XmlLogger.cs:line 149
at Microsoft.Build.BuildEngine.EventSource.Rais
eBuildStartedEvent(Object sender, BuildStartedEventArgs e)
[Test:Info]: Task execution failed
[Test:Info]: Task output: MSBUILD : error MSB4017: The build was aborted because
of an unexpected logger failure.
System.InvalidOperationException: Token StartAttribute in state Content would re
sult in an invalid XML document.
at System.Xml.XmlTextWriter.AutoComplete(Token token)
at System.Xml.XmlTextWriter.WriteStartAttribute(String prefix, String localNa
me, String ns)
at System.Xml.XmlWriter.WriteAttributeString(String localName, String value)
at Kobush.Build.Logging.XmlLogger.SetAttribute(String name, Object value) in
C:\Temp\Cruise Control\MSBuild Logger\Kobush.Build.Logging.XmlLogger\src\XmlLogg
er.cs:line 326
at Kobush.Build.Logging.XmlLogger.LogStageStarted(String elementName, String
stageName, String file, DateTime timeStamp) in C:\Temp\Cruise Control\MSBuild Lo
gger\Kobush.Build.Logging.XmlLogger\src\XmlLogger.cs:line 227
at Kobush.Build.Logging.XmlLogger.eventSource_BuildStartedHandler(Object send
er, BuildStartedEventArgs e) in C:\Temp\Cruise Control\MSBuild Logger\Kobush.Bui
ld.Logging.XmlLogger\src\XmlLogger.cs:line 149
at Microsoft.Build.BuildEngine.EventSource.RaiseBuildStartedEvent(Object send
er, BuildStartedEventArgs e)



# re: XmlLogger for MSBuild 3/23/2006 1:47 PM Szymon
Teo,
To be honest I have no idea why this happens. From the stack I see that this happens just when the build starts when logger attempts to add timestamp attribute to the root element. But XmlWriter won't accept attributes in it's current state. The only situation I imagine this could happen is when logger recives the BuildStartedEvent second time. Do you build multiple projects in one command line or do something like this ? What is the exact command line you invoke msbuild?

# re: XmlLogger for MSBuild 4/5/2006 5:39 PM Kirk Baucom
I'm trying to use MSBuild with CC.Net and your XmlLogger. I'd like to have tasks run by MSBuild (in particular NUnit) generate XML that ends up as raw XML in the final CC.Net log. I realize I could use a <merge/>, but it seems like it would be easier if CC.Net didn't have to know about a potentially large number of log files. I see in your source code that there is a boolean that causes angle brackets to be passed unescaped, but the output is still wrapped in a CDATA. Is there a reason why you would want legal XML inside a CDATA? It would be nice if either setting the flag to false didn't wrap it in a CDATA or there was another way to write raw XML to the log.

# re: XmlLogger for MSBuild 4/5/2006 6:10 PM Szymon
Kirk,
The reason all messages are put in CDATA is that in most cases they contain output from various tasks and tools invoked during build and potentially can contain texts that would make the whole XML document not valid. Consider an error message citing code line containing some greater then comparision. The logger has no way of knowing which messages can be safely treated as XML. So only sollution was either to escape the angle brackets or put them in CDATA.

# re: XmlLogger for MSBuild 7/19/2006 2:31 PM Morgan
I was working with your logger and I ran into an situation that causes the logger to throw an exception and kill the build.

Basically, I was calling MSBuild on a solution that contains multiple projects. MSBuild reported a warning, about one of the projects. This caused the logger to go into an invalid state when writing the XML. Basically, the sequence of events is such:

Build starts

Initialize method is called.

InitializeLogFile method is called

XmlWriter.WriteStartElement is called to write the opening msbuild tag.

The WarningRaised event fires, calling the eventSource_WarningRaised handler, which calls the LogErrorOrWarning method. This method calls XmlWriter.WriteStartElement(messageType), which starts the warning tag. Four or five calls are made to SetAttribute to write the attributes of the warning tag, then the XmlWriter.WriteEndElement method is called to close the warning tag.

After the warning is written, the BuildStarted event is raised, and handled by the eventSource_BuildStartedHandler method. This method calls the LogStageStarted method. The LogStageStarted method then tries to set some attributes of the msbuild tag. However, because of the warning, the XmlWriter state no longer allows setting of attributes for the msbuild tag, and an exception is thrown.

I'm not sure if this is because of an error in msbuild as far as the order of events raised, or if there's a better way of handling the warning event at the start of the build. I'd really like to use the logger, but I'm not sure how to modify it to handle this. Any ideas?

thanks much,

Morgan

# re: XmlLogger for MSBuild 7/19/2006 2:34 PM Morgan
Actually, the problem in my previous post seems to be related to the situation described in Teo's 3/23/2006 post. It may very well explain his problem as well.

# re: XmlLogger for MSBuild 8/22/2006 12:27 PM hmoeller
I came across the same issue (exception thrown by the XmlLogger after an error message issued by MSBuild right at the beinning).

In my case, the error message stated an orphaned project GUID reference. Actually, one of my projects referenced another one for which the GUID had changed in the meantime. After removing that project reference, MSBuild stopped complaining and the XmlLogger did its job perfectly right.

# re: XmlLogger for MSBuild 8/22/2006 12:36 PM Szymon
Hi hmoeller,
Thanks for raporting this. I've never encountered such problem with my projects so I couldn't find any solution. I hope this would also help anyone alse having such issues.

# re: XmlLogger for MSBuild 5/7/2007 7:09 PM Kevin Gabbert
hmoeller, Szymon,

That was *exactly* the problem I was having! I have a similar story.

I'll include what I got so others can see.

as you will see below, I had 2 errors. Somehow, one of my projects got out of sync, I had noted earlier that I had pointed to the wreng project, then switched back & back again, so I think in the confusion something got misreferenced.

I wound up going into the .sln file & looked up those numbers. The name of the offending project is right next to that number. In this case, it was named "TestHarness".

Turns out that "TestHarness" had a bad reference in it. It compiled fine on my machine, just not on the build server. --likely because of .net's mysteriousness & remembering things it shouldn't.

so in the end, I deleted a bad reference in "TestHarness" and everything works now. What a pain that was!


WHAT VISUAL STUDIO TOLD ME:

Errors:
MSBUILD : error MSB4017: The build was aborted because of an unexpected logger failure.
External Program Failed: C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727/msbuild.exe (return code was 1)


Warnings:
Read-only property "repository.tag.generate" cannot be overwritten.
D:\CCNET\Builds\Fedora\TestBuild\xxx.sln : Solution file warning MSB4051: Project {E33AE51D-3E38-4663-837F-478C4E8D4239} is referencing a project with GUID {756B0BF8-BBD5-4463-ACFC-A717371AF073}, but a project with this GUID was not found in the .SLN file.
D:\CCNET\Builds\Fedora\TestBuild\xxx.sln : Solution file warning MSB4051: Project {E33AE51D-3E38-4663-837F-478C4E8D4239} is referencing a project with GUID {EFCBC07F-73E0-46F7-9487-C909C9BF9690}, but a project with this GUID was not found in the .SLN file.




WHAT THE .SLN FILE HAD IN IT (filtered for your convenience):

Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestHarness", "TestHarness\TestHarness.csproj", "{E33AE51D-3E38-4663-837F-478C4E8D4239}"
ProjectSection(WebsiteProperties) = preProject
Debug.AspNetCompiler.Debug = "True"
Release.AspNetCompiler.Debug = "False"
EndProjectSection
EndProject



WHAT THE ERR'D PROJECT HAD IN IT:

<ProjectReference Include="..\Utilities\Utilities.csproj">
<Project>{EFCBC07F-73E0-46F7-9487-C909C9BF9690}</Project>
<Name>Utilities</Name>
</ProjectReference>


So in the end, I went back into VS & deleted that reference (to Utilities).

Kevin



# re: XmlLogger for MSBuild 2/20/2008 12:37 AM Jason Unsworth
I've also found that XmlLogger will cause "error MSB4017" when it's used to log an MSBuild run where MSBuild verbosity is turned up to "Detailed". (MSBuild verbosity levels below Detailed do seem to work fine with XmlLogger.) Here's a stack trace (when I use NAnt to call NAntContrib's <msbuild> task):

[msbuild] MSBUILD : error MSB4017: The build was aborted because of an unexpected logger failure.
[msbuild] System.InvalidOperationException: Token StartAttribute in state Content would result in an invalid XML document.
[msbuild] at System.Xml.XmlTextWriter.AutoComplete(Token token)
[msbuild] at System.Xml.XmlTextWriter.WriteStartAttribute(String prefix, String localName, String ns)
[msbuild] at System.Xml.XmlWriter.WriteAttributeString(String localName, String value)
[msbuild] at Kobush.Build.Logging.XmlLogger.SetAttribute(String name, Object value)
[msbuild] at Kobush.Build.Logging.XmlLogger.LogStageStarted(String elementName, String stageName, String file, DateTime timeStamp)
[msbuild] at Kobush.Build.Logging.XmlLogger.eventSource_BuildStartedHandler(Object sender, BuildStartedEventArgs e)
[msbuild] at Microsoft.Build.Framework.BuildStartedEventHandler.Invoke(Object sender, BuildStartedEventArgs e)
[msbuild] at Microsoft.Build.BuildEngine.EventSource.RaiseBuildStartedEvent(Object sender, BuildStartedEventArgs e)

# re: XmlLogger for MSBuild 4/21/2009 1:28 PM Paul Tew
Hi Szymon, is there any way of merging several msbuild logs before the main msbuild log is merged? I have a number of projects being compiled within a project block and each of those needs a separate msbuild log file. Paul

# re: XmlLogger for MSBuild 10/23/2009 4:59 AM Alexander Razvalinov
The logger doesn't work with "msbuild.exe /verbosity:detailed" and "... /verbosity:diagnostic"

If set them to any of these values you get MSB4017 error

# re: XmlLogger for MSBuild 11/24/2009 12:58 PM Mark Harmon
I have a workaround for the "Token StartAttribute in state Content would result in an invalid XML document." problem.

Add these private class members to the XmlLogger class.

private bool isBuildStarted = false;
private string extraErrors = string.Empty;

eventSource_BuildStartedHandler should now be:

private void eventSource_BuildStartedHandler(object sender, BuildStartedEventArgs e) {
LogStageStarted(XmlLoggerElements.Build, "", "", e.Timestamp);
isBuildStarted = true;
}

LogErrorOrWrarning changed to this:

private void LogErrorOrWarning(string messageType, string message, string code, string file, int lineNumber, int columnNumber, DateTime timestamp) {
if (isBuildStarted) {
xmlWriter.WriteStartElement(messageType);
SetAttribute(XmlLoggerAttributes.Code, code);

SetAttribute(XmlLoggerAttributes.File, file);
SetAttribute(XmlLoggerAttributes.LineNumber, lineNumber);
SetAttribute(XmlLoggerAttributes.ColumnNumber, columnNumber);

if (Verbosity == LoggerVerbosity.Diagnostic)
SetAttribute(XmlLoggerAttributes.TimeStamp, timestamp);

// Escape < and > if this is not a "Properties" message. This is because in a Properties
// message, we want the ability to insert legal XML, but otherwise we can get malformed
// XML that will cause the parser to fail.
WriteMessage(message, code != "Properties");

xmlWriter.WriteEndElement();
}
else {
extraErrors += string.Format("Code={0},LineNumber={1},ColumnNumber={2}\r\n{3}\r\n",
new object[] { code, lineNumber, columnNumber, message });
}
}


LogStageFinished is:

private void LogStageFinished(bool succeded, DateTime timeStamp) {
// log duration of current stage
DateTime startTime = stageDurationStack.Pop();
if (stageDurationStack.Count == 0 || Verbosity == LoggerVerbosity.Diagnostic) {
TimeSpan duration = timeStamp - startTime;
xmlWriter.WriteStartElement(XmlLoggerElements.Duration);
xmlWriter.WriteValue(duration.TotalSeconds.ToString("g2", CultureInfo.InvariantCulture));
xmlWriter.WriteEndElement();
}

if (string.IsNullOrEmpty(extraErrors) == false) {
xmlWriter.WriteElementString("ExtraErrors", extraErrors);
extraErrors = string.Empty;
}

xmlWriter.WriteEndElement();
xmlWriter.Flush();
}


These code changes track if the BuildStartedHandler has completed yet. If it hasn't then it save any errors or warnings in the extraErrors string. At the end of a stage it writes out these errors. I realize this isn't the most robust solution, but at least it will run and let you see what error or warning occured.



# re: XmlLogger for MSBuild 8/11/2010 4:13 AM Abhinav Nigam
Thank's a lot. For my automated build I am using (default)FileLogger, but from that I am not able to customize the build report.

# re: XmlLogger for MSBuild 1/12/2011 1:05 PM shijith
when i use the logger for a single file the "corebuild" element is displayed in the output xml file , but wenever i try to include all the solution or project files in a particular folder the "core build" element is missing from the o/p xml file.. any suggestions?

# re: XmlLogger for MSBuild 7/11/2012 3:57 PM Elena
First at all thank you for sharing this implementation :-)!

I have a small issue: the output file name I'm using contains blanks and it seems to be a problem for the logger.
Since these blanks are in the folder name (it is a WinXP system with "C:\Documents and settings\...") and I would like to keep the folder I'm storing output files I am just wondering if there is a way to give the logger a path/file name containing blanks?

# Output file name containing blanks --> solved 7/12/2012 11:36 AM Elena
I found a error in my script calling MSBuild, your logger works just fine :-)
Sorry for bothering!

Post A Comment
Title:
Name:
Email:
Comment:
Verification: