これまで私は同じ問題を抱えていましたが、本当にすぐに私がMono.Cecilを使って一連のDLLをDLLに挿入する機能を手に入れました。以下のコードは、DLLの署名されていないバージョンにトレースを挿入し、開始時にロギング行を注入してコードに "インデントされたトレース"を作成するために使用できる新しいDLLを出力しますそれぞれのコールの入力と存在を時間を計ることができるようにします。サードパーティのツールがたくさんありますが、これは簡単です(最高でうまく動作します)、開発者を完全に制御し、ボーナスとして無料です。
また、トレースクラスを持つDLL(以下のIISStackTraceProvider)と、データのログに使用できる静的呼び出し "TraceStep"を作成する必要があります。ワーカープロセスとスレッド間でそのデータを再構築するには、 "HttpContext.Itemsプロパティ"を使用してBeginRequest/EndRequestにGUIDとストップウォッチを関連付けます。あなたのコールがハングアップしているので...「開始」しても「終了」しない、またはタイムアウトで終了するコールをトレースし、残りの部分を投げ捨てて速く保つことができます。
パフォーマンスに影響を与えずに、どのような要求を記録したいのか、どんな要求を捨て去るのかに注意しながら、本番環境のWebファームで1時間あたり100万件の呼び出しに対してこれをテストしました。また、私は書き込み時間が非常に速く、また無料であるため、Redisを使ってログをキャプチャしました。問題がトラップされると、Redisデータを読み取るだけです。
class TraceInjection
{
private ELogLevel logLevel;
public enum ELogLevel
{
eLow,
eMid,
eHigh
}
public TraceInjection(ELogLevel logLevel)
{
this.logLevel = logLevel;
}
public bool InjectTracingLine(string assemblyPath, string outputDirectory)
{
CustomAttribute customAttr;
AssemblyDefinition asmDef;
// New assembly path
string fileName = Path.GetFileName(assemblyPath);
string newPath = outputDirectory + "\\" + fileName;
// Check if Output directory already exists, if not, create one
if (!Directory.Exists(outputDirectory))
{
Directory.CreateDirectory(outputDirectory);
}
ModuleDefinition modDefCopy = null;
TypeDefinition typDefCopy = null;
try
{
var resolver = new DefaultAssemblyResolver();
resolver.AddSearchDirectory(System.IO.Path.GetDirectoryName(assemblyPath));
var parameters = new ReaderParameters
{
AssemblyResolver = resolver,
};
// Load assembly
asmDef = AssemblyDefinition.ReadAssembly(assemblyPath, parameters);
String functionsFound = "";
foreach (var modDef in asmDef.Modules)
{
modDefCopy = modDef;
foreach (var typDef in modDef.Types)
{
typDefCopy = typDef;
foreach (MethodDefinition metDef in typDef.Methods)
{
try
{
// Skipping things I personally don't want traced...
if (metDef.IsConstructor ||
metDef.IsAbstract ||
metDef.IsCompilerControlled ||
metDef.IsGetter ||
metDef.IsSetter
) continue;
functionsFound += String.Format("{0}\r\n", metDef.Name.Trim());
// Get ILProcessor
ILProcessor ilProcessor = metDef.Body.GetILProcessor();
/*** Begin Method ******/
// Load fully qualified method name as string
Instruction i1 = ilProcessor.Create(
OpCodes.Ldstr,
String.Format(">,{0},{1}", metDef.Name.Replace(",", ""), asmDef.Name.Name)
);
ilProcessor.InsertBefore(metDef.Body.Instructions[0], i1);
// Call the method which would write tracing info
Instruction i2 = ilProcessor.Create(
OpCodes.Call,
metDef.Module.Import(
typeof(IISStackTraceProvider).GetMethod("TraceStep", new[] { typeof(string) })
)
);
ilProcessor.InsertAfter(i1, i2);
}catch(Exception ex)
{
// ...
}
}
}
}
Console.Write(functionsFound);
Console.ReadKey();
// Save modified assembly
asmDef.Write(newPath, new WriterParameters() { WriteSymbols = true });
}
catch (Exception ex)
{
modDefCopy = null;
typDefCopy = null;
// Nothing to be done, just let the caller handle exception
// or do logging and so on
throw;
}
return true;
}
public bool TryGetCustomAttribute(MethodDefinition type, string attributeType, out CustomAttribute result)
{
result = null;
if (!type.HasCustomAttributes)
return false;
foreach (CustomAttribute attribute in type.CustomAttributes)
{
if (attribute.Constructor.DeclaringType.FullName != attributeType)
continue;
result = attribute;
return true;
}
return false;
}
}
デバッガを接続するか、ログを追加します。 – CodeCaster
ステップ1 - 完全なメモリダンプを取得します。タスクエクスプローラまたはデバッグツールで実行できます。ステップ2 - [Debug Diagnostic Tool](https://www.microsoft.com/en-us/download/details.aspx?id=49924)を使用してメモリダンプを解析するか、Windbgを使用してください最初のオプション)。スレッドの完全なリストを取得し、スレッドごとにスタックを呼び出すことは比較的簡単です。Webアプリケーションが応答しなくなったと思うときは、メモリダンプを作成する必要があります。 – Igor
サイドノート - 'Debug Diagnostic Tool'アプリは非常にうまく作られており、ダウンロードして試してみます。それは完全なGUIを持っているので、コマンドを学ぶ必要はありません。結果を分析するために少しは努力しますが、このようなことを考え出すことは、あなたがそれに近づく方法にかかわらず、通常は簡単な作業ではありません。 – Igor