TraceSource.TraceEvent()在记录包含非可打印字符的异常信息时失败。

3

我有一个调用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
        }
    }
}

在某些情况下,我无法读取异常信息,因此无法确定第二个调用是否在WADLogsTable中找到。是否有某些字符不被TraceSourceDiagnosticMonitor允许使用?
为了进一步缩小范围,所讨论的异常实际上是异常的InnerException:"XML文档(72,-499)存在错误"。导致异常的XML包含无效字符实体,例如。是否可能异常消息包含这些字符实体,而TraceSource无法记录它们? 编辑:最终我能够在我的开发环境中重现此问题,因此我能够在调试器中检查异常。无法记录的异常是一个XmlException

'', hexadecimal value 0x11, is an invalid character. Line 72, position -499.

引号之间的是不可打印字符-在调试器中显示为黑色三角形。因此,这使我相信我的怀疑是正确的-某些日志记录机制不喜欢不可打印字符。那么,哪个部分?或者更重要的是,由于看起来我需要从跟踪开始对所有字符串进行消毒,我应该查找哪些字符以进行删除?
是否有一些内置函数可以消毒字符串,删除不可打印字符?
2个回答

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的引用才能使其正常运行。


谢谢Jeremy。这不是一个坏答案,但不完全是我想要的。我只想处理控制字符,而HTML并不一定是我想要的目标编码。 - gilly3
好的,但是跟踪源是否也不喜欢非引用的XML实体,例如<和>以及"? - Jeremy McGee

1

另一个问题的答案帮助我找到了解决方案。为了方便,我添加了几个扩展方法:

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());
}

我喜欢不必每次调用TraceEvent时都将MyEvtEnum强制转换为int的额外好处,这样做还增加了一个自然的重载,感觉像是双倍的收获。

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

我不想接受自己的答案,所以如果你有其他解决方案或改进我的方案,请发表并且如果更好,我会接受它。


看起来很整洁。是的,我完全同意,这不应该发生。我怀疑你可以找到一种方法,只替换控制字符而保留换行符。 - Jeremy McGee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接