Для нормальной работы приложений в корпоративной среде нужен постоянный мониторинг. Особенно это актуально для работы сервисов, когда приложение живет само по себе и ошибки проявляются часто не сразу. На платформе .NET мониторинг обеспечить достаточно легко путем включения в приложения логирования ошибок и извещения администратора, например по электронной почте.
Логирование
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text; namespace Poligon { /// <summary> /// Файл ведения логов в формате RAMO /// </summary> public class Logger { /// <summary> /// Ведение логов /// </summary> public Logger() { } /// <summary> /// Ведение логов /// </summary> /// <param name="source">Имя программы</param> /// <param name="logPath">Директория лог-файлов</param> /// <param name="eventLog">Запись в системный лог</param> public Logger(string source, string logPath, EventLog eventLog) { Source = source; Log = eventLog; Log.Source = Source; LogPath = logPath; try { if (!EventLog.SourceExists(Source)) EventLog.CreateEventSource(Source, "Application"); } catch { } } /// <summary> /// Запись в системный лог /// </summary> public EventLog Log { get; set; } /// <summary> /// Директория лог-файлов /// </summary> public string LogPath { get; set; } /// <summary> /// Имя сервиса /// </summary> public string Source { get; set; } /// <summary> /// Трассировка ошибок /// </summary> /// <param name="message"></param> public void TraceError(string message) { TraceMessage(message, EventLogEntryType.Error); } /// <summary> /// Трассировка ошибок аудита /// </summary> /// <param name="message"></param> public void TraceFailed(string message) { TraceMessage(message, EventLogEntryType.FailureAudit); } /// <summary> /// Трассировка информационных сообщений /// </summary> /// <param name="message"></param> public void TraceInformation(string message) { TraceMessage(message, EventLogEntryType.Information); } /// <summary> /// Трассировка успешного аудита /// </summary> /// <param name="message"></param> public void TraceSuccess(string message) { TraceMessage(message, EventLogEntryType.SuccessAudit); } /// <summary> /// Трассировка предупреждений /// </summary> /// <param name="message"></param> public void TraceWarning(string message) { TraceMessage(message, EventLogEntryType.Warning); } private void TraceMessage(string message, EventLogEntryType entryType) { try { Log.WriteEntry(message, entryType); } catch { } try { if ((entryType == EventLogEntryType.Error) || (entryType == EventLogEntryType.FailureAudit)) _errors.Add(message); var logPath = LogPath; var fileName = string.Format("{0}_{1}.log", Source, DateTime.Now.ToString("yyyyMMdd")); if (string.IsNullOrEmpty(logPath)) fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName); else { fileName = Path.Combine(logPath, fileName); if (!Directory.Exists(logPath)) Directory.CreateDirectory(logPath); } using (var fs = new FileStream(fileName, FileMode.Append, FileAccess.Write)) { string prefix; switch (entryType) { case EventLogEntryType.Error: prefix = "E"; break; case EventLogEntryType.FailureAudit: prefix = "F"; break; case EventLogEntryType.Information: prefix = "I"; break; case EventLogEntryType.SuccessAudit: prefix = "S"; break; case EventLogEntryType.Warning: prefix = "W"; break; default: prefix = "U"; break; } message = string.Format("{0}:{1}>{2}\r\n", prefix, DateTime.Now.ToString("HH:mm:ss"), message); var buffer = Encoding.Default.GetBytes(message); fs.Write(buffer, 0, buffer.Length); } } catch (Exception ex) { try { Log.WriteEntry(ex.Message, EventLogEntryType.Error); } catch { } } } private readonly List<string> _errors = new List<string>(); /// <summary> /// Список ошибок /// </summary> public IList<string> Errors { get { return _errors.AsReadOnly(); } } /// <summary> /// Сброс ошибок /// </summary> public void ResetErrors() { _errors.Clear(); } } }
Уведомление
using System; using System.Collections.Generic; using System.Net; using System.Net.Mail; using System.Text; namespace Poligon { /// <summary> /// Отправка сообщений /// Стандартная настройка SMTP в config-файле /// <system.net> /// <mailSettings> /// <smtp deliveryMethod="Network"> /// <network host="..." /// port="25" /// userName="..." /// password="..." /> /// </smtp> /// </mailSettings> /// </system.net> /// </summary> public class Mailer { /// <summary> /// Отправка сообщений /// </summary> public Mailer() { } /// <summary> /// Отправка сообщений /// </summary> /// <param name="from">Отправитель</param> /// <param name="recipients">Получатели</param> public Mailer(string from, string recipients) { From = from; Recipients = recipients; } /// <summary> /// Отправка сообщений /// </summary> /// <param name="from">Отправитель</param> /// <param name="recipients">Получатели</param> /// <param name="errorRecipient">Получатель ошибок</param> public Mailer(string from, string recipients, string errorRecipient) : this(from, recipients) { ErrorRecipient = errorRecipient; } /// <summary> /// Отправитель /// </summary> public string From { get; set; } /// <summary> /// Получатетели /// </summary> public string Recipients { get; set; } /// <summary> /// Получатель ошибок /// </summary> public string ErrorRecipient { get; set; } private SmtpClient _client; protected virtual SmtpClient Client { get { if (_client != null) return _client; _client = new SmtpClient(); return _client; } set { _client = value; } } /// <summary> /// Отправить сообщение /// </summary> /// <param name="subject">Тема</param> /// <param name="body">Текст письма</param> /// <param name="attachments">Вложения</param> public void SendMail(string subject, string body, string[] attachments) { var message = new MailMessage(From, Recipients, subject, body); foreach (var fileName in attachments) message.Attachments.Add(new Attachment(fileName)); Client.Send(message); } /// <summary> /// Отправить ошибки /// </summary> /// <param name="source">От кого</param> /// <param name="errors">Список ошибок</param> public void SendErrors(string source, IList<string> errors) { if (errors.Count == 0) return; var subject = string.Format(SubjectTemplate, source, DateTime.Now.ToString("dd.MM.yyyy hh:mm")); var body = new StringBuilder(ReportHeaderTemplate); body.AppendFormat(ReportNoteTemplate, subject) .Append(TableHeaderTemplate); foreach (var error in errors) body.AppendFormat(TableItemTemplate, error); body.Append(TableFooterTemplate) .AppendFormat(ReportFooterTemplate, errors.Count); Client.Send(From, ErrorRecipient, subject, body.ToString()); } #region ErrorReportTemplates private const string SubjectTemplate = "Отчет {0} ({1})"; private const string ReportHeaderTemplate = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">" + "<html>" + "<head>" + "<meta http-equiv=\"content-type\" content=\"text/html; charset=windows-1251\">" + "<style type=\"text/css\">" + "BODY { FONT-SIZE: small; FONT-FAMILY: Arial, Verdana, Helvetica, Tahoma, sans-serif}" + "TD { FONT-SIZE: x-small; BACKGROUND-COLOR: lightgrey}" + "TH { FONT-SIZE: x-small; COLOR: white; BACKGROUND-COLOR: silver;TEXT-ALIGN: left}" + "H1 { FONT-SIZE: small; FONT-WEIGHT: bold}" + "P { FONT-SIZE: x-small}" + "</style>" + "</head>" + "<body>"; private const string ReportNoteTemplate = "<h2>{0}</h2>"; private const string TableHeaderTemplate = "<table cellspacing=\"1\" cellpadding=\"2\" width=\"100%\" border=\"0\">" + "<tbody>" + "<tr>" + "<th>Мониторинг выполнения</th>" + "</tr>"; private const string TableItemTemplate = "<tr valign=top>" + "<td width=\"100%\">{0}</td>" + "</tr>"; private const string TableFooterTemplate = "</tbody>" + "</table>" + "<hr />"; private const string ReportFooterTemplate = "<p>Количество ошибок при выполнении: {0}</p>" + "<p>Данное сообщение сгенерированно и отправлено Вам программой, отвечать на него не нужно.</p>" + "</body>" + "</html>"; #endregion } /// <summary> /// Ручная настройка SMTP /// </summary> public class CustomMailer : Mailer { /// <summary> /// Отправка сообщений /// </summary> public CustomMailer() { } /// <summary> /// Отправка сообщений /// </summary> /// <param name="from">Отправитель</param> /// <param name="recipients">Получатели</param> public CustomMailer(string from, string recipients) : base(from, recipients) { } /// <summary> /// Отправка сообщений /// </summary> /// <param name="from">Отправитель</param> /// <param name="recipients">Получатели</param> /// <param name="errorRecipient">Получатель ошибок</param> public CustomMailer(string from, string recipients, string errorRecipient) : base(from, recipients, errorRecipient) { } /// <summary> /// SMTP-сервер /// </summary> public string Host { get; set; } /// <summary> /// Порт /// </summary> public int Port { get; set; } /// <summary> /// Домен /// </summary> public string Domain { get; set; } /// <summary> /// ПОльзователь /// </summary> public string UserName { get; set; } /// <summary> /// Пароль /// </summary> public string Password { get; set; } protected override SmtpClient Client { get { if (base.Client != null) return base.Client; base.Client = new SmtpClient(Host, Port) { Credentials = new NetworkCredential { Domain = Domain, Password = Password, UserName = UserName } }; return base.Client; } set { base.Client = value; } } } }
Комментарии
Отправить комментарий