Для нормальной работы приложений в корпоративной среде нужен постоянный мониторинг. Особенно это актуально для работы сервисов, когда приложение живет само по себе и ошибки проявляются часто не сразу. На платформе .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; }
}
}
}
Комментарии
Отправить комментарий