Кто должен регистрировать ошибку/исключение

Я пытаюсь выяснить лучшие практики при регистрации исключений.

До сих пор я веду журнал каждый раз, когда ловлю исключение. Но когда класс более низкого уровня перехватывает исключение (скажем, из уровня базы данных) и оборачивает его в исключение нашего собственного приложения — должен ли я также регистрировать исходное исключение или я должен просто позволить классу верхнего рычага регистрировать все детали?
А как насчет мест, где мой класс более низкого уровня решает создать исключение из-за неверных входных параметров? Должен ли он также регистрировать исключение или, еще раз, просто позволить перехватывающему коду регистрировать его?


person Noam Gal    schedule 13.08.2009    source источник


Ответы (4)


В основном вам следует избегать регистрации его как в улове более низкого уровня, так и в улове более высокого уровня, так как это раздувает журнал избыточной информацией (не говоря уже о том, что для записи в журнал требуются дополнительные ресурсы ввода-вывода).

Если вы ищете общие рекомендации по обработке исключений, эта ссылка будет удобна. .

person Nelson    schedule 13.08.2009

Вы можете избежать ведения журнала только один раз на самом верхнем уровне вашего приложения, если ваш код ведения журнала (а) регистрирует трассировку стека исключения и (б) также регистрирует всю цепочку внутренних исключений.

Блок приложения Microsoft Exception Handling Application Block позаботится обо всех этих вещах за вас. Я предполагаю, что другие фреймворки ведения журналов сделали бы то же самое.

person Christian Hayter    schedule 13.08.2009

В моих приложениях winform я создал Observer для ведения журнала. У Observer есть подписчики, которые могут куда-то записывать лог или обрабатывать его. Это выглядит:

    public static class LoggingObserver
    {
        /// <summary>
        /// Last getted log message
        /// </summary>
        public static string LastLog;

        /// <summary>
        /// Last getted exception
        /// </summary>
        public static Exception LastException;

        /// <summary>
        /// List of log's processors
        /// </summary>
        public static List<BaseLogging> loggings = new List<BaseLogging>();

        /// <summary>
        /// Get Exception and send for log's processors
        /// </summary>
        /// <param name="ex">Exception with message</param>
        public static void AddLogs(Exception ex)
        {
            LastException = ex;
            LastLog = string.Empty;
            foreach (BaseLogging logs in loggings)
            {
                logs.AddLogs(ex);
            }
        }

        /// <summary>
        /// Get message log for log's processors
        /// </summary>
        /// <param name="str">Message log</param>
        public static void AddLogs(string str)
        {
            LastException = null;
            LastLog = str;
            foreach (BaseLogging logs in loggings)
            {
                logs.AddLogs(str);
            }
        }

        /// <summary>
        /// Close all processors
        /// </summary>
        public static void Close()
        {
            foreach (BaseLogging logs in loggings)
            {
                logs.Close();
            }
        }
    }

Абстрактный класс подписчика:

public abstract class BaseLogging
    {
        /// <summary>
        /// Culture (using for date) 
        /// </summary>
        public CultureInfo culture;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="culture">Culture</param>
        public BaseLogging(CultureInfo culture)
        {
            this.culture = culture;
        }

        /// <summary>
        /// Add log in log system
        /// </summary>
        /// <param name="str">message of log</param>
        public virtual void AddLogs(string str)
        {
            DateTime dt = DateTime.Now;

            string dts = Convert.ToString(dt, culture.DateTimeFormat);

            WriteLine(String.Format("{0} : {1}", dts, str));
        }

        /// <summary>
        /// Add log in log system
        /// </summary>
        /// <param name="ex">Exception</param>
        public virtual void AddLogs(Exception ex)
        {
            DateTime dt = DateTime.Now;

            string dts = Convert.ToString(dt, culture.DateTimeFormat);
            WriteException(ex);
        }

        /// <summary>
        /// Write string on log system processor 
        /// </summary>
        /// <param name="str">logs message</param>
        protected abstract void WriteLine(string str);

        /// <summary>
        /// Write string on log system processor 
        /// </summary>
        /// <param name="ex">Exception</param>
        protected abstract void WriteException(Exception ex);

        /// <summary>
        /// Close log system (file, stream, etc...)
        /// </summary>
        public abstract void Close();
    }

И реализация для ведения журнала в файл:

/// <summary>
    /// Logger processor, which write log to some stream
    /// </summary>
    public class LoggingStream : BaseLogging
    {
        private Stream stream;

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="stream">Initialized stream</param>
        /// <param name="culture">Culture of log system</param>
        public LoggingStream (Stream stream, CultureInfo culture)
            : base(culture)
        {
            this.stream = stream;
        }

        /// <summary>
        /// Write message log to stream
        /// </summary>
        /// <param name="str">Message log</param>
        protected override void WriteLine(string str)
        {
            try
            {
                byte[] bytes;

                bytes = Encoding.ASCII.GetBytes(str + "\n");
                stream.Write(bytes, 0, bytes.Length);
                stream.Flush();
            }
            catch { }
        }

        /// <summary>
        /// Write Exception to stream
        /// </summary>
        /// <param name="ex">Log's Exception</param>
        protected override void WriteException(Exception ex)
        {
            DateTime dt = DateTime.Now;

            string dts = Convert.ToString(dt, culture.DateTimeFormat);
            string message = String.Format("{0} : Exception : {1}", dts, ex.Message);
            if (ex.InnerException != null)
            {
                message = "Error : " + AddInnerEx(ex.InnerException, message);
            }
            WriteLine(message);
        }
        /// <summary>
        /// Closing stream
        /// </summary>
        public override void Close()
        {
            stream.Close();
        }

        private string AddInnerEx(Exception exception, string message)
        {
            message += "\nInner Exception : " + exception.Message;
            if (exception.InnerException != null)
            {
                message = AddInnerEx(exception.InnerException, message);
            }
            return message;
        }
    }

С использованием:

//initialization 
FileStream FS = new FileStream(LogFilePath, FileMode.Create);
LoggingObserver.loggings.Add(new LoggingStream(FS, Thread.CurrentThread.CurrentCulture));
//write exception 
catch (Exception ex) {
LoggingObserver.AddLog(new Exception ("Exception message", ex));
}
//write log 
LoggingObserver.AddLog("Just a log");
person Chernikov    schedule 13.08.2009
comment
Как это отвечает на вопросы ОП? - person Nelson; 13.08.2009
comment
Использование различных подписчиков для журналов процессов. Это мой лучший опыт. - person Chernikov; 13.08.2009

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

я бы предложил

try{
.
.
.
} catch(Exception ex){
 ... log ....
 throw;
}

если вам нужно войти в систему и передать исключение.

person Preet Sangha    schedule 13.08.2009
comment
Однако не проглатывайте исключение, если вы не знаете, что оно безвредно, или если вы не можете с ним справиться. -- Даже тогда ты не должен его глотать. ИМХО, для этого и существуют уровни логов. - person Robert Petermeier; 13.08.2009
comment
Я не согласен - если API предназначен для предоставления исключений, таких как MSMQ, тогда вы должны проглотить и принять это. Очевидно, вы должны быть уверены в типе и содержании исключения. - person Preet Sangha; 14.08.2009