Today I wanted to setup a debugging page to read the trace log for our prototype WCF services and display the last 10 messages that have come across the wire. I'm using the XmlWriterTraceListener to write the entries. The XmlWriterTraceListener writes Xml fragments to the log file.  This is good and all but the problem is reading in the log. Since a well formed xml file can only have one root element the log cant be successfully parsed (As far as I could tell anyway's, if anyone knows of another way please let me know). So the only decent solution I could come up with was to create a reader that injects a root element.  The usage is simple, just pass in a stream or stream reader and the name of the root element:

XDocument log = XDocument.Load(
    new XmlFragmentTextReader(
        new FileStream(
            @"D:\Logs\Wcf.log", 
            FileMode.Open, 
            FileAccess.Read, 
            FileShare.ReadWrite), 
         "root"));

var entries = from entry in log.Element("root")
                  .Elements(
                    XName.Get(
                    "E2ETraceEvent", 
                    "http://schemas.microsoft.com/2004/06/E2ETraceEvent"))
              select entry;

foreach (XElement entry in entries)
{
    // Do Something...
}

Here is the implementation. Since the read/peek methods in the readers in the BCL are not virtual I'm forced to choose aggregation over inheritance. Only the Read and Peek methods need to be implemented as all other methods call these in the base TextReader class.

public class XmlFragmentTextReader : TextReader
{
    #region Private Members

        private enum Location
        { RootOpen, Fragments, RootClose }

        private StreamReader _fragmentReader;
        private Location _location = Location.RootOpen;
        private int _index = 0;
        private char[] _rootOpenBuffer;
        private char[] _rootCloseBuffer;

    #endregion

    #region Constructors

        public XmlFragmentTextReader(StreamReader reader, 
            string rootElementName) : base()
        {
            _fragmentReader = reader;
            _rootOpenBuffer = string.Format("<{0}>\r\n", 
                rootElementName).ToCharArray();
            _rootCloseBuffer = string.Format("\r\n", 
                rootElementName).ToCharArray();
        }

        public XmlFragmentTextReader(Stream stream, 
            string rootElementName) : 
            this(new StreamReader(stream), rootElementName) { }

    #endregion

    #region Overridden Methods

        public override int Peek()
        {
            switch (_location)
            {
                case Location.RootOpen:
                    return _rootOpenBuffer[_index];
                case Location.Fragments:
                    return _fragmentReader.Peek();
                case Location.RootClose:
                    return _rootCloseBuffer[_index];
                default : return - 1;
            }
        }

        public override int Read()
        {
            switch (_location)
            {
                case Location.RootOpen:
                    if (_index < _rootOpenBuffer.Length)
                        return _rootOpenBuffer[_index++];
                    else
                    {
                        _location = Location.Fragments;
                        return Read();
                    }
                case Location.Fragments:
                    if (!_fragmentReader.EndOfStream)
                        return _fragmentReader.Read();
                    else
                    {
                        _location = Location.RootClose;
                        _index = 0;
                        return Read();
                    }
                case Location.RootClose:
                    if (_index < _rootCloseBuffer.Length)
                        return _rootCloseBuffer[_index++];
                    else return -1;
                default: return -1;
            }
        }

        public override void Close()
        { _fragmentReader.Close(); }

    #endregion
}

Like I said, if anyone knows of a better way please drop me a line!