mirror of
https://github.com/bitwarden/server.git
synced 2025-05-05 03:32:21 -05:00
admin logs
This commit is contained in:
parent
f2ecea0a17
commit
d4b4a2b014
70
src/Admin/Controllers/LogsController.cs
Normal file
70
src/Admin/Controllers/LogsController.cs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.Admin.Models;
|
||||||
|
using Bit.Core;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Azure.Documents.Client;
|
||||||
|
using Microsoft.Azure.Documents.Linq;
|
||||||
|
|
||||||
|
namespace Bit.Admin.Controllers
|
||||||
|
{
|
||||||
|
[Authorize]
|
||||||
|
[SelfHosted(NotSelfHostedOnly = true)]
|
||||||
|
public class LogsController : Controller
|
||||||
|
{
|
||||||
|
private const string Database = "Diagnostics";
|
||||||
|
private const string Collection = "Logs";
|
||||||
|
|
||||||
|
private readonly GlobalSettings _globalSettings;
|
||||||
|
|
||||||
|
public LogsController(GlobalSettings globalSettings)
|
||||||
|
{
|
||||||
|
_globalSettings = globalSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> Index(string cursor = null, int count = 25)
|
||||||
|
{
|
||||||
|
var collectionLink = UriFactory.CreateDocumentCollectionUri(Database, Collection);
|
||||||
|
using(var client = new DocumentClient(new Uri(_globalSettings.DocumentDb.Uri),
|
||||||
|
_globalSettings.DocumentDb.Key))
|
||||||
|
{
|
||||||
|
var options = new FeedOptions
|
||||||
|
{
|
||||||
|
MaxItemCount = count,
|
||||||
|
RequestContinuation = cursor
|
||||||
|
};
|
||||||
|
|
||||||
|
var query = client.CreateDocumentQuery(collectionLink, options)
|
||||||
|
.OrderByDescending(l => l.Timestamp).AsDocumentQuery();
|
||||||
|
var response = await query.ExecuteNextAsync<LogModel>();
|
||||||
|
|
||||||
|
return View(new CursorPagedModel<LogModel>
|
||||||
|
{
|
||||||
|
Items = response.ToList(),
|
||||||
|
Count = count,
|
||||||
|
Cursor = cursor,
|
||||||
|
NextCursor = response.ResponseContinuation
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> View(string id)
|
||||||
|
{
|
||||||
|
using(var client = new DocumentClient(new Uri(_globalSettings.DocumentDb.Uri),
|
||||||
|
_globalSettings.DocumentDb.Key))
|
||||||
|
{
|
||||||
|
var uri = UriFactory.CreateDocumentUri(Database, Collection, id);
|
||||||
|
var response = await client.ReadDocumentAsync<LogModel>(uri);
|
||||||
|
if(response?.Document == null)
|
||||||
|
{
|
||||||
|
return RedirectToAction("Index");
|
||||||
|
}
|
||||||
|
|
||||||
|
return View(response.Document);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
src/Admin/Models/CursorPagedModel.cs
Normal file
12
src/Admin/Models/CursorPagedModel.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Bit.Admin.Models
|
||||||
|
{
|
||||||
|
public class CursorPagedModel<T>
|
||||||
|
{
|
||||||
|
public List<T> Items { get; set; }
|
||||||
|
public int Count { get; set; }
|
||||||
|
public string Cursor { get; set; }
|
||||||
|
public string NextCursor { get; set; }
|
||||||
|
}
|
||||||
|
}
|
28
src/Admin/Models/LogModel.cs
Normal file
28
src/Admin/Models/LogModel.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using Microsoft.Azure.Documents;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Serilog.Events;
|
||||||
|
|
||||||
|
namespace Bit.Admin.Models
|
||||||
|
{
|
||||||
|
public class LogModel : Resource
|
||||||
|
{
|
||||||
|
public long EventIdHash { get; set; }
|
||||||
|
public LogEventLevel Level { get; set; }
|
||||||
|
public string Message { get; set; }
|
||||||
|
public string MessageTruncated => Message.Length > 200 ? $"{Message.Substring(0, 200)}..." : Message;
|
||||||
|
public string MessageTemplate { get; set; }
|
||||||
|
public Error Exception { get; set; }
|
||||||
|
|
||||||
|
[JsonObject(MemberSerialization.OptIn)]
|
||||||
|
public class Error : Exception, ISerializable
|
||||||
|
{
|
||||||
|
[JsonProperty(PropertyName = "error")]
|
||||||
|
public string ErrorMessage { get; set; }
|
||||||
|
|
||||||
|
[JsonConstructor]
|
||||||
|
public Error() { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
61
src/Admin/Views/Logs/Index.cshtml
Normal file
61
src/Admin/Views/Logs/Index.cshtml
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
@model CursorPagedModel<LogModel>
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Logs";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h1>Logs</h1>
|
||||||
|
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="width: 50px;"> </th>
|
||||||
|
<th style="width: 200px;">Timestamp</th>
|
||||||
|
<th style="width: 100px;">Level</th>
|
||||||
|
<th>Message</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@if(!Model.Items.Any())
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td colspan="4">No results to list.</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@foreach(var log in Model.Items)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a asp-action="View" asp-route-id="@log.Id" title="View">
|
||||||
|
<i class="fa fa-file-text-o fa-lg"></i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>@log.Timestamp.ToString()</td>
|
||||||
|
<td>@log.Level</td>
|
||||||
|
<td>@log.MessageTruncated</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav>
|
||||||
|
<ul class="pagination">
|
||||||
|
@if(string.IsNullOrWhiteSpace(Model.NextCursor))
|
||||||
|
{
|
||||||
|
<li class="page-item disabled">
|
||||||
|
<a class="page-link" href="#" tabindex="-1">Next</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" asp-action="Index" asp-route-cursor="@Model.NextCursor"
|
||||||
|
asp-route-count="@Model.Count">Next</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
30
src/Admin/Views/Logs/View.cshtml
Normal file
30
src/Admin/Views/Logs/View.cshtml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
@model LogModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Log: " + Model.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
<h1>Log <small>@Model.Id</small></h1>
|
||||||
|
|
||||||
|
<h2>Information</h2>
|
||||||
|
<dl class="row">
|
||||||
|
<dt class="col-sm-4 col-lg-3">Id</dt>
|
||||||
|
<dd class="col-sm-8 col-lg-9"><code>@Model.Id</code></dd>
|
||||||
|
|
||||||
|
<dt class="col-sm-4 col-lg-3">Event Id Hash</dt>
|
||||||
|
<dd class="col-sm-8 col-lg-9">@Model.EventIdHash</dd>
|
||||||
|
|
||||||
|
<dt class="col-sm-4 col-lg-3">Timestamp</dt>
|
||||||
|
<dd class="col-sm-8 col-lg-9">@Model.Timestamp.ToString()</dd>
|
||||||
|
|
||||||
|
<dt class="col-sm-4 col-lg-3">Level</dt>
|
||||||
|
<dd class="col-sm-8 col-lg-9">@Model.Level</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h2>Message</h2>
|
||||||
|
<pre style="max-height: 500px;">@Model.Message</pre>
|
||||||
|
|
||||||
|
@if(Model.Exception != null)
|
||||||
|
{
|
||||||
|
<h2>Exception</h2>
|
||||||
|
<pre style="max-height: 500px;">@Model.Exception.ToString()</pre>
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
@inject SignInManager<IdentityUser> SignInManager
|
@inject SignInManager<IdentityUser> SignInManager
|
||||||
|
@inject Bit.Core.GlobalSettings GlobalSettings
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
@ -36,6 +37,12 @@
|
|||||||
<li class="nav-item" active-controller="Organizations">
|
<li class="nav-item" active-controller="Organizations">
|
||||||
<a class="nav-link" asp-controller="Organizations" asp-action="Index">Organizations</a>
|
<a class="nav-link" asp-controller="Organizations" asp-action="Index">Organizations</a>
|
||||||
</li>
|
</li>
|
||||||
|
@if(!GlobalSettings.SelfHosted)
|
||||||
|
{
|
||||||
|
<li class="nav-item" active-controller="Logs">
|
||||||
|
<a class="nav-link" asp-controller="Logs" asp-action="Index">Logs</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="https://help.bitwarden.com/hosting/" target="_blank">Docs</a>
|
<a class="nav-link" href="https://help.bitwarden.com/hosting/" target="_blank">Docs</a>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user