private void RenderPageNavigators(HtmlTextWriter w) { w.RenderBeginTag(HtmlTextWriterTag.P); int firstErrorNumber = _pageIndex * _pageSize + 1; int lastErrorNumber = firstErrorNumber + _errorEntryList.Count - 1; int totalPages = (int)Math.Ceiling((double)_totalCount / _pageSize); ErrorLogEntry errorEntry = (ErrorLogEntry)_errorEntryList[0]; w.Write(@"<div id=""errorcount"">{0} Errors; last {1}</div>", _totalCount, errorEntry.Error.Time.ToRelativeTime()); if (_totalCount > _pageSize) { w.Write(@"<div id=""pagination"">"); for (int i = 0; i < (_totalCount / _pageSize) + 1; i++) { if (i == _pageIndex) { w.Write(@"<span id=""page-num-current"">"); } else { w.Write(@"<span id=""page-num"">"); } RenderLinkToPage(w, (i + 1).ToString(), i); w.Write(@"</span>"); } w.Write(@"</div>"); } w.RenderEndTag(); // </p> w.WriteLine(); }
/// <summary> /// Returns a page of errors from the application memory in descending order of logged time. /// </summary> public override int GetErrors(int pageIndex, int pageSize, IList errorEntryList) { if (pageIndex < 0) { throw new ArgumentOutOfRangeException("pageIndex"); } if (pageSize < 0) { throw new ArgumentOutOfRangeException("pageSite"); } // // To minimize the time for which we hold the lock, we'll first // grab just references to the entries we need to return. Later, // we'll make copies and return those to the caller. Since Error // is mutable, we don't want to return direct references to our // internal versions since someone could change their state. // ErrorLogEntry[] selectedEntries; int totalCount; _lock.AcquireReaderLock(Timeout.Infinite); try { if (_entries == null) { return(0); } int lastIndex = Math.Max(0, _entries.Count - (pageIndex * pageSize)) - 1; selectedEntries = new ErrorLogEntry[lastIndex + 1]; int sourceIndex = lastIndex; int targetIndex = 0; while (sourceIndex >= 0) { selectedEntries[targetIndex++] = _entries[sourceIndex--]; } totalCount = _entries.Count; } finally { _lock.ReleaseReaderLock(); } // Return copies of fetched entries. If the Error class would // be immutable then this step wouldn't be necessary. foreach (ErrorLogEntry entry in selectedEntries) { Error error = (Error)((ICloneable)entry.Error).Clone(); errorEntryList.Add(new ErrorLogEntry(this, entry.Id, error)); } return(totalCount); }
public void Add(Guid id, ErrorLogEntry entry) { if (this.Count == _size) { BaseRemoveAt(0); } BaseAdd(entry.Id, entry); }
protected override void OnLoad(EventArgs e) { string errorId = this.Request.QueryString["id"] ?? ""; if (errorId.Length == 0) return; _errorEntry = this.ErrorLog.GetError(errorId); if (_errorEntry == null) return; this.Title = string.Format("Error: {0} [{1}]", _errorEntry.Error.Type, _errorEntry.Id); base.OnLoad(e); }
public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/xml"; // Get the last set of errors for this application. const int pageSize = 15; ArrayList errorEntryList = new ArrayList(pageSize); ErrorLog.Default.GetErrors(0, pageSize, errorEntryList); // We'll be emitting RSS vesion 0.91. RichSiteSummary rss = new RichSiteSummary(); rss.version = "0.91"; // Set up the RSS channel. Channel channel = new Channel(); channel.title = "Error log of " + ErrorLog.Default.ApplicationName + " on " + Environment.MachineName; channel.description = "Log of recent errors"; channel.language = "en"; channel.link = context.Request.Url.GetLeftPart(UriPartial.Authority) + context.Request.ServerVariables["URL"]; rss.channel = channel; // For each error, build a simple channel item. // Only the title, description, link and pubDate fields are populated. channel.item = new Item[errorEntryList.Count]; for (int index = 0; index < errorEntryList.Count; index++) { ErrorLogEntry errorEntry = (ErrorLogEntry)errorEntryList[index]; Error error = errorEntry.Error; Item item = new Item(); item.title = error.Message; item.description = "An error of type " + error.Type + " occurred. " + error.Message; item.link = channel.link + "/detail?id=" + errorEntry.Id; item.pubDate = error.Time.ToUniversalTime().ToString("r"); channel.item[index] = item; } XmlSerializer serializer = new XmlSerializer(typeof(RichSiteSummary)); serializer.Serialize(context.Response.Output, rss); }
protected override void OnLoad(EventArgs e) { string errorId = this.Request.QueryString["id"] ?? ""; if (errorId.Length == 0) { return; } _errorEntry = this.ErrorLog.GetError(errorId); if (_errorEntry == null) { return; } this.Title = string.Format("Error: {0} [{1}]", _errorEntry.Error.Type, _errorEntry.Id); base.OnLoad(e); }
protected override void Render(HtmlTextWriter w) { string errorId = this.Request.QueryString["id"] ?? ""; if (errorId.Length == 0) { return; } ErrorLogEntry errorEntry = this.ErrorLog.GetError(errorId); if (errorEntry == null) { return; } // If we have a host (ASP.NET) formatted HTML message for the error then just stream it out as our response. if (errorEntry.Error.WebHostHtmlMessage.Length != 0) { w.Write(errorEntry.Error.WebHostHtmlMessage); } }
/// <summary> /// Logs an error to the application memory. /// </summary> /// <remarks> /// If the log is full then the oldest error entry is removed. /// </remarks> public override void Log(Error error) { if (error == null) throw new ArgumentNullException("error"); // Make a copy of the error to log since the source is mutable. error = (Error)((ICloneable)error).Clone(); error.ApplicationName = this.ApplicationName; Guid newId = Guid.NewGuid(); ErrorLogEntry entry = new ErrorLogEntry(this, newId.ToString(), error); _lock.AcquireWriterLock(Timeout.Infinite); try { if (_entries == null) { _entries = new EntryCollection(_size); } _entries.Add(newId, entry); } finally { _lock.ReleaseWriterLock(); } }
/// <summary> /// Returns a page of errors from the application memory in descending order of logged time. /// </summary> public override int GetErrors(int pageIndex, int pageSize, IList errorEntryList) { if (pageIndex < 0) throw new ArgumentOutOfRangeException("pageIndex"); if (pageSize < 0) throw new ArgumentOutOfRangeException("pageSite"); // // To minimize the time for which we hold the lock, we'll first // grab just references to the entries we need to return. Later, // we'll make copies and return those to the caller. Since Error // is mutable, we don't want to return direct references to our // internal versions since someone could change their state. // ErrorLogEntry[] selectedEntries; int totalCount; _lock.AcquireReaderLock(Timeout.Infinite); try { if (_entries == null) { return 0; } int lastIndex = Math.Max(0, _entries.Count - (pageIndex * pageSize)) - 1; selectedEntries = new ErrorLogEntry[lastIndex + 1]; int sourceIndex = lastIndex; int targetIndex = 0; while (sourceIndex >= 0) { selectedEntries[targetIndex++] = _entries[sourceIndex--]; } totalCount = _entries.Count; } finally { _lock.ReleaseReaderLock(); } // Return copies of fetched entries. If the Error class would // be immutable then this step wouldn't be necessary. foreach (ErrorLogEntry entry in selectedEntries) { Error error = (Error)((ICloneable)entry.Error).Clone(); errorEntryList.Add(new ErrorLogEntry(this, entry.Id, error)); } return totalCount; }
private void RenderErrors(HtmlTextWriter w) { // Create a table to display error information in each row. Table table = new Table(); table.ID = "ErrorLog"; table.CellSpacing = 0; TableRow headRow = new TableRow(); headRow.Cells.Add(FormatCell(new TableHeaderCell(), "", "type-col")); // actions, e.g. delete, protect headRow.Cells.Add(FormatCell(new TableHeaderCell(), "Type", "type-col")); headRow.Cells.Add(FormatCell(new TableHeaderCell(), "Error", "error-col")); headRow.Cells.Add(FormatCell(new TableHeaderCell(), "Url", "url-col")); headRow.Cells.Add(FormatCell(new TableHeaderCell(), "Remote IP", "user-col")); headRow.Cells.Add(FormatCell(new TableHeaderCell(), "Time", "user-col")); table.Rows.Add(headRow); for (int errorIndex = 0; errorIndex < _errorEntryList.Count; errorIndex++) { ErrorLogEntry errorEntry = (ErrorLogEntry)_errorEntryList[errorIndex]; Error error = errorEntry.Error; TableRow bodyRow = new TableRow(); bodyRow.CssClass = errorIndex % 2 == 0 ? "even-row" : "odd-row"; TableCell actionCell = new TableCell(); bodyRow.Cells.Add(actionCell); HyperLink deleteLink = new HyperLink(); deleteLink.NavigateUrl = this.Request.Path + (Request.Path.EndsWith("/") ? "" : "/") + "delete?id=" + errorEntry.Id; deleteLink.CssClass = "delete-link"; deleteLink.Text = " X "; deleteLink.ToolTip = "Delete this error"; actionCell.Controls.Add(deleteLink); if (!error.IsProtected) { HyperLink protectLink = new HyperLink(); protectLink.NavigateUrl = this.Request.Path + (Request.Path.EndsWith("/") ? "" : "/") + "protect?id=" + errorEntry.Id; protectLink.CssClass = "protect-link"; protectLink.Text = " P "; protectLink.ToolTip = "Protect this error from automatic deletion"; actionCell.Controls.Add(protectLink); } bodyRow.Cells.Add(FormatCell(new TableCell(), GetSimpleErrorType(error), "type-col", error.Type, true)); TableCell messageCell = new TableCell(); messageCell.CssClass = "error-col"; HyperLink detailsLink = new HyperLink(); detailsLink.NavigateUrl = this.Request.Path + (Request.Path.EndsWith("/") ? "" : "/") + "detail?id=" + errorEntry.Id; detailsLink.CssClass = "details-link"; detailsLink.Text = this.Server.HtmlEncode(error.Message); if (error.DuplicateCount.HasValue) { detailsLink.Text += string.Format(@" <span class='duplicate-count' title='number of similar errors occurring close to this error'>({0})</span>", error.DuplicateCount); } messageCell.Controls.Add(detailsLink); messageCell.Controls.Add(new LiteralControl(" ")); bodyRow.Cells.Add(messageCell); string url = error.ServerVariables["URL"] ?? ""; string title = url; if (title.Length > 40) { title = title.TruncateWithEllipsis(40); } bodyRow.Cells.Add(FormatCellRaw(new TableCell(), String.Format(@"<a href=""{0}"">{1}</a>", url, title), "user-col")); bodyRow.Cells.Add(FormatCell(new TableCell(), GetRemoteIP(error.ServerVariables), "user-col ip-address")); bodyRow.Cells.Add(FormatCellRaw(new TableCell(), error.Time.ToRelativeTimeSpan(), "user-col")); table.Rows.Add(bodyRow); } table.RenderControl(w); }