当Exception消息包含不可打印的字符时,TraceSource.TraceEvent()无法记录日志

时间:2011-09-30 19:11:08

标签: c# logging unicode azure azure-diagnostics

我打电话给TraceSource.TraceEvent(),有时候没有写入Azure诊断日志。

public class WorkerRole : RoleEntryPoint
{
    private TraceSource trace = new TraceSource(
        "ImportService", SourceLevels.Information);

    public override void Run()
    {
        ...
        try
        {
            ...
        }
        catch (Exception ex)
        {
            bool hasMsg = !string.IsNullOrEmpty(ex.Message);
            trace.TraceEvent(TraceEventType.Error, 0,
                "ex has message: " + hasMsg.ToString());   // this gets logged
            trace.TraceEvent(TraceEventType.Error, 0,
                "Inner exception message: " + ex.Message); // this does not
        }
    }
}

在某些情况下,我无法分辨哪个因为我无法读取Exception消息,所以在WADLogsTable中找不到第二个调用。是TraceSource还是DiagnosticMonitor

是否存在某些不允许的字符

为了进一步缩小范围,有问题的异常实际上是异常的InnerException:“XML文档中存在错误(72,-499)”。导致异常的XML包含无效的字符实体,例如。可能是Exception消息包含一些这些字符实体而且TraceSource无法记录它们吗?

编辑:我能够在我的开发环境中最终重现这一点,因此我能够在调试器中检查异常。不记录的异常是XmlException

  

'',十六进制值0x11,是无效字符。第72行,位置-499。

在引号之间是不可打印的字符 - 它在调试器中显示为黑色三角形。所以,这让我相信我的怀疑是正确的 - 某些记录机制不喜欢不可打印的字符。那么,哪一块?或者,更重要的是,因为看起来我需要在跟踪时开始清理所有字符串,我应该找哪些字符删除?

是否有一些内置函数可以清理字符串,删除不可打印的字符?

2 个答案:

答案 0 :(得分:1)

有趣。看起来您需要对异常字符串进行HTML编码。这会将引号变为例如"和您的ASCII非打印字符或类似内容。

所以:

    trace.TraceEvent(TraceEventType.Error, 0,
        "ex has message: " + HttpUtility.HtmlEncode(hasMsg.ToString()));   
    trace.TraceEvent(TraceEventType.Error, 0,
        "Inner exception message: " + HttpUtility.HtmlEncode(ex.Message)); 

应该工作得很好。

令人沮丧的是,HttpUtility在System.Web中,您需要添加对System.Web.dll的引用才能实现此目的。

答案 1 :(得分:1)

The answer to another question帮助我找到了解决方案。为方便起见,我添加了几个扩展方法:

public static string RemoveControlChars(this string s)
{
    return Regex.Replace(s, @"(?![\r\n])\p{Cc}", "");
}
public static void TraceEvent(this TraceSource trace, 
    TraceEventType eventType, MyEvtEnum eventId, string message)
{
    trace.TraceEvent(eventType, (int)eventId, message.RemoveControlChars());
}

我喜欢每次拨打MyEvtEnum时不必将int投射到TraceEvent的额外好处,并且它会增加自然超载,所以这感觉就像双赢。

让我感到困扰的是我必须这样做。诊断系统的主要用途之一是记录异常。这样的诊断系统应该能够处理异常消息可能包含的任何字符串。 我也失去了换行符,这令人沮丧。 编辑:失去换行符是RemoveControlChars()的副作用。我没有意识到\r\n被包含为“控制字符”。我已将正则表达式更新为不替换\r\n字符。

我不喜欢接受我自己的答案,所以如果你有替代解决方案或我的改进,请发布它,如果它更好,我会接受它。