1

我通过执行以下内部方法向我的应用程序添加了自定义跟踪,我想了解以下信息:

public static void MyMethod(params)
{
    pathTrace += "MyMethod(" + params + "){";

    // Some method calls and calculations etc ...

    pathTrace += INTERESTINGOUTPUT + "}";
}

一旦用户旅程结束,pathTrace 字符串就会被发送到数据库,其中包含我感兴趣的所有方法以及参数和输出,格式清晰易读。

然而,这看起来很难看,因为我必须将 pathTrace 增量器添加到每个方法中......

任何人都可以建议一种方法,我可以编写一个为我添加这个的方法(如果可能的话,包括参数和输出和括号),这样我也许可以这样称呼它:

public static void MyMethd(params)
{
    pathTrace();

    // Some method calls and calculations etc ...
}

理想情况下,我希望包括开始结束括号(我觉得这是困难的部分)......

非常感谢任何建议!谢谢

4

2 回答 2

1

如果您按照您要求的方式调用它,则必须检查堆栈跟踪以找到调用方法的名称并进行大量反射以收集运行时参数信息,并且成本很高。你当然不能把电话留在原地。

您可以通过将一些冗余信息(例如当前方法名称)传递给您的跟踪内容来避免大部分成本。我已经做了类似的事情,这样我就可以使用跟踪包装器“检测”方法的主体。调用可能如下所示:

static void DoSomeMethod( )
{
  Tracer.TraceRun( "DoSomeMethod", ( ) =>
  {
    //--> body of method...
    var x = DoSomeFunction( );

  } );
}

static int DoSomeFunction( )
{
  return Tracer.TraceRun( "DoSomeFunction", ( ) =>
  {

    //--> body of method...
    return 9 - DoSomeFunctionWithArgs( 3 );

  } );
}

static int DoSomeFunctionWithArgs( int arg )
{
  return Tracer.TraceRun( "DoSomeFunctionWithArgs", ( ) =>
  {

    //--> body of method...
    return 1 + arg;

  }, arg );
}

...运行的预期输出DoSomeMethod()将是:

DoSomeMethod(){
 DoSomeFunction(){
  DoSomeFunctionWithArgs(3){
   4}
  5}
 }

为了使这项工作,Tracer.TraceRun被重载,以便我可以执行方法和功能:

class Tracer
{
  [ThreadStatic]
  private static int depth = 0;
  public static void TraceRun( string name, Action method, params object[ ] args )
  {
    TraceStartCall( name, args );
    depth++;
    method( );
    TraceEndCall( );
    depth--;
  }

  public static T TraceRun<T>( string name, Func<T> function, params object[ ] args )
  {
    TraceStartCall( name, args );
    depth++;
    var results = function( );
    TraceEndCall( results );
    depth--;
    return results;
  }

  private static void TraceStartCall( string functionName, params object[ ] args )
  {
    Trace.WriteLine
    (
      string.Format
      (
        "{0}: {1}{2}({3}){{",
        Thread.CurrentThread.ManagedThreadId,
        new string( ' ', depth ),
        functionName,
        args == null ?
          string.Empty :
          string.Join( ", ", Array.ConvertAll( args, i => i.ToString( ) ).ToArray( ) )
      )
    );
  }

  private static void TraceEndCall( object results = null )
  {
    Trace.WriteLine
    (
      string.Format
      (
        "{0}: {1}{2}}}",
        Thread.CurrentThread.ManagedThreadId,
        new string( ' ', depth ),
        results
      )
    );
  }


}

这段代码以廉价和简单的方式处理线程管理问题...只需输出 threadId 以便您可以查看线程如何互操作(并使用 ThreadStatic 标记 Tracer 的深度)。当我运行它时,输出看起来像这样:

10: DoSomeMethod(){
10:  DoSomeFunction(){
10:   DoSomeFunctionWithArgs(3){
10:    4}
10:   5}
10:  }
于 2015-12-08T21:53:52.373 回答
1

两种技术,一种简单但不优雅,另一种很难,你真的需要工具。

方法一:创建一个实现IDisposable的定时器类

public class MyTimer:IDisposable{
     // Start timer in constructor
     // end time in Dispose()
}

当您使用时,这会将时间跟踪到一行代码加上花括号

public void MyMethod(){
   using (MyTimer()){
   //method body
   }
}

或者,您使用程序集重写,作为后编译步骤,工具会查找具有属性的方法并注入额外的代码。这是面向方面的编程,这里讨论了 C# 中的各种技术。

于 2015-12-08T16:02:41.093 回答