mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-09-05 21:37:10 -04:00
Use stopwatch for more accurate measurements and reduce log spam
DateTime.Now is suitible for small timespans Replaced the needlessly complex and verbose logging for the httpserver
This commit is contained in:
parent
b3438559cc
commit
0f9006c81f
@ -550,16 +550,18 @@ namespace Emby.Server.Implementations
|
|||||||
|
|
||||||
var entryPoints = GetExports<IServerEntryPoint>();
|
var entryPoints = GetExports<IServerEntryPoint>();
|
||||||
|
|
||||||
var now = DateTime.UtcNow;
|
var stopWatch = new Stopwatch();
|
||||||
|
stopWatch.Start();
|
||||||
await Task.WhenAll(StartEntryPoints(entryPoints, true));
|
await Task.WhenAll(StartEntryPoints(entryPoints, true));
|
||||||
Logger.LogInformation("Executed all pre-startup entry points in {Elapsed:fff} ms", DateTime.Now - now);
|
Logger.LogInformation("Executed all pre-startup entry points in {Elapsed:fff} ms", stopWatch.Elapsed);
|
||||||
|
|
||||||
Logger.LogInformation("Core startup complete");
|
Logger.LogInformation("Core startup complete");
|
||||||
HttpServer.GlobalResponse = null;
|
HttpServer.GlobalResponse = null;
|
||||||
|
|
||||||
now = DateTime.UtcNow;
|
stopWatch.Restart();
|
||||||
await Task.WhenAll(StartEntryPoints(entryPoints, false));
|
await Task.WhenAll(StartEntryPoints(entryPoints, false));
|
||||||
Logger.LogInformation("Executed all post-startup entry points in {Elapsed:fff} ms", DateTime.Now - now);
|
Logger.LogInformation("Executed all post-startup entry points in {Elapsed:fff} ms", stopWatch.Elapsed);
|
||||||
|
stopWatch.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<Task> StartEntryPoints(IEnumerable<IServerEntryPoint> entryPoints, bool isBeforeStartup)
|
private IEnumerable<Task> StartEntryPoints(IEnumerable<IServerEntryPoint> entryPoints, bool isBeforeStartup)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -286,31 +287,6 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly string[] _skipLogExtensions =
|
|
||||||
{
|
|
||||||
".js",
|
|
||||||
".css",
|
|
||||||
".woff",
|
|
||||||
".woff2",
|
|
||||||
".ttf",
|
|
||||||
".html"
|
|
||||||
};
|
|
||||||
|
|
||||||
private bool EnableLogging(string url, string localPath)
|
|
||||||
{
|
|
||||||
var extension = GetExtension(url);
|
|
||||||
|
|
||||||
return ((string.IsNullOrEmpty(extension) || !_skipLogExtensions.Contains(extension))
|
|
||||||
&& (string.IsNullOrEmpty(localPath) || localPath.IndexOf("system/ping", StringComparison.OrdinalIgnoreCase) == -1));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetExtension(string url)
|
|
||||||
{
|
|
||||||
var parts = url.Split(new[] { '?' }, 2);
|
|
||||||
|
|
||||||
return Path.GetExtension(parts[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string RemoveQueryStringByKey(string url, string key)
|
public static string RemoveQueryStringByKey(string url, string key)
|
||||||
{
|
{
|
||||||
var uri = new Uri(url);
|
var uri = new Uri(url);
|
||||||
@ -448,10 +424,9 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected async Task RequestHandler(IHttpRequest httpReq, string urlString, string host, string localPath, CancellationToken cancellationToken)
|
protected async Task RequestHandler(IHttpRequest httpReq, string urlString, string host, string localPath, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var date = DateTime.Now;
|
var stopWatch = new Stopwatch();
|
||||||
|
stopWatch.Start();
|
||||||
var httpRes = httpReq.Response;
|
var httpRes = httpReq.Response;
|
||||||
bool enableLog = false;
|
|
||||||
bool logHeaders = false;
|
|
||||||
string urlToLog = null;
|
string urlToLog = null;
|
||||||
string remoteIp = httpReq.RemoteIp;
|
string remoteIp = httpReq.RemoteIp;
|
||||||
|
|
||||||
@ -498,18 +473,8 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var operationName = httpReq.OperationName;
|
urlToLog = GetUrlToLog(urlString);
|
||||||
|
Logger.LogDebug("HTTP {HttpMethod} {Url} UserAgent: {UserAgent} \nHeaders: {@Headers}", urlToLog, httpReq.UserAgent ?? string.Empty, httpReq.HttpMethod, httpReq.Headers);
|
||||||
enableLog = EnableLogging(urlString, localPath);
|
|
||||||
urlToLog = urlString;
|
|
||||||
logHeaders = enableLog && urlToLog.IndexOf("/videos/", StringComparison.OrdinalIgnoreCase) != -1;
|
|
||||||
|
|
||||||
if (enableLog)
|
|
||||||
{
|
|
||||||
urlToLog = GetUrlToLog(urlString);
|
|
||||||
|
|
||||||
LoggerUtils.LogRequest(_logger, urlToLog, httpReq.HttpMethod, httpReq.UserAgent, logHeaders ? httpReq.Headers : null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.Equals(localPath, "/emby/", StringComparison.OrdinalIgnoreCase) ||
|
if (string.Equals(localPath, "/emby/", StringComparison.OrdinalIgnoreCase) ||
|
||||||
string.Equals(localPath, "/mediabrowser/", StringComparison.OrdinalIgnoreCase))
|
string.Equals(localPath, "/mediabrowser/", StringComparison.OrdinalIgnoreCase))
|
||||||
@ -517,6 +482,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
RedirectToUrl(httpRes, DefaultRedirectPath);
|
RedirectToUrl(httpRes, DefaultRedirectPath);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.Equals(localPath, "/emby", StringComparison.OrdinalIgnoreCase) ||
|
if (string.Equals(localPath, "/emby", StringComparison.OrdinalIgnoreCase) ||
|
||||||
string.Equals(localPath, "/mediabrowser", StringComparison.OrdinalIgnoreCase))
|
string.Equals(localPath, "/mediabrowser", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
@ -562,16 +528,19 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
RedirectToUrl(httpRes, DefaultRedirectPath);
|
RedirectToUrl(httpRes, DefaultRedirectPath);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.Equals(localPath, "/web/", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(localPath, "/web/", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
RedirectToUrl(httpRes, "../" + DefaultRedirectPath);
|
RedirectToUrl(httpRes, "../" + DefaultRedirectPath);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
RedirectToUrl(httpRes, DefaultRedirectPath);
|
RedirectToUrl(httpRes, DefaultRedirectPath);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(localPath))
|
if (string.IsNullOrEmpty(localPath))
|
||||||
{
|
{
|
||||||
RedirectToUrl(httpRes, "/" + DefaultRedirectPath);
|
RedirectToUrl(httpRes, "/" + DefaultRedirectPath);
|
||||||
@ -607,33 +576,21 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
|
|
||||||
if (handler != null)
|
if (handler != null)
|
||||||
{
|
{
|
||||||
await handler.ProcessRequestAsync(this, httpReq, httpRes, Logger, operationName, cancellationToken).ConfigureAwait(false);
|
await handler.ProcessRequestAsync(this, httpReq, httpRes, Logger, httpReq.OperationName, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await ErrorHandler(new FileNotFoundException(), httpReq, false, false).ConfigureAwait(false);
|
await ErrorHandler(new FileNotFoundException(), httpReq, false, false).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException ex)
|
catch (Exception ex) when (ex is SocketException || ex is IOException || ex is OperationCanceledException)
|
||||||
{
|
{
|
||||||
await ErrorHandler(ex, httpReq, false, false).ConfigureAwait(false);
|
await ErrorHandler(ex, httpReq, false, false).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (IOException ex)
|
|
||||||
{
|
|
||||||
await ErrorHandler(ex, httpReq, false, false).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (SocketException ex)
|
|
||||||
{
|
|
||||||
await ErrorHandler(ex, httpReq, false, false).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (SecurityException ex)
|
catch (SecurityException ex)
|
||||||
{
|
{
|
||||||
await ErrorHandler(ex, httpReq, false, true).ConfigureAwait(false);
|
await ErrorHandler(ex, httpReq, false, true).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
var logException = !string.Equals(ex.GetType().Name, "SocketException", StringComparison.OrdinalIgnoreCase);
|
var logException = !string.Equals(ex.GetType().Name, "SocketException", StringComparison.OrdinalIgnoreCase);
|
||||||
@ -644,13 +601,15 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
{
|
{
|
||||||
httpRes.Close();
|
httpRes.Close();
|
||||||
|
|
||||||
if (enableLog)
|
stopWatch.Stop();
|
||||||
|
var elapsed = stopWatch.Elapsed;
|
||||||
|
if (elapsed.Milliseconds > 500)
|
||||||
{
|
{
|
||||||
var statusCode = httpRes.StatusCode;
|
_logger.LogWarning("HTTP Response {StatusCode} to {RemoteIp}. Time (slow): {Elapsed:ss.fff}. {Url}", httpRes.StatusCode, remoteIp, stopWatch.Elapsed, urlToLog);
|
||||||
|
}
|
||||||
var duration = DateTime.Now - date;
|
else
|
||||||
|
{
|
||||||
LoggerUtils.LogResponse(_logger, statusCode, urlToLog, remoteIp, duration, logHeaders ? httpRes.Headers : null);
|
_logger.LogDebug("HTTP Response {StatusCode} to {RemoteIp}. Time: {Elapsed:ss.fff}. {Url}", httpRes.StatusCode, remoteIp, stopWatch.Elapsed, urlToLog);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -663,12 +622,11 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
var pathParts = pathInfo.TrimStart('/').Split('/');
|
var pathParts = pathInfo.TrimStart('/').Split('/');
|
||||||
if (pathParts.Length == 0)
|
if (pathParts.Length == 0)
|
||||||
{
|
{
|
||||||
_logger.LogError("Path parts empty for PathInfo: {pathInfo}, Url: {RawUrl}", pathInfo, httpReq.RawUrl);
|
_logger.LogError("Path parts empty for PathInfo: {PathInfo}, Url: {RawUrl}", pathInfo, httpReq.RawUrl);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var restPath = ServiceHandler.FindMatchingRestPath(httpReq.HttpMethod, pathInfo, out string contentType);
|
var restPath = ServiceHandler.FindMatchingRestPath(httpReq.HttpMethod, pathInfo, out string contentType);
|
||||||
|
|
||||||
if (restPath != null)
|
if (restPath != null)
|
||||||
{
|
{
|
||||||
return new ServiceHandler
|
return new ServiceHandler
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Globalization;
|
|
||||||
using MediaBrowser.Model.Services;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.HttpServer
|
|
||||||
{
|
|
||||||
public static class LoggerUtils
|
|
||||||
{
|
|
||||||
public static void LogRequest(ILogger logger, string url, string method, string userAgent, QueryParamCollection headers)
|
|
||||||
{
|
|
||||||
if (headers == null)
|
|
||||||
{
|
|
||||||
logger.LogInformation("{0} {1}. UserAgent: {2}", "HTTP " + method, url, userAgent ?? string.Empty);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var headerText = string.Empty;
|
|
||||||
var index = 0;
|
|
||||||
|
|
||||||
foreach (var i in headers)
|
|
||||||
{
|
|
||||||
if (index > 0)
|
|
||||||
{
|
|
||||||
headerText += ", ";
|
|
||||||
}
|
|
||||||
|
|
||||||
headerText += i.Name + "=" + i.Value;
|
|
||||||
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.LogInformation("HTTP {0} {1}. {2}", method, url, headerText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Logs the response.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="logger">The logger.</param>
|
|
||||||
/// <param name="statusCode">The status code.</param>
|
|
||||||
/// <param name="url">The URL.</param>
|
|
||||||
/// <param name="endPoint">The end point.</param>
|
|
||||||
/// <param name="duration">The duration.</param>
|
|
||||||
public static void LogResponse(ILogger logger, int statusCode, string url, string endPoint, TimeSpan duration, QueryParamCollection headers)
|
|
||||||
{
|
|
||||||
var durationMs = duration.TotalMilliseconds;
|
|
||||||
var logSuffix = durationMs >= 1000 && durationMs < 60000 ? "ms (slow)" : "ms";
|
|
||||||
|
|
||||||
//var headerText = headers == null ? string.Empty : "Headers: " + string.Join(", ", headers.Where(i => i.Name.IndexOf("Access-", StringComparison.OrdinalIgnoreCase) == -1).Select(i => i.Name + "=" + i.Value).ToArray());
|
|
||||||
var headerText = string.Empty;
|
|
||||||
logger.LogInformation("HTTP Response {0} to {1}. Time: {2}{3}. {4} {5}", statusCode, endPoint, Convert.ToInt32(durationMs).ToString(CultureInfo.InvariantCulture), logSuffix, url, headerText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -44,7 +44,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
|
|||||||
|
|
||||||
var dueTime = triggerDate - now;
|
var dueTime = triggerDate - now;
|
||||||
|
|
||||||
logger.LogInformation("Daily trigger for {0} set to fire at {1}, which is {2} minutes from now.", taskName, triggerDate.ToString(), dueTime.TotalMinutes.ToString(CultureInfo.InvariantCulture));
|
logger.LogInformation("Daily trigger for {0} set to fire at {1}, which is {2} minutes from now.", taskName, triggerDate, dueTime);
|
||||||
|
|
||||||
Timer = new Timer(state => OnTriggered(), null, dueTime, TimeSpan.FromMilliseconds(-1));
|
Timer = new Timer(state => OnTriggered(), null, dueTime, TimeSpan.FromMilliseconds(-1));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user