Основы Silverlight Logging и/или лучшие практики
Теперь Silverlight 2 наконец отправлен. Мне интересно, собрал ли кто-нибудь какие-либо фреймворки для ведения журнала, возможно, что-то вроде регистрация в корпоративной библиотеке или log4net? Мне интересно то, что может выполнять трассировку на стороне клиента, а также протоколировать сообщения на сервер.
Пока единственный найденный мной проект Clog на CodeProject. Кто-нибудь использовал это? Каковы были ваши мысли?
Ответы
Ответ 1
Я собираюсь вникать в нечто подобное себе для продукта, который мы написали. Я рассматриваю возможность использования PostSharp для Silverlight для добавления журнала на стороне клиента в качестве аспекта.
Я использовал проект NLog с большим успехом раньше, чем в полной .NET Framework и Compact Framework, поэтому я, скорее всего, возьму существующий код инфраструктуры и добавлю несколько целей ведения журнала:
- Стандартная целевая система System.Diagnostics для включения захвата с использованием DebugView и т.д.
- Асинхронная цель веб-сервиса, аналогичная таковой в NLog.
- Целевая изолированная память с отложенной передачей на семантику сервера.
Я кратко посмотрел на Clog, и, похоже, он страдает от одного серьезного недостатка - он не может зарегистрировать сбой подключения. Поэтому, предполагая, что ваш веб-сервер постоянно работает в сети, да, он будет работать, но когда проблемы возникают в восходящем или на самом сервере, данные протоколирования теряются и могут даже сбой вашего приложения.
Ответ 2
Если вы готовы забрать свой шлем космонавта на минуту, ниже представлен легкий журнал, который я написал для Silverlight, для ведения журнала на стороне клиента (для использования в основном с операциями WCF, но может быть для любых ошибок).
Первоначально он использовался в Monotouch для iPhone-приложений и был адаптирован для IsolateStorage
. Вы можете использовать метод Read
для отображения в текстовом поле, если это необходимо. Протестировано в SL4.
/// <summary>
/// A lightweight logging class for Silverlight.
/// </summary>
public class Log
{
/// <summary>
/// The log file to write to. Defaults to "dd-mm-yyyy.log" e.g. "13-01-2010.log"
/// </summary>
public static string LogFilename { get; set; }
/// <summary>
/// Whether to appendthe calling method to the start of the log line.
/// </summary>
public static bool UseStackFrame { get; set; }
static Log()
{
LogFilename = string.Format("{0}.log", DateTime.Today.ToString("dd-MM-yyyy"));
UseStackFrame = false;
}
/// <summary>
/// Reads the entire log file, or returns an empty string if it doesn't exist yet.
/// </summary>
/// <returns></returns>
public static string ReadLog()
{
string result = "";
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForSite();
if (storage.FileExists(LogFilename))
{
try
{
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(LogFilename,FileMode.OpenOrCreate,storage))
{
using (StreamReader reader = new StreamReader(stream))
{
result = reader.ReadToEnd();
}
}
}
catch (IOException)
{
// Ignore
}
}
return result;
}
/// <summary>
/// Writes information (not errors) to the log file.
/// </summary>
/// <param name="format">A format string</param>
/// <param name="args">Any arguments for the format string.</param>
public static void Info(string format, params object[] args)
{
WriteLine(LoggingLevel.Info, format, args);
}
/// <summary>
/// Writes a warning (non critical error) to the log file
/// </summary>
/// <param name="format">A format string</param>
/// <param name="args">Any arguments for the format string.</param>
public static void Warn(string format, params object[] args)
{
WriteLine(LoggingLevel.Warn, format, args);
}
/// <summary>
/// Writes a critical or fatal error to the log file.
/// </summary>
/// <param name="format">A format string</param>
/// <param name="args">Any arguments for the format string.</param>
public static void Fatal(string format, params object[] args)
{
WriteLine(LoggingLevel.Fatal, format, args);
}
/// <summary>
/// Writes the args to the default logging output using the format provided.
/// </summary>
public static void WriteLine(LoggingLevel level, string format, params object[] args)
{
string message = string.Format(format, args);
// Optionally show the calling method
if (UseStackFrame)
{
var name = new StackFrame(2, false).GetMethod().Name;
string prefix = string.Format("[{0} - {1}] ", level, name);
message = string.Format(prefix + format, args);
}
Debug.WriteLine(message);
WriteToFile(message);
}
/// <summary>
/// Writes a line to the current log file.
/// </summary>
/// <param name="message"></param>
private static void WriteToFile(string message)
{
try
{
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForSite();
bool b = storage.FileExists(LogFilename);
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(LogFilename,FileMode.Append,storage))
{
using (StreamWriter writer = new StreamWriter(stream))
{
writer.WriteLine("[{0}] {1}", DateTime.UtcNow.ToString(), message);
}
}
}
catch (IOException)
{
// throw new Catch22Exception();
}
}
}
/// <summary>
/// The type of error to log.
/// </summary>
public enum LoggingLevel
{
/// <summary>
/// A message containing information only.
/// </summary>
Info,
/// <summary>
/// A non-critical warning error message.
/// </summary>
Warn,
/// <summary>
/// A fatal error message.
/// </summary>
Fatal
}
Ответ 3
если вы просто хотите выводить отладочные сообщения на консоль. Вы можете использовать механизм браузера console.log. Я закодировал для этого метод расширения. Вы можете найти на мой блог.
// http://kodierer.blogspot.com.es/2009/05/silverlight-logging-extension-method.html
public static string Log(string message)
{
var msgLog = "";
try
{
HtmlWindow window = HtmlPage.Window;
//only log if a console is available
var isConsoleAvailable = (bool)window.Eval("typeof(console) != 'undefined' && typeof(console.log) != 'undefined'");
if (!isConsoleAvailable) return "isConsoleAvailable " + isConsoleAvailable;
var createLogFunction = (bool)window.Eval("typeof(ssplog) == 'undefined'");
if (createLogFunction)
{
// Load the logging function into global scope:
string logFunction = @"function ssplog(msg) { console.log(msg); }";
string code = string.Format(@"if(window.execScript) {{ window.execScript('{0}'); }} else {{ eval.call(null, '{0}'); }}", logFunction);
window.Eval(code);
}
// Prepare the message
DateTime dateTime = DateTime.Now;
string output = string.Format("{0} - {1} - {2}", dateTime.ToString("u"), "DEBUG", message);
// Invoke the logging function:
var logger = window.Eval("ssplog") as ScriptObject;
logger.InvokeSelf(output);
}
catch (Exception ex)
{
msgLog = "Error Log " + ex.Message;
}
return msgLog;
}
Ответ 4
Вы также можете использовать этот: http://silverlightlogging.codeplex.com/
Ответ 5
Я закончил тем, что создал новую систему ведения журнала с нуля, которая устраняет этот недостаток. Я создал локальную очередь, которая получит сообщения журнала/трассировки, а затем сделает фильтр и отправит их на сервер. Затем очередь будет поддерживаться изолированным хранилищем, поэтому, даже если клиент окончательно отключится для этого сеанса, сообщения будут отправляться, когда он будет снова в сети.
Ответ 6
Я использую окна JavaScript и делаю его сценарием в Silverlight. Для "производства" я могу отключить это окно, но все же сохранить строки журнала в памяти, а затем, если что-то пойдет не так, отправьте это на сервер. Таким образом, я получаю лучшее из обоих миров. Простой, ведение журнала в реальном времени на клиенте для отладки и журналов для удаленных посмертных ситуаций, с которыми могут столкнуться пользователи.