2013-09-17 2 views
10

Это не вопрос, а ответ, который, мы надеемся, поможет другим людям.Отладка ошибок переполнения стека в фоновых сервисах

Те, кто написал службу окна раньше, знает, что миссия это может быть, чтобы найти ошибку в этом, особенно если это происходит только на живом окружении. В моем случае у меня была служба, которая работала гладко в течение нескольких часов, а затем упала из-за ошибки переполнения стека. Нет трассировки стека. Удачи найти иглу в стоге сена.

служба сделал создать файл журнал, а код был завален записями журнала, но, как подробно, как есть было, он произвел лог файлы 500 МБ! Вы едва могли открыть файл, не считая его анализа. Но как вы обошли эту проблему? Вы можете попытаться создать файлы журналов с меньшей информацией или автоматически удалить старые записи журналов, поскольку записываются новые, но затем вы теряете важный контекст ошибки.

Решение лог-файл, который будет следить за петлями в коде, и автоматически удалять записи журнала для каждой успешной итерации этого цикла. Таким образом, вы можете поддерживать файл с задержанным долгом, который остается относительно небольшим одновременно. Когда ваш сервис ломается, ваш файл журнала скажет вам, где именно произошло, плюс весь необходимый контекст, чтобы объяснить, как и почему это произошло.

Вы можете скачать этот генератор журнала с 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() 

Надеюсь, это поможет кому-то решить эту проблему, которая в противном случае могла занять недели. Он наверняка сделал трюк для меня.

+8

Положите свое решение в качестве ответа. Прочитайте еще раз http://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/ –

+6

Это прекрасно, и на самом деле поощряется переполнение стека. Но вы все равно должны представить его в вопросе, который вы затем отвечаете самим. –

+1

Спасибо за ваш вклад. Я призываю вас сделать то, что предложили другие: отредактируйте свой вопрос, чтобы это был просто вопрос, затем отправьте ответ в качестве ответа. Когда у вас будет достаточно репутации для прохождения ограничений для новых пользователей, вы можете отправить свой вопрос и ответить одновременно. – User

ответ

0

Хорошая работа, но если настоящая проблема работает с большими журналами или даже огромными журналами, вы должны взглянуть на microsoft LogParser. Пока вы правильно отформатируете файлы журнала, вы сможете запросить журнал так же, как и в SQL. Вы даже можете создавать csv-файлы из результатов и анализировать их или использовать библиотеки для выполнения сложных операций в приложении .net.

Например, вы хотите, чтобы выбрать все записи IIS для данной страницы и сохранить результаты в CSV, вы могли бы сделать что-то вроде этого

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

Моей точки здесь не лопнут ваш пузырь, но и покажите вам, как обрабатывать большие файлы, если вы ранее формировали вывод журнала приложений и не беспокоились о том, чтобы удалить записи из него.

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() 
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:

The result

Это класс я использую:

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

решение не обеспечивает небольшой размер файла, но вы можете реализуйте эту опцию в том же классе.

Смежные вопросы