mirror of https://github.com/Squidex/squidex.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
180 lines
7.1 KiB
180 lines
7.1 KiB
// ==========================================================================
|
|
// Squidex Headless CMS
|
|
// ==========================================================================
|
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
// All rights reserved. Licensed under the MIT license.
|
|
// ==========================================================================
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using CsvHelper;
|
|
using CsvHelper.Configuration;
|
|
using Squidex.Infrastructure;
|
|
using Squidex.Infrastructure.Log;
|
|
|
|
namespace Squidex.Domain.Apps.Entities.Apps
|
|
{
|
|
public sealed class DefaultAppLogStore : IAppLogStore
|
|
{
|
|
private const string FieldAuthClientId = "AuthClientId";
|
|
private const string FieldAuthUserId = "AuthUserId";
|
|
private const string FieldBytes = "Bytes";
|
|
private const string FieldCosts = "Costs";
|
|
private const string FieldCacheStatus = "CacheStatus";
|
|
private const string FieldCacheServer = "CacheServer";
|
|
private const string FieldCacheTTL = "CacheTTL";
|
|
private const string FieldCacheHits = "CacheHits";
|
|
private const string FieldRequestElapsedMs = "RequestElapsedMs";
|
|
private const string FieldRequestMethod = "RequestMethod";
|
|
private const string FieldRequestPath = "RequestPath";
|
|
private const string FieldStatusCode = "StatusCode";
|
|
private const string FieldTimestamp = "Timestamp";
|
|
|
|
private static readonly CsvConfiguration CsvConfiguration = new CsvConfiguration(CultureInfo.InvariantCulture)
|
|
{
|
|
Delimiter = "|",
|
|
LeaveOpen = true,
|
|
LineBreakInQuotedFieldIsBadData = false
|
|
};
|
|
|
|
private readonly IRequestLogStore requestLogStore;
|
|
|
|
public DefaultAppLogStore(IRequestLogStore requestLogStore)
|
|
{
|
|
this.requestLogStore = requestLogStore;
|
|
}
|
|
|
|
public Task LogAsync(DomainId appId, RequestLog request)
|
|
{
|
|
if (!requestLogStore.IsEnabled)
|
|
{
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
var storedRequest = new Request
|
|
{
|
|
Key = appId.ToString(),
|
|
Properties = new Dictionary<string, string>
|
|
{
|
|
[FieldCosts] = request.Costs.ToString(CultureInfo.InvariantCulture)
|
|
},
|
|
Timestamp = request.Timestamp
|
|
};
|
|
|
|
Append(storedRequest, FieldAuthClientId, request.UserClientId);
|
|
Append(storedRequest, FieldAuthUserId, request.UserId);
|
|
Append(storedRequest, FieldBytes, request.Bytes);
|
|
Append(storedRequest, FieldCacheHits, request.CacheHits);
|
|
Append(storedRequest, FieldCacheServer, request.CacheServer);
|
|
Append(storedRequest, FieldCacheStatus, request.CacheStatus);
|
|
Append(storedRequest, FieldCacheTTL, request.CacheTTL);
|
|
Append(storedRequest, FieldCosts, request.Costs);
|
|
Append(storedRequest, FieldRequestElapsedMs, request.ElapsedMs);
|
|
Append(storedRequest, FieldRequestMethod, request.RequestMethod);
|
|
Append(storedRequest, FieldRequestPath, request.RequestPath);
|
|
Append(storedRequest, FieldStatusCode, request.StatusCode);
|
|
|
|
return requestLogStore.LogAsync(storedRequest);
|
|
}
|
|
|
|
public async Task ReadLogAsync(DomainId appId, DateTime fromDate, DateTime toDate, Stream stream,
|
|
CancellationToken ct = default)
|
|
{
|
|
Guard.NotNull(appId, nameof(appId));
|
|
|
|
var writer = new StreamWriter(stream, Encoding.UTF8, 4096, true);
|
|
try
|
|
{
|
|
await using (var csv = new CsvWriter(writer, CsvConfiguration))
|
|
{
|
|
csv.WriteField(FieldTimestamp);
|
|
csv.WriteField(FieldRequestPath);
|
|
csv.WriteField(FieldRequestMethod);
|
|
csv.WriteField(FieldRequestElapsedMs);
|
|
csv.WriteField(FieldCosts);
|
|
csv.WriteField(FieldAuthClientId);
|
|
csv.WriteField(FieldAuthUserId);
|
|
csv.WriteField(FieldBytes);
|
|
csv.WriteField(FieldCacheHits);
|
|
csv.WriteField(FieldCacheServer);
|
|
csv.WriteField(FieldCacheStatus);
|
|
csv.WriteField(FieldCacheTTL);
|
|
csv.WriteField(FieldStatusCode);
|
|
|
|
await csv.NextRecordAsync();
|
|
|
|
await requestLogStore.QueryAllAsync(async request =>
|
|
{
|
|
csv.WriteField(request.Timestamp.ToString());
|
|
csv.WriteField(GetString(request, FieldRequestPath));
|
|
csv.WriteField(GetString(request, FieldRequestMethod));
|
|
csv.WriteField(GetDouble(request, FieldRequestElapsedMs));
|
|
csv.WriteField(GetDouble(request, FieldCosts));
|
|
csv.WriteField(GetString(request, FieldAuthClientId));
|
|
csv.WriteField(GetString(request, FieldAuthUserId));
|
|
csv.WriteField(GetLong(request, FieldBytes));
|
|
csv.WriteField(GetLong(request, FieldCacheHits));
|
|
csv.WriteField(GetString(request, FieldCacheServer));
|
|
csv.WriteField(GetString(request, FieldCacheStatus));
|
|
csv.WriteField(GetLong(request, FieldCacheTTL));
|
|
csv.WriteField(GetLong(request, FieldStatusCode));
|
|
|
|
await csv.NextRecordAsync();
|
|
}, appId.ToString(), fromDate, toDate, ct);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
await writer.FlushAsync();
|
|
}
|
|
}
|
|
|
|
private static void Append(Request request, string key, string? value)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(value))
|
|
{
|
|
request.Properties[key] = value;
|
|
}
|
|
}
|
|
|
|
private static void Append(Request request, string key, object? value)
|
|
{
|
|
if (value != null)
|
|
{
|
|
Append(request, key, Convert.ToString(value, CultureInfo.InvariantCulture));
|
|
}
|
|
}
|
|
|
|
private static string? GetString(Request request, string key)
|
|
{
|
|
return request.Properties.GetValueOrDefault(key, string.Empty);
|
|
}
|
|
|
|
private static double? GetDouble(Request request, string key)
|
|
{
|
|
if (request.Properties.TryGetValue(key, out var value) &&
|
|
double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static long? GetLong(Request request, string key)
|
|
{
|
|
if (request.Properties.TryGetValue(key, out var value) &&
|
|
long.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|