10

这不是一个真正的问题,而是一个希望对其他人有所帮助的答案。

那些以前编写过 Windows 服务的人都知道,在其中找到错误可能是一项艰巨的任务,特别是如果它只发生在实时环境中。就我而言,我的服务平稳运行了几个小时,然后因堆栈溢出错误而倒下。没有堆栈跟踪。祝你好运,大海捞针。

该服务确实生成了一个日志文件,并且代码中充斥着日志条目,但就其细节而言,它生成了 500 MB 的日志文件!您几乎无法打开文件,更不用说分析它了。但是你如何解决这个问题?您可以尝试生成信息较少的日志文件,或者在写入新日志条目时自动删除旧日志条目的日志文件,但随后您会丢失错误的重要上下文。

解决方案是一个日志文件,它将跟踪代码中的循环,并自动删除该循环每次成功迭代的日志条目。这样,您可以维护一个高度保留的日志文件,同时该文件仍然相对较小。当您的服务中断时,您的日志文件会告诉您它发生的确切位置,以及所有必要的上下文来解释它是如何发生的以及为什么发生。

您可以从http://sourceforge.net/projects/smartl/files/?source=navbar下载此日志文件生成器。它是一个独立的类,它的所有方法都是静态的。提供了一个示例类来向您展示如何正确使用日志记录方法:

    public void ExampleMethod()
    {           
        SmartLog.EnterMethod("ExampleMethod()"); 
        try
        {
            SmartLog.Write("Some code happening before the loop");

            Guid exampleLoopID = SmartLog.RegisterLoop("exampleLoopID");
            for (int i = 0; i < 10; i++)
            {
                SmartLog.IncrementLoop(exampleLoopID);

                SmartLog.Write("Some code happening inside the loop.");

            }
            SmartLog.CompleteLoop(exampleLoopID);

            SmartLog.Write("Some code happening after the loop.");

            SmartLog.LeaveMethod("ExampleMethod()");
        }
        catch (Exception ex)
        {
            SmartLog.WriteException(ex);
            SmartLog.LeaveMethod("ExampleMethod()");
            throw;
        }
    }

确保您的应用程序对其根文件夹具有读写权限。

如果您执行代码,并在循环中将其中断,则日志文件将如下所示:

. ENTER METHOD: FirstMethod()
some code happening here.
Calling a different method:

. . ENTER METHOD: ExampleMethod()
some code happening before the loop.

LOOP: doWorkLoopID [4135a8ed-05b7-45de-b887-b2ab3c638faa] - CURRENT ITERATION: 20
some code happening inside the loop.

循环完成后,其内容将被删除,您的日志文件将如下所示:

. ENTER METHOD: FirstMethod()
some code happening here.
Calling a different method:

. . ENTER METHOD: ExampleMethod()
some code happening before the loop.

LOOP: doWorkLoopID [4135a8ed-05b7-45de-b887-b2ab3c638faa] - TOTAL ITERATIONS: 22

some code happening after the loop.
. . LEAVING METHOD: ExampleMethod()

some code happening here.
some code happening here.
. LEAVING METHOD: FirstMethod()

我希望这可以帮助某人解决这个问题,否则这可能需要数周时间。它确实对我有用。

4

3 回答 3

1

这是我的静态记录器解决方案。对所有项目有用,不仅服务:

申请开始于:

MyLog.Reset();

Yhen 每个静态或非静态方法都以:

System.Diagnostics.StackTrace stackTrace = new System.Diagnostics.StackTrace(); MyLog.Log("", stackTrace.GetFrame(0).GetMethod().DeclaringType.ToString(), stackTrace.GetFrame(0).GetMethod().Name, 0);

结果是一个 Graphviz 图源,如下所示: 请注意,当您从 log.text 复制文本以生成 GraphViz 图时,应手动添加最后一个右大括号。

digraph G{arrowsize=2.0; ratio=fill; node[fontsize=24];graph [fontsize=24] edge [fontsize=24] node [fontsize=24] ranksep = 1.5 nodesep = .25 edge [style="setlinewidth(3)"]; 

subgraph cluster_Riogrande_UI { node [style=filled]; label = "Riogrande_UI"; color=red  
subgraph cluster_UsersForm { node [style=filled]; _ctor_UF; label = "UsersForm"; color=blue }}
subgraph cluster_Riogrande_DL { node [style=filled]; label = "Riogrande_DL"; color=red  
subgraph cluster_DataAccessUsers { node [style=filled]; _ctor_DAU; label = "DataAccessUsers"; color=blue    }}
_ctor_UF -> _ctor_DAU;
}

这是来自GraphViz的图表:

结果

这是我使用的类:

namespace Riogrande
{
    public class MyLog
    {
        private static int MaximAcceptedLevel = 5;
        private static string lastMethodName = string.Empty;
        private static string filePath = "log.txt";

        public static void Log(string namespaceName, string className, string methodName, int logLevel)
        {
            if (logLevel < MaximAcceptedLevel)
            using (StreamWriter w = File.AppendText(filePath))
            {
                string namespceName = className.Substring(0, className.LastIndexOf('.')).Replace('.', '_');

                if (className.Contains('.'))
                {
                    className = className.Substring(className.LastIndexOf('.') + 1);
                }
                if (className.Contains('+'))
                {
                    className = className.Substring(0, className.LastIndexOf('+'));
                }
                className = className.Replace('.', '_');
                string cls = "";
                for (int i = className.Length-1; i > -1; i--)
                {
                    if (Char.IsUpper(className[i]))
                    {
                        if (cls.Length < 3)
                        {
                            cls = className[i] + cls;
                        }
                    }
                }
                string currentMethodName = methodName.Replace('.', '_') + "_" + cls;
                w.WriteLine("subgraph cluster_" + namespceName + " { node [style=filled]; label = \"" + namespceName + "\"; color=red   ");
                w.WriteLine("subgraph cluster_" + className + " { node [style=filled]; " + currentMethodName + "; label = \"" + className + "\"; color=blue }}");
                if (!string.IsNullOrEmpty(lastMethodName))
                {
                    w.WriteLine(lastMethodName + " -> " + currentMethodName + ";");
                }
                lastMethodName = currentMethodName;
            }
        }

        public static void Reset()
        {
            File.Delete(filePath);
            using (StreamWriter w = File.AppendText(filePath))
            {
                w.WriteLine("digraph G{arrowsize=2.0; ratio=fill; node[fontsize=24];graph [fontsize=24] edge [fontsize=24] node [fontsize=24] ranksep = 1.5 nodesep = .25 edge [style=\"setlinewidth(3)\"]; ");
                w.WriteLine();
            }
        }    
    }
}

该解决方案不提供小文件,但您可以在同一个类中实现此选项。

于 2013-10-19T18:00:15.780 回答
0

解决方案是一个日志文件,它将跟踪代码中的循环,并自动删除该循环每次成功迭代的日志条目。这样,您可以维护一个高度保留的日志文件,同时该文件仍然相对较小。当您的服务中断时,您的日志文件会告诉您它发生的确切位置,以及所有必要的上下文来解释它是如何发生的以及为什么发生。

您可以从http://sourceforge.net/projects/smartl/files/?source=navbar下载此日志文件生成器。它是一个独立的类,它的所有方法都是静态的。提供了一个示例类来向您展示如何正确使用日志记录方法:

public void ExampleMethod()
{           
    SmartLog.EnterMethod("ExampleMethod()"); 
    try
    {
        SmartLog.Write("Some code happening before the loop");

        Guid exampleLoopID = SmartLog.RegisterLoop("exampleLoopID");
        for (int i = 0; i < 10; i++)
        {
            SmartLog.IncrementLoop(exampleLoopID);

            SmartLog.Write("Some code happening inside the loop.");

        }
        SmartLog.CompleteLoop(exampleLoopID);

        SmartLog.Write("Some code happening after the loop.");

        SmartLog.LeaveMethod("ExampleMethod()");
    }
    catch (Exception ex)
    {
        SmartLog.WriteException(ex);
        SmartLog.LeaveMethod("ExampleMethod()");
        throw;
    }
}

确保您的应用程序对其根文件夹具有读写权限。

如果您执行代码,并在循环中将其中断,则日志文件将如下所示:

. ENTER METHOD: FirstMethod()
some code happening here.
Calling a different method:

. . ENTER METHOD: ExampleMethod()
some code happening before the loop.

LOOP: doWorkLoopID [4135a8ed-05b7-45de-b887-b2ab3c638faa] - CURRENT ITERATION: 20
some code happening inside the loop.

循环完成后,其内容将被删除,您的日志文件将如下所示:

. ENTER METHOD: FirstMethod()
some code happening here.
Calling a different method:

. . ENTER METHOD: ExampleMethod()
some code happening before the loop.

LOOP: doWorkLoopID [4135a8ed-05b7-45de-b887-b2ab3c638faa] - TOTAL ITERATIONS: 22

some code happening after the loop.
. . LEAVING METHOD: ExampleMethod()

some code happening here.
some code happening here.
. LEAVING METHOD: FirstMethod()
于 2013-10-16T10:10:05.050 回答
0

干得好,但如果真正的问题是处理大日志甚至大日志,你应该看看 microsoft LogParser。只要您正确格式化日志文件,您就可以像在 SQL 中使用的那样查询日志。您甚至可以根据结果创建 csv 文件并对其进行分析,或者使用库在 .net 应用程序中执行复杂的操作。

例如,假设您要选择给定页面的所有 IIS 条目并将结果保存为 CSV,您可以执行以下操作

logparser "select * into LANDINGPAGEHITS.CSV from [yourlogfile] where cs-uri-stem like '/home.aspx"

我的意思不是要打破你的泡沫,而是要告诉你如何处理大文件,如果你以前格式化了你的应用程序日志输出,而不用担心从中删除条目。

于 2013-10-15T19:32:38.303 回答