Browse Source

OpenTelemetry support. (#747)

pull/748/head
Sebastian Stehle 4 years ago
committed by GitHub
parent
commit
fd4b2ba5d0
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 100
      backend/Squidex.ruleset
  2. 37
      backend/extensions/Squidex.Extensions/APM/ApplicationInsights/ApplicationInsightsPlugin.cs
  3. 36
      backend/extensions/Squidex.Extensions/APM/ApplicationInsights/RoleNameTelemetryInitializer.cs
  4. 82
      backend/extensions/Squidex.Extensions/APM/Datadog/DatadogPlugin.cs
  5. 35
      backend/extensions/Squidex.Extensions/APM/Otlp/OtlpPlugin.cs
  6. 39
      backend/extensions/Squidex.Extensions/APM/Stackdriver/StackdriverExceptionHandler.cs
  7. 37
      backend/extensions/Squidex.Extensions/APM/Stackdriver/StackdriverPlugin.cs
  8. 43
      backend/extensions/Squidex.Extensions/APM/Stackdriver/StackdriverSeverityLogAppender.cs
  9. 10
      backend/extensions/Squidex.Extensions/Squidex.Extensions.csproj
  10. 2
      backend/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj
  11. 7
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository.cs
  12. 11
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository_SnapshotStore.cs
  13. 15
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs
  14. 11
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository_SnapshotStore.cs
  15. 15
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollection.cs
  16. 11
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository_SnapshotStore.cs
  17. 2
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Squidex.Domain.Apps.Entities.MongoDb.csproj
  18. 19
      backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsIndex.cs
  19. 3
      backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetEnricher.cs
  20. 3
      backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetLoader.cs
  21. 3
      backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetQueryParser.cs
  22. 19
      backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetQueryService.cs
  23. 16
      backend/src/Squidex.Domain.Apps.Entities/Backup/RestoreGrain.cs
  24. 5
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentEnricher.cs
  25. 3
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentLoader.cs
  26. 3
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryParser.cs
  27. 9
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryService.cs
  28. 5
      backend/src/Squidex.Domain.Apps.Entities/Rules/Indexes/RulesIndex.cs
  29. 3
      backend/src/Squidex.Domain.Apps.Entities/Rules/Queries/RuleEnricher.cs
  30. 11
      backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasIndex.cs
  31. 2
      backend/src/Squidex.Domain.Apps.Entities/Squidex.Domain.Apps.Entities.csproj
  32. 2
      backend/src/Squidex.Domain.Users.MongoDb/Squidex.Domain.Users.MongoDb.csproj
  33. 2
      backend/src/Squidex.Domain.Users/Squidex.Domain.Users.csproj
  34. 7
      backend/src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore_Reader.cs
  35. 5
      backend/src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore_Writer.cs
  36. 4
      backend/src/Squidex.Infrastructure.MongoDb/Squidex.Infrastructure.MongoDb.csproj
  37. 11
      backend/src/Squidex.Infrastructure.MongoDb/States/MongoSnapshotStore.cs
  38. 5
      backend/src/Squidex.Infrastructure/Orleans/J{T}.cs
  39. 10
      backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj
  40. 33
      backend/src/Squidex.Infrastructure/Telemetry.cs
  41. 4
      backend/src/Squidex.Web/ETagExtensions.cs
  42. 3
      backend/src/Squidex.Web/Pipeline/ApiCostsFilter.cs
  43. 2
      backend/src/Squidex.Web/Pipeline/CachingManager.cs
  44. 6
      backend/src/Squidex.Web/Pipeline/MeasureResultFilter.cs
  45. 2
      backend/src/Squidex.Web/Pipeline/RequestLogOptions.cs
  46. 37
      backend/src/Squidex.Web/Pipeline/RequestLogPerformanceMiddleware.cs
  47. 11
      backend/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs
  48. 1
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs
  49. 8
      backend/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs
  50. 32
      backend/src/Squidex/Config/Domain/TelemetryServices.cs
  51. 24
      backend/src/Squidex/Squidex.csproj
  52. 1
      backend/src/Squidex/Startup.cs
  53. 609
      backend/src/Squidex/appsettings.json

100
backend/Squidex.ruleset

@ -1,100 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="Squidex Rules" Description="Squidex Rules" ToolsVersion="14.0">
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
<Rule Id="SA1002" Action="Error" />
<Rule Id="SA1003" Action="Error" />
<Rule Id="SA1008" Action="None" />
<Rule Id="SA1009" Action="None" />
<Rule Id="SA1012" Action="Error" />
<Rule Id="SA1013" Action="Error" />
<Rule Id="SA1025" Action="Error" />
<Rule Id="SA1026" Action="Error" />
<Rule Id="SA1028" Action="Error" />
<Rule Id="SA1000" Action="Error" />
<Rule Id="SA1001" Action="Error" />
<Rule Id="SA1101" Action="None" />
<Rule Id="SA1004" Action="Error" />
<Rule Id="SA1107" Action="None" />
<Rule Id="SA1010" Action="Error" />
<Rule Id="SA1111" Action="None" />
<Rule Id="SA1116" Action="None" />
<Rule Id="SA1117" Action="None" />
<Rule Id="SA1118" Action="None" />
<Rule Id="SA1119" Action="None" />
<Rule Id="SA1122" Action="Error" />
<Rule Id="SA1127" Action="None" />
<Rule Id="SA1128" Action="Error" />
<Rule Id="SA1129" Action="Error" />
<Rule Id="SA1200" Action="None" />
<Rule Id="SA1201" Action="None" />
<Rule Id="SA1202" Action="None" />
<Rule Id="SA1203" Action="Error" />
<Rule Id="SA1204" Action="None" />
<Rule Id="SA1208" Action="Error" />
<Rule Id="SA1210" Action="Error" />
<Rule Id="SA1214" Action="Error" />
<Rule Id="SA1306" Action="Error" />
<Rule Id="SA1311" Action="Error" />
<Rule Id="SA1400" Action="Error" />
<Rule Id="SA1401" Action="Error" />
<Rule Id="SA1402" Action="None" />
<Rule Id="SA1407" Action="Error" />
<Rule Id="SA1408" Action="None" />
<Rule Id="SA1502" Action="Error" />
<Rule Id="SA1504" Action="Error" />
<Rule Id="SA1505" Action="Error" />
<Rule Id="SA1507" Action="Error" />
<Rule Id="SA1508" Action="Error" />
<Rule Id="SA1518" Action="Error" />
<Rule Id="SA1512" Action="None" />
<Rule Id="SA1513" Action="Error" />
<Rule Id="SA1515" Action="None" />
<Rule Id="SA1516" Action="None" />
<Rule Id="SA1600" Action="None" />
<Rule Id="SA1612" Action="None" />
<Rule Id="SA1615" Action="None" />
<Rule Id="SA1623" Action="None" />
<Rule Id="SA1633" Action="Error" />
<Rule Id="SA1649" Action="Error" />
<Rule Id="SA1634" Action="None" />
<Rule Id="SA1635" Action="None" />
<Rule Id="SA1652" Action="None" />
<Rule Id="SA1404" Action="None" />
<Rule Id="SA1601" Action="None" />
<Rule Id="SA1413" Action="None" />
<Rule Id="SA0001" Action="None" />
<Rule Id="SA1602" Action="None" />
</Rules>
<Rules AnalyzerId="RefactoringEssentials" RuleNamespace="RefactoringEssentials">
<Rule Id="RECS0061" Action="Error" />
<Rule Id="RECS0017" Action="Error" />
<Rule Id="RECS0060" Action="Error" />
<Rule Id="RECS0062" Action="Error" />
<Rule Id="RECS0063" Action="Error" />
<Rule Id="RECS0064" Action="Error" />
<Rule Id="RECS0133" Action="Error" />
<Rule Id="REVB0145" Action="None" />
<Rule Id="RECS0002" Action="Error" />
<Rule Id="RECS0154" Action="None" />
<Rule Id="RECS0146" Action="Error" />
<Rule Id="RECS0026" Action="Error" />
<Rule Id="RECS0145" Action="None" />
<Rule Id="RECS0129" Action="None" />
<Rule Id="RECS0070" Action="None" />
</Rules>
<Rules AnalyzerId="Roslyn.Core" RuleNamespace="Roslyn.Core">
<Rule Id="AD0001" Action="None" />
</Rules>
<Rules AnalyzerId="Roslyn.Core" RuleNamespace="Microsoft.CodeAnalysis.Diagnostics">
<Rule Id="IDE0070" Action="None" />
<Rule Id="IDE0032" Action="None" />
<Rule Id="IDE0042" Action="None" />
<Rule Id="IDE0090" Action="None" />
</Rules>
<Rules AnalyzerId="Microsoft.AspNetCore.Mvc.Api.Analyzers" RuleNamespace="Microsoft.AspNetCore.Mvc.Api.Analyzers">
<Rule Id="API1000" Action="Error" />
<Rule Id="API1001" Action="Error" />
<Rule Id="API1002" Action="Error" />
<Rule Id="API1003" Action="Error" />
</Rules>
</RuleSet>

37
backend/extensions/Squidex.Extensions/APM/ApplicationInsights/ApplicationInsightsPlugin.cs

@ -5,46 +5,27 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.DataContracts;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Azure.Monitor.OpenTelemetry.Exporter;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Infrastructure.Plugins;
using Squidex.Log;
namespace Squidex.Extensions.APM.ApplicationInsights
{
public sealed class ApplicationInsightsPlugin : IPlugin, IStartupFilter
public sealed class ApplicationInsightsPlugin : IPlugin
{
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
{
return builder =>
public void ConfigureServices(IServiceCollection services, IConfiguration config)
{
var client = builder.ApplicationServices.GetRequiredService<TelemetryClient>();
Profiler.SpanStarted += session =>
services.AddOpenTelemetryTracing(builder =>
{
session.Listen(client.StartOperation<RequestTelemetry>(session.Key));
};
next(builder);
};
}
public void ConfigureServices(IServiceCollection services, IConfiguration config)
if (config.GetValue<bool>("logging:applicationInsights:enabled"))
{
var isEnabled = config.GetValue<bool>("logging:applicationInsights");
if (isEnabled)
builder.AddAzureMonitorTraceExporter(options =>
{
services.AddSingleton<IStartupFilter>(this);
services.AddApplicationInsightsTelemetry();
services.AddSingleton<ITelemetryInitializer, RoleNameTelemetryInitializer>();
config.GetSection("logging:applicationInsights").Bind(options);
});
}
});
}
}
}

36
backend/extensions/Squidex.Extensions/APM/ApplicationInsights/RoleNameTelemetryInitializer.cs

@ -1,36 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.Extensions.Configuration;
namespace Squidex.Extensions.APM.ApplicationInsights
{
public sealed class RoleNameTelemetryInitializer : ITelemetryInitializer
{
private readonly string roleName;
public RoleNameTelemetryInitializer(IConfiguration configuration)
{
roleName = configuration.GetValue<string>("logging:roleName");
if (string.IsNullOrWhiteSpace(roleName))
{
roleName = "Squidex";
}
}
public void Initialize(ITelemetry telemetry)
{
if (string.IsNullOrEmpty(telemetry.Context.Cloud.RoleName))
{
telemetry.Context.Cloud.RoleName = roleName;
}
}
}
}

82
backend/extensions/Squidex.Extensions/APM/Datadog/DatadogPlugin.cs

@ -1,82 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using Datadog.Trace;
using Datadog.Trace.Configuration;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Infrastructure.Plugins;
using Squidex.Log;
namespace Squidex.Extensions.APM.Datadog
{
public sealed class DatadogPlugin : IPlugin, IStartupFilter
{
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
{
return builder =>
{
builder.Use(async (context, next) =>
{
using (var scope = Tracer.Instance.StartActive(context.Request.Path))
{
try
{
scope.Span.SetTag("http.method", context.Request.Method);
await next();
}
catch (Exception ex)
{
scope.Span.SetException(ex);
throw;
}
finally
{
scope.Span.SetTag("http.status_code", context.Response.StatusCode.ToString());
}
}
});
next(builder);
};
}
public void ConfigureServices(IServiceCollection services, IConfiguration config)
{
var isEnabled = config.GetValue<bool>("logging:datadog");
if (isEnabled)
{
services.AddSingleton<IStartupFilter>(this);
SetupTracer();
SetupProfiler();
}
}
private static void SetupProfiler()
{
Profiler.SpanStarted += session =>
{
session.Listen(Tracer.Instance.StartActive(session.Key));
};
}
private static void SetupTracer()
{
var settings = TracerSettings.FromDefaultSources();
settings.ServiceName = "squidex";
Tracer.Instance = new Tracer(settings);
}
}
}

35
backend/extensions/Squidex.Extensions/APM/Otlp/OtlpPlugin.cs

@ -0,0 +1,35 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Trace;
using Squidex.Infrastructure.Plugins;
namespace Squidex.Extensions.APM.Datadog
{
public sealed class OtlpPlugin : IPlugin
{
public void ConfigureServices(IServiceCollection services, IConfiguration config)
{
services.AddOpenTelemetryTracing(builder =>
{
if (config.GetValue<bool>("logging:otlp:enabled"))
{
// See: https://docs.microsoft.com/aspnet/core/grpc/troubleshoot#call-insecure-grpc-services-with-net-core-client
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
builder.AddOtlpExporter(options =>
{
config.GetSection("logging:otlp").Bind(options);
});
}
});
}
}
}

39
backend/extensions/Squidex.Extensions/APM/Stackdriver/StackdriverExceptionHandler.cs

@ -0,0 +1,39 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using Google.Cloud.Diagnostics.AspNetCore;
using Microsoft.AspNetCore.Http;
using Squidex.Infrastructure;
using Squidex.Log;
namespace Squidex.Extensions.APM.Stackdriver
{
internal class StackdriverExceptionHandler : ILogAppender
{
private readonly DefaultHttpContext fallbackContext = new DefaultHttpContext();
private readonly IExceptionLogger logger;
private readonly IHttpContextAccessor httpContextAccessor;
public StackdriverExceptionHandler(IExceptionLogger logger, IHttpContextAccessor httpContextAccessor)
{
this.logger = logger;
this.httpContextAccessor = httpContextAccessor;
}
public void Append(IObjectWriter writer, SemanticLogLevel logLevel, Exception exception)
{
if (exception != null && exception is not DomainException)
{
var httpContext = httpContextAccessor.HttpContext;
logger.Log(exception, httpContext ?? fallbackContext);
}
}
}
}

37
backend/extensions/Squidex.Extensions/APM/Stackdriver/StackdriverPlugin.cs

@ -0,0 +1,37 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Trace;
using Squidex.Infrastructure.Plugins;
using Squidex.Log;
namespace Squidex.Extensions.APM.Stackdriver
{
public sealed class StackdriverPlugin : IPlugin
{
public void ConfigureServices(IServiceCollection services, IConfiguration config)
{
services.AddOpenTelemetryTracing(builder =>
{
if (config.GetValue<bool>("logging:stackdriver:enabled"))
{
var projectId = config.GetValue<string>("logging:stackdriver:projectId");
builder.UseStackdriverExporter(projectId);
services.AddSingleton<ILogAppender,
StackdriverSeverityLogAppender>();
services.AddSingleton<ILogAppender,
StackdriverExceptionHandler>();
}
});
}
}
}

43
backend/extensions/Squidex.Extensions/APM/Stackdriver/StackdriverSeverityLogAppender.cs

@ -0,0 +1,43 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using Squidex.Log;
namespace Squidex.Extensions.APM.Stackdriver
{
public sealed class StackdriverSeverityLogAppender : ILogAppender
{
public void Append(IObjectWriter writer, SemanticLogLevel logLevel, Exception exception)
{
var severity = GetSeverity(logLevel);
writer.WriteProperty(nameof(severity), severity);
}
private static string GetSeverity(SemanticLogLevel logLevel)
{
switch (logLevel)
{
case SemanticLogLevel.Trace:
return "DEBUG";
case SemanticLogLevel.Debug:
return "DEBUG";
case SemanticLogLevel.Information:
return "INFO";
case SemanticLogLevel.Warning:
return "WARNING";
case SemanticLogLevel.Error:
return "ERROR";
case SemanticLogLevel.Fatal:
return "CRITICAL";
default:
return "DEFAULT";
}
}
}
}

10
backend/extensions/Squidex.Extensions/Squidex.Extensions.csproj

@ -13,16 +13,20 @@
<PackageReference Include="Confluent.Kafka" Version="1.7.0" />
<PackageReference Include="Confluent.SchemaRegistry.Serdes" Version="1.3.0" />
<PackageReference Include="CoreTweet" Version="1.0.0.483" />
<PackageReference Include="Datadog.Trace" Version="1.27.1" />
<PackageReference Include="Elasticsearch.Net" Version="7.13.2" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.17.0" />
<PackageReference Include="Elasticsearch.Net" Version="7.14.1" />
<PackageReference Include="Google.Cloud.Diagnostics.AspNetCore" Version="4.0.0" />
<PackageReference Include="Google.Cloud.Logging.V2" Version="3.3.0" />
<PackageReference Include="Microsoft.Azure.CognitiveServices.Vision.ComputerVision" Version="7.0.0" />
<PackageReference Include="Microsoft.Azure.SignalR.Management" Version="1.9.2" />
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
<PackageReference Include="Microsoft.OData.Core" Version="7.9.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="NodaTime" Version="3.0.5" />
<PackageReference Include="Azure.Monitor.OpenTelemetry.Exporter" Version="1.0.0-beta.2" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.2.0-alpha1" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.0.0-rc7" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="Squidex.OpenTelemetry.Exporter.Stackdriver" Version="0.0.0-alpha.0.97" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />

2
backend/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj

@ -20,7 +20,7 @@
<PackageReference Include="GeoJSON.Net" Version="1.2.19" />
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
<PackageReference Include="Microsoft.OData.Core" Version="7.9.0" />
<PackageReference Include="NJsonSchema" Version="10.4.4" />
<PackageReference Include="NJsonSchema" Version="10.5.2" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="Squidex.Jint" Version="3.0.0-beta-0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />

7
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository.cs

@ -14,7 +14,6 @@ using Squidex.Domain.Apps.Entities.Assets;
using Squidex.Domain.Apps.Entities.Assets.Repositories;
using Squidex.Infrastructure;
using Squidex.Infrastructure.MongoDb;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
{
@ -46,7 +45,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
public async Task<IResultList<IAssetFolderEntity>> QueryAsync(DomainId appId, DomainId parentId,
CancellationToken ct = default)
{
using (Profiler.TraceMethod<MongoAssetFolderRepository>("QueryAsyncByQuery"))
using (Telemetry.Activities.StartMethod<MongoAssetFolderRepository>("QueryAsyncByQuery"))
{
var filter = BuildFilter(appId, parentId);
@ -61,7 +60,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
public async Task<IReadOnlyList<DomainId>> QueryChildIdsAsync(DomainId appId, DomainId parentId,
CancellationToken ct = default)
{
using (Profiler.TraceMethod<MongoAssetRepository>())
using (Telemetry.Activities.StartMethod<MongoAssetRepository>())
{
var filter = BuildFilter(appId, parentId);
@ -78,7 +77,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
public async Task<IAssetFolderEntity?> FindAssetFolderAsync(DomainId appId, DomainId id,
CancellationToken ct = default)
{
using (Profiler.TraceMethod<MongoAssetFolderRepository>())
using (Telemetry.Activities.StartMethod<MongoAssetFolderRepository>())
{
var documentId = DomainId.Combine(appId, id);

11
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository_SnapshotStore.cs

@ -17,7 +17,6 @@ using Squidex.Infrastructure;
using Squidex.Infrastructure.MongoDb;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.States;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
{
@ -25,7 +24,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
{
async Task<(AssetFolderDomainObject.State Value, bool Valid, long Version)> ISnapshotStore<AssetFolderDomainObject.State>.ReadAsync(DomainId key)
{
using (Profiler.TraceMethod<MongoAssetFolderRepository>())
using (Telemetry.Activities.StartMethod<MongoAssetFolderRepository>())
{
var existing =
await Collection.Find(x => x.DocumentId == key)
@ -42,7 +41,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
async Task ISnapshotStore<AssetFolderDomainObject.State>.WriteAsync(DomainId key, AssetFolderDomainObject.State value, long oldVersion, long newVersion)
{
using (Profiler.TraceMethod<MongoAssetFolderRepository>())
using (Telemetry.Activities.StartMethod<MongoAssetFolderRepository>())
{
var entity = Map(value);
@ -52,7 +51,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
async Task ISnapshotStore<AssetFolderDomainObject.State>.WriteManyAsync(IEnumerable<(DomainId Key, AssetFolderDomainObject.State Value, long Version)> snapshots)
{
using (Profiler.TraceMethod<MongoAssetFolderRepository>())
using (Telemetry.Activities.StartMethod<MongoAssetFolderRepository>())
{
var updates = snapshots.Select(Map).Select(x =>
new ReplaceOneModel<MongoAssetFolderEntity>(
@ -74,7 +73,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
async Task ISnapshotStore<AssetFolderDomainObject.State>.ReadAllAsync(Func<AssetFolderDomainObject.State, long, Task> callback,
CancellationToken ct)
{
using (Profiler.TraceMethod<MongoAssetFolderRepository>())
using (Telemetry.Activities.StartMethod<MongoAssetFolderRepository>())
{
await Collection.Find(new BsonDocument(), Batching.Options).ForEachAsync(x => callback(Map(x), x.Version), ct);
}
@ -82,7 +81,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
async Task ISnapshotStore<AssetFolderDomainObject.State>.RemoveAsync(DomainId key)
{
using (Profiler.TraceMethod<MongoAssetFolderRepository>())
using (Telemetry.Activities.StartMethod<MongoAssetFolderRepository>())
{
await Collection.DeleteOneAsync(x => x.DocumentId == key);
}

15
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs

@ -18,7 +18,6 @@ using Squidex.Infrastructure;
using Squidex.Infrastructure.MongoDb;
using Squidex.Infrastructure.MongoDb.Queries;
using Squidex.Infrastructure.Translations;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
{
@ -91,7 +90,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
public async Task<IResultList<IAssetEntity>> QueryAsync(DomainId appId, DomainId? parentId, Q q,
CancellationToken ct = default)
{
using (Profiler.TraceMethod<MongoAssetRepository>("QueryAsyncByQuery"))
using (Telemetry.Activities.StartMethod<MongoAssetRepository>("QueryAsyncByQuery"))
{
try
{
@ -153,7 +152,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
public async Task<IReadOnlyList<DomainId>> QueryIdsAsync(DomainId appId, HashSet<DomainId> ids,
CancellationToken ct = default)
{
using (Profiler.TraceMethod<MongoAssetRepository>("QueryAsyncByIds"))
using (Telemetry.Activities.StartMethod<MongoAssetRepository>("QueryAsyncByIds"))
{
var assetEntities =
await Collection.Find(BuildFilter(appId, ids)).Only(x => x.Id)
@ -168,7 +167,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
public async Task<IReadOnlyList<DomainId>> QueryChildIdsAsync(DomainId appId, DomainId parentId,
CancellationToken ct = default)
{
using (Profiler.TraceMethod<MongoAssetRepository>())
using (Telemetry.Activities.StartMethod<MongoAssetRepository>())
{
var assetEntities =
await Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && x.ParentId == parentId).Only(x => x.Id)
@ -183,7 +182,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
public async Task<IAssetEntity?> FindAssetByHashAsync(DomainId appId, string hash, string fileName, long fileSize,
CancellationToken ct = default)
{
using (Profiler.TraceMethod<MongoAssetRepository>())
using (Telemetry.Activities.StartMethod<MongoAssetRepository>())
{
var assetEntity =
await Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && x.FileHash == hash && x.FileName == fileName && x.FileSize == fileSize)
@ -196,7 +195,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
public async Task<IAssetEntity?> FindAssetBySlugAsync(DomainId appId, string slug,
CancellationToken ct = default)
{
using (Profiler.TraceMethod<MongoAssetRepository>())
using (Telemetry.Activities.StartMethod<MongoAssetRepository>())
{
var assetEntity =
await Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && x.Slug == slug)
@ -209,7 +208,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
public async Task<IAssetEntity?> FindAssetAsync(DomainId appId, DomainId id,
CancellationToken ct = default)
{
using (Profiler.TraceMethod<MongoAssetRepository>())
using (Telemetry.Activities.StartMethod<MongoAssetRepository>())
{
var documentId = DomainId.Combine(appId, id);
@ -224,7 +223,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
public async Task<IAssetEntity?> FindAssetAsync(DomainId id,
CancellationToken ct = default)
{
using (Profiler.TraceMethod<MongoAssetRepository>())
using (Telemetry.Activities.StartMethod<MongoAssetRepository>())
{
var assetEntity =
await Collection.Find(x => x.Id == id && !x.IsDeleted)

11
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository_SnapshotStore.cs

@ -17,7 +17,6 @@ using Squidex.Infrastructure;
using Squidex.Infrastructure.MongoDb;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.States;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
{
@ -25,7 +24,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
{
async Task<(AssetDomainObject.State Value, bool Valid, long Version)> ISnapshotStore<AssetDomainObject.State>.ReadAsync(DomainId key)
{
using (Profiler.TraceMethod<MongoAssetRepository>())
using (Telemetry.Activities.StartMethod<MongoAssetRepository>())
{
var existing =
await Collection.Find(x => x.DocumentId == key)
@ -42,7 +41,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
async Task ISnapshotStore<AssetDomainObject.State>.WriteAsync(DomainId key, AssetDomainObject.State value, long oldVersion, long newVersion)
{
using (Profiler.TraceMethod<MongoAssetRepository>())
using (Telemetry.Activities.StartMethod<MongoAssetRepository>())
{
var entity = Map(value);
@ -52,7 +51,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
async Task ISnapshotStore<AssetDomainObject.State>.WriteManyAsync(IEnumerable<(DomainId Key, AssetDomainObject.State Value, long Version)> snapshots)
{
using (Profiler.TraceMethod<MongoAssetFolderRepository>())
using (Telemetry.Activities.StartMethod<MongoAssetFolderRepository>())
{
var updates = snapshots.Select(Map).Select(x =>
new ReplaceOneModel<MongoAssetEntity>(
@ -74,7 +73,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
async Task ISnapshotStore<AssetDomainObject.State>.ReadAllAsync(Func<AssetDomainObject.State, long, Task> callback,
CancellationToken ct)
{
using (Profiler.TraceMethod<MongoAssetRepository>())
using (Telemetry.Activities.StartMethod<MongoAssetRepository>())
{
await Collection.Find(new BsonDocument(), Batching.Options).ForEachAsync(x => callback(Map(x), x.Version), ct);
}
@ -82,7 +81,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
async Task ISnapshotStore<AssetDomainObject.State>.RemoveAsync(DomainId key)
{
using (Profiler.TraceMethod<MongoAssetRepository>())
using (Telemetry.Activities.StartMethod<MongoAssetRepository>())
{
await Collection.DeleteOneAsync(x => x.DocumentId == key);
}

15
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollection.cs

@ -20,7 +20,6 @@ using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Infrastructure;
using Squidex.Infrastructure.MongoDb;
using Squidex.Infrastructure.Queries;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
{
@ -107,7 +106,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
public async Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, List<ISchemaEntity> schemas, Q q,
CancellationToken ct)
{
using (Profiler.TraceMethod<MongoContentRepository>())
using (Telemetry.Activities.StartMethod<MongoContentRepository>())
{
if (q.Ids != null && q.Ids.Count > 0)
{
@ -136,7 +135,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
public async Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, Q q,
CancellationToken ct)
{
using (Profiler.TraceMethod<MongoContentRepository>())
using (Telemetry.Activities.StartMethod<MongoContentRepository>())
{
if (q.Ids != null && q.Ids.Count > 0)
{
@ -160,7 +159,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
public async Task<IContentEntity?> FindContentAsync(ISchemaEntity schema, DomainId id,
CancellationToken ct)
{
using (Profiler.TraceMethod<MongoContentRepository>())
using (Telemetry.Activities.StartMethod<MongoContentRepository>())
{
return await queryBdId.QueryAsync(schema, id, ct);
}
@ -169,7 +168,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
public async Task QueryScheduledWithoutDataAsync(Instant now, Func<IContentEntity, Task> callback,
CancellationToken ct)
{
using (Profiler.TraceMethod<MongoContentRepository>())
using (Telemetry.Activities.StartMethod<MongoContentRepository>())
{
await queryScheduled.QueryAsync(now, callback, ct);
}
@ -178,7 +177,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
public async Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, HashSet<DomainId> ids,
CancellationToken ct)
{
using (Profiler.TraceMethod<MongoContentRepository>())
using (Telemetry.Activities.StartMethod<MongoContentRepository>())
{
return await queryByIds.QueryIdsAsync(appId, ids, ct);
}
@ -187,7 +186,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
public async Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, DomainId schemaId, FilterNode<ClrValue> filterNode,
CancellationToken ct)
{
using (Profiler.TraceMethod<MongoContentRepository>())
using (Telemetry.Activities.StartMethod<MongoContentRepository>())
{
return await queryByQuery.QueryIdsAsync(appId, schemaId, filterNode, ct);
}
@ -196,7 +195,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
public async Task<bool> HasReferrersAsync(DomainId appId, DomainId contentId,
CancellationToken ct)
{
using (Profiler.TraceMethod<MongoContentRepository>())
using (Telemetry.Activities.StartMethod<MongoContentRepository>())
{
return await queryReferrers.CheckExistsAsync(appId, contentId, ct);
}

11
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository_SnapshotStore.cs

@ -15,7 +15,6 @@ using Squidex.Domain.Apps.Entities.Contents.DomainObject;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.States;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
{
@ -29,7 +28,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
async Task<(ContentDomainObject.State Value, bool Valid, long Version)> ISnapshotStore<ContentDomainObject.State>.ReadAsync(DomainId key)
{
using (Profiler.TraceMethod<MongoContentRepository>())
using (Telemetry.Activities.StartMethod<MongoContentRepository>())
{
var version = await collectionAll.FindVersionAsync(key);
@ -39,7 +38,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
async Task ISnapshotStore<ContentDomainObject.State>.ClearAsync()
{
using (Profiler.TraceMethod<MongoContentRepository>())
using (Telemetry.Activities.StartMethod<MongoContentRepository>())
{
await collectionAll.ClearAsync();
await collectionPublished.ClearAsync();
@ -48,7 +47,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
async Task ISnapshotStore<ContentDomainObject.State>.RemoveAsync(DomainId key)
{
using (Profiler.TraceMethod<MongoContentRepository>())
using (Telemetry.Activities.StartMethod<MongoContentRepository>())
{
await collectionAll.RemoveAsync(key);
await collectionPublished.RemoveAsync(key);
@ -57,7 +56,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
async Task ISnapshotStore<ContentDomainObject.State>.WriteAsync(DomainId key, ContentDomainObject.State value, long oldVersion, long newVersion)
{
using (Profiler.TraceMethod<MongoContentRepository>())
using (Telemetry.Activities.StartMethod<MongoContentRepository>())
{
if (value.SchemaId.Id == DomainId.Empty)
{
@ -72,7 +71,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
async Task ISnapshotStore<ContentDomainObject.State>.WriteManyAsync(IEnumerable<(DomainId Key, ContentDomainObject.State Value, long Version)> snapshots)
{
using (Profiler.TraceMethod<MongoContentRepository>())
using (Telemetry.Activities.StartMethod<MongoContentRepository>())
{
var entitiesPublished = new List<MongoContentEntity>();
var entitiesAll = new List<MongoContentEntity>();

2
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Squidex.Domain.Apps.Entities.MongoDb.csproj

@ -17,7 +17,7 @@
<ProjectReference Include="..\Squidex.Domain.Apps.Entities\Squidex.Domain.Apps.Entities.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MongoDB.Driver" Version="2.12.4" />
<PackageReference Include="MongoDB.Driver" Version="2.13.1" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />

19
backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsIndex.cs

@ -1,4 +1,4 @@
// ==========================================================================
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
@ -19,7 +19,6 @@ using Squidex.Infrastructure.Orleans;
using Squidex.Infrastructure.Security;
using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation;
using Squidex.Log;
using Squidex.Shared;
using Squidex.Text;
@ -77,7 +76,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes
public async Task<List<IAppEntity>> GetAppsAsync()
{
using (Profiler.TraceMethod<AppsIndex>())
using (Telemetry.Activities.StartMethod<AppsIndex>())
{
var ids = await GetAppIdsAsync();
@ -91,7 +90,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes
public async Task<List<IAppEntity>> GetAppsForUserAsync(string userId, PermissionSet permissions)
{
using (Profiler.TraceMethod<AppsIndex>())
using (Telemetry.Activities.StartMethod<AppsIndex>())
{
var ids =
await Task.WhenAll(
@ -109,7 +108,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes
public async Task<IAppEntity?> GetAppByNameAsync(string name, bool canCache = false)
{
using (Profiler.TraceMethod<AppsIndex>())
using (Telemetry.Activities.StartMethod<AppsIndex>())
{
if (canCache)
{
@ -132,7 +131,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes
public async Task<IAppEntity?> GetAppAsync(DomainId appId, bool canCache)
{
using (Profiler.TraceMethod<AppsIndex>())
using (Telemetry.Activities.StartMethod<AppsIndex>())
{
if (canCache)
{
@ -155,7 +154,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes
private async Task<List<DomainId>> GetAppIdsByUserAsync(string userId)
{
using (Profiler.TraceMethod<AppProvider>())
using (Telemetry.Activities.StartMethod<AppProvider>())
{
return await grainFactory.GetGrain<IAppsByUserIndexGrain>(userId).GetIdsAsync();
}
@ -163,7 +162,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes
private async Task<List<DomainId>> GetAppIdsAsync()
{
using (Profiler.TraceMethod<AppProvider>())
using (Telemetry.Activities.StartMethod<AppProvider>())
{
return await grainFactory.GetGrain<IAppsByNameIndexGrain>(SingleGrain.Id).GetIdsAsync();
}
@ -171,7 +170,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes
private async Task<List<DomainId>> GetAppIdsAsync(string[] names)
{
using (Profiler.TraceMethod<AppProvider>())
using (Telemetry.Activities.StartMethod<AppProvider>())
{
return await grainFactory.GetGrain<IAppsByNameIndexGrain>(SingleGrain.Id).GetIdsAsync(names);
}
@ -179,7 +178,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes
private async Task<DomainId> GetAppIdAsync(string name)
{
using (Profiler.TraceMethod<AppProvider>())
using (Telemetry.Activities.StartMethod<AppProvider>())
{
return await grainFactory.GetGrain<IAppsByNameIndexGrain>(SingleGrain.Id).GetIdAsync(name);
}

3
backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetEnricher.cs

@ -14,7 +14,6 @@ using Squidex.Domain.Apps.Core.Tags;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Caching;
using Squidex.Infrastructure.Reflection;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Assets.Queries
{
@ -48,7 +47,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
Guard.NotNull(assets, nameof(assets));
Guard.NotNull(context, nameof(context));
using (Profiler.TraceMethod<AssetEnricher>())
using (Telemetry.Activities.StartMethod<AssetEnricher>())
{
var results = assets.Select(x => SimpleMapper.Map(x, new AssetEntity())).ToList();

3
backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetLoader.cs

@ -9,7 +9,6 @@ using System.Threading.Tasks;
using Orleans;
using Squidex.Domain.Apps.Entities.Assets.DomainObject;
using Squidex.Infrastructure;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Assets.Queries
{
@ -24,7 +23,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
public async Task<IAssetEntity?> GetAsync(DomainId appId, DomainId id, long version)
{
using (Profiler.TraceMethod<AssetLoader>())
using (Telemetry.Activities.StartMethod<AssetLoader>())
{
var key = DomainId.Combine(appId, id);

3
backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetQueryParser.cs

@ -21,7 +21,6 @@ using Squidex.Infrastructure.Queries.Json;
using Squidex.Infrastructure.Queries.OData;
using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation;
using Squidex.Log;
using Squidex.Text;
namespace Squidex.Domain.Apps.Entities.Assets.Queries
@ -48,7 +47,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
Guard.NotNull(context, nameof(context));
Guard.NotNull(q, nameof(q));
using (Profiler.TraceMethod<AssetQueryParser>())
using (Telemetry.Activities.StartMethod<AssetQueryParser>())
{
var query = ParseClrQuery(q);

19
backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetQueryService.cs

@ -12,7 +12,6 @@ using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Squidex.Domain.Apps.Entities.Assets.Repositories;
using Squidex.Infrastructure;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Assets.Queries
{
@ -45,7 +44,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
public async Task<IReadOnlyList<IAssetFolderEntity>> FindAssetFolderAsync(DomainId appId, DomainId id,
CancellationToken ct = default)
{
using (Profiler.TraceMethod<AssetQueryService>())
using (Telemetry.Activities.StartMethod<AssetQueryService>())
{
var result = new List<IAssetFolderEntity>();
@ -71,7 +70,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
public async Task<IResultList<IAssetFolderEntity>> QueryAssetFoldersAsync(DomainId appId, DomainId parentId,
CancellationToken ct = default)
{
using (Profiler.TraceMethod<AssetQueryService>())
using (Telemetry.Activities.StartMethod<AssetQueryService>())
{
var assetFolders = await QueryFoldersCoreAsync(appId, parentId, ct);
@ -82,7 +81,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
public async Task<IResultList<IAssetFolderEntity>> QueryAssetFoldersAsync(Context context, DomainId parentId,
CancellationToken ct = default)
{
using (Profiler.TraceMethod<AssetQueryService>())
using (Telemetry.Activities.StartMethod<AssetQueryService>())
{
var assetFolders = await QueryFoldersCoreAsync(context, parentId, ct);
@ -95,7 +94,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
{
Guard.NotNull(context, nameof(context));
using (Profiler.TraceMethod<AssetQueryService>())
using (Telemetry.Activities.StartMethod<AssetQueryService>())
{
var asset = await FindByHashCoreAsync(context, hash, fileName, fileSize, ct);
@ -113,7 +112,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
{
Guard.NotNull(context, nameof(context));
using (Profiler.TraceMethod<AssetQueryService>())
using (Telemetry.Activities.StartMethod<AssetQueryService>())
{
var asset = await FindBySlugCoreAsync(context, slug, ct);
@ -131,7 +130,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
{
Guard.NotNull(context, nameof(context));
using (Profiler.TraceMethod<AssetQueryService>())
using (Telemetry.Activities.StartMethod<AssetQueryService>())
{
var asset = await FindCoreAsync(id, ct);
@ -149,7 +148,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
{
Guard.NotNull(context, nameof(context));
using (Profiler.TraceMethod<AssetQueryService>())
using (Telemetry.Activities.StartMethod<AssetQueryService>())
{
IAssetEntity? asset;
@ -181,7 +180,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
return EmptyAssets;
}
using (Profiler.TraceMethod<AssetQueryService>())
using (Telemetry.Activities.StartMethod<AssetQueryService>())
{
q = await queryParser.ParseAsync(context, q);
@ -215,7 +214,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
private async Task<IReadOnlyList<IEnrichedAssetEntity>> TransformCoreAsync(Context context, IEnumerable<IAssetEntity> assets,
CancellationToken ct)
{
using (Profiler.TraceMethod<AssetQueryService>())
using (Telemetry.Activities.StartMethod<AssetQueryService>())
{
return await assetEnricher.EnrichAsync(assets, context, ct);
}

16
backend/src/Squidex.Domain.Apps.Entities/Backup/RestoreGrain.cs

@ -136,7 +136,7 @@ namespace Squidex.Domain.Apps.Entities.Backup
jobUrl: CurrentJob.Url.ToString()
);
using (Profiler.StartSession())
using (Telemetry.Activities.StartActivity("RestoreBackup"))
{
try
{
@ -156,14 +156,14 @@ namespace Squidex.Domain.Apps.Entities.Backup
{
await reader.CheckCompatibilityAsync();
using (Profiler.Trace("ReadEvents"))
using (Telemetry.Activities.StartActivity("ReadEvents"))
{
await ReadEventsAsync(reader, handlers);
}
foreach (var handler in handlers)
{
using (Profiler.TraceMethod(handler.GetType(), nameof(IBackupHandler.RestoreAsync)))
using (Telemetry.Activities.StartMethod(handler.GetType(), nameof(IBackupHandler.RestoreAsync)))
{
await handler.RestoreAsync(runningContext);
}
@ -173,7 +173,7 @@ namespace Squidex.Domain.Apps.Entities.Backup
foreach (var handler in handlers)
{
using (Profiler.TraceMethod(handler.GetType(), nameof(IBackupHandler.CompleteRestoreAsync)))
using (Telemetry.Activities.StartMethod(handler.GetType(), nameof(IBackupHandler.CompleteRestoreAsync)))
{
await handler.CompleteRestoreAsync(runningContext);
}
@ -194,8 +194,6 @@ namespace Squidex.Domain.Apps.Entities.Backup
w.WriteProperty("status", "completed");
w.WriteProperty("operationId", ctx.jobId);
w.WriteProperty("url", ctx.jobUrl);
Profiler.Session?.Write(w);
});
}
catch (Exception ex)
@ -223,8 +221,6 @@ namespace Squidex.Domain.Apps.Entities.Backup
w.WriteProperty("status", "failed");
w.WriteProperty("operationId", ctx.jobId);
w.WriteProperty("url", ctx.jobUrl);
Profiler.Session?.Write(w);
});
}
finally
@ -294,7 +290,7 @@ namespace Squidex.Domain.Apps.Entities.Backup
private async Task<IBackupReader> DownloadAsync()
{
using (Profiler.Trace("Download"))
using (Telemetry.Activities.StartActivity("Download"))
{
Log("Downloading Backup");
@ -421,7 +417,7 @@ namespace Squidex.Domain.Apps.Entities.Backup
{
var userMapping = new UserMapping(CurrentJob.Actor);
using (Profiler.Trace("CreateUsers"))
using (Telemetry.Activities.StartActivity("CreateUsers"))
{
Log("Creating Users");

5
backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentEnricher.cs

@ -13,7 +13,6 @@ using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Contents.Queries
{
@ -51,7 +50,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
private async Task<IReadOnlyList<IEnrichedContentEntity>> EnrichInternalAsync(IEnumerable<IContentEntity> contents, bool cloneData, Context context,
CancellationToken ct)
{
using (Profiler.TraceMethod<ContentEnricher>())
using (Telemetry.Activities.StartMethod<ContentEnricher>())
{
var results = new List<ContentEntity>();
@ -102,7 +101,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{
ct.ThrowIfCancellationRequested();
using (Profiler.TraceMethod(step.ToString()!))
using (Telemetry.Activities.StartMethod(step.ToString()!))
{
await step.EnrichAsync(context, results, GetSchema, ct);
}

3
backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentLoader.cs

@ -9,7 +9,6 @@ using System.Threading.Tasks;
using Orleans;
using Squidex.Domain.Apps.Entities.Contents.DomainObject;
using Squidex.Infrastructure;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Contents.Queries
{
@ -24,7 +23,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
public async Task<IContentEntity?> GetAsync(DomainId appId, DomainId id, long version)
{
using (Profiler.TraceMethod<ContentLoader>())
using (Telemetry.Activities.StartMethod<ContentLoader>())
{
var key = DomainId.Combine(appId, id).ToString();

3
backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryParser.cs

@ -28,7 +28,6 @@ using Squidex.Infrastructure.Queries.Json;
using Squidex.Infrastructure.Queries.OData;
using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation;
using Squidex.Log;
using Squidex.Text;
namespace Squidex.Domain.Apps.Entities.Contents.Queries
@ -59,7 +58,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
Guard.NotNull(context, nameof(context));
Guard.NotNull(q, nameof(q));
using (Profiler.TraceMethod<ContentQueryParser>())
using (Telemetry.Activities.StartMethod<ContentQueryParser>())
{
var query = await ParseClrQueryAsync(context, q, schema);

9
backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryService.cs

@ -16,7 +16,6 @@ using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Security;
using Squidex.Infrastructure.Translations;
using Squidex.Log;
using Squidex.Shared;
using Squidex.Shared.Identity;
@ -53,7 +52,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{
Guard.NotNull(context, nameof(context));
using (Profiler.TraceMethod<ContentQueryService>())
using (Telemetry.Activities.StartMethod<ContentQueryService>())
{
var schema = await GetSchemaOrThrowAsync(context, schemaIdOrName);
@ -82,7 +81,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{
Guard.NotNull(context, nameof(context));
using (Profiler.TraceMethod<ContentQueryService>())
using (Telemetry.Activities.StartMethod<ContentQueryService>())
{
if (q == null)
{
@ -114,7 +113,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{
Guard.NotNull(context, nameof(context));
using (Profiler.TraceMethod<ContentQueryService>())
using (Telemetry.Activities.StartMethod<ContentQueryService>())
{
if (q == null)
{
@ -160,7 +159,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
private async Task<IReadOnlyList<IEnrichedContentEntity>> TransformCoreAsync(Context context, IEnumerable<IContentEntity> contents,
CancellationToken ct)
{
using (Profiler.TraceMethod<ContentQueryService>())
using (Telemetry.Activities.StartMethod<ContentQueryService>())
{
return await contentEnricher.EnrichAsync(contents, context, ct);
}

5
backend/src/Squidex.Domain.Apps.Entities/Rules/Indexes/RulesIndex.cs

@ -13,7 +13,6 @@ using Squidex.Domain.Apps.Entities.Rules.Commands;
using Squidex.Domain.Apps.Entities.Rules.DomainObject;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Rules.Indexes
{
@ -33,7 +32,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Indexes
public async Task<List<IRuleEntity>> GetRulesAsync(DomainId appId)
{
using (Profiler.TraceMethod<RulesIndex>())
using (Telemetry.Activities.StartMethod<RulesIndex>())
{
var ids = await GetRuleIdsAsync(appId);
@ -47,7 +46,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Indexes
private async Task<List<DomainId>> GetRuleIdsAsync(DomainId appId)
{
using (Profiler.TraceMethod<RulesIndex>())
using (Telemetry.Activities.StartMethod<RulesIndex>())
{
return await Index(appId).GetIdsAsync();
}

3
backend/src/Squidex.Domain.Apps.Entities/Rules/Queries/RuleEnricher.cs

@ -12,7 +12,6 @@ using Squidex.Domain.Apps.Entities.Rules.Repositories;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Caching;
using Squidex.Infrastructure.Reflection;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Rules.Queries
{
@ -42,7 +41,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Queries
Guard.NotNull(rules, nameof(rules));
Guard.NotNull(context, nameof(context));
using (Profiler.TraceMethod<RuleEnricher>())
using (Telemetry.Activities.StartMethod<RuleEnricher>())
{
var results = new List<RuleEntity>();

11
backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasIndex.cs

@ -17,7 +17,6 @@ using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation;
using Squidex.Log;
using Squidex.Text;
namespace Squidex.Domain.Apps.Entities.Schemas.Indexes
@ -41,7 +40,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes
public async Task<List<ISchemaEntity>> GetSchemasAsync(DomainId appId)
{
using (Profiler.TraceMethod<SchemasIndex>())
using (Telemetry.Activities.StartMethod<SchemasIndex>())
{
var ids = await GetSchemaIdsAsync(appId);
@ -55,7 +54,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes
public async Task<ISchemaEntity?> GetSchemaByNameAsync(DomainId appId, string name, bool canCache)
{
using (Profiler.TraceMethod<SchemasIndex>())
using (Telemetry.Activities.StartMethod<SchemasIndex>())
{
var cacheKey = GetCacheKey(appId, name);
@ -80,7 +79,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes
public async Task<ISchemaEntity?> GetSchemaAsync(DomainId appId, DomainId id, bool canCache)
{
using (Profiler.TraceMethod<SchemasIndex>())
using (Telemetry.Activities.StartMethod<SchemasIndex>())
{
var cacheKey = GetCacheKey(appId, id);
@ -105,7 +104,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes
private async Task<DomainId> GetSchemaIdAsync(DomainId appId, string name)
{
using (Profiler.TraceMethod<SchemasIndex>())
using (Telemetry.Activities.StartMethod<SchemasIndex>())
{
return await Index(appId).GetIdAsync(name);
}
@ -113,7 +112,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes
private async Task<List<DomainId>> GetSchemaIdsAsync(DomainId appId)
{
using (Profiler.TraceMethod<SchemasIndex>())
using (Telemetry.Activities.StartMethod<SchemasIndex>())
{
return await Index(appId).GetIdsAsync();
}

2
backend/src/Squidex.Domain.Apps.Entities/Squidex.Domain.Apps.Entities.csproj

@ -18,7 +18,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="CsvHelper" Version="27.1.1" />
<PackageReference Include="Elasticsearch.Net" Version="7.13.2" />
<PackageReference Include="Elasticsearch.Net" Version="7.14.1" />
<PackageReference Include="Equals.Fody" Version="4.0.1" PrivateAssets="all" />
<PackageReference Include="Fody" Version="6.5.2">
<PrivateAssets>all</PrivateAssets>

2
backend/src/Squidex.Domain.Users.MongoDb/Squidex.Domain.Users.MongoDb.csproj

@ -19,7 +19,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="MongoDB.Driver" Version="2.12.4" />
<PackageReference Include="MongoDB.Driver" Version="2.13.1" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.Security.Principal.Windows" Version="5.0.0" />

2
backend/src/Squidex.Domain.Users/Squidex.Domain.Users.csproj

@ -17,7 +17,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="IdentityModel" Version="5.1.0" />
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="5.0.7" />
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="5.0.9" />
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="OpenIddict.AspNetCore" Version="3.1.0" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />

7
backend/src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore_Reader.cs

@ -14,7 +14,6 @@ using System.Threading.Tasks;
using MongoDB.Driver;
using NodaTime;
using Squidex.Infrastructure.MongoDb;
using Squidex.Log;
using EventFilter = MongoDB.Driver.FilterDefinition<Squidex.Infrastructure.EventSourcing.MongoEventCommit>;
namespace Squidex.Infrastructure.EventSourcing
@ -48,7 +47,7 @@ namespace Squidex.Infrastructure.EventSourcing
return EmptyEvents;
}
using (Profiler.TraceMethod<MongoEventStore>())
using (Telemetry.Activities.StartMethod<MongoEventStore>())
{
var commits =
await Collection.Find(
@ -65,7 +64,7 @@ namespace Squidex.Infrastructure.EventSourcing
{
Guard.NotNullOrEmpty(streamName, nameof(streamName));
using (Profiler.TraceMethod<MongoEventStore>())
using (Telemetry.Activities.StartMethod<MongoEventStore>())
{
var commits =
await Collection.Find(
@ -84,7 +83,7 @@ namespace Squidex.Infrastructure.EventSourcing
{
Guard.NotNull(streamNames, nameof(streamNames));
using (Profiler.TraceMethod<MongoEventStore>())
using (Telemetry.Activities.StartMethod<MongoEventStore>())
{
var position = EtagVersion.Empty;

5
backend/src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore_Writer.cs

@ -10,7 +10,6 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using MongoDB.Bson;
using MongoDB.Driver;
using Squidex.Log;
namespace Squidex.Infrastructure.EventSourcing
{
@ -40,7 +39,7 @@ namespace Squidex.Infrastructure.EventSourcing
Guard.LessThan(events.Count, MaxCommitSize, "events.Count");
Guard.GreaterEquals(expectedVersion, EtagVersion.Any, nameof(expectedVersion));
using (Profiler.TraceMethod<MongoEventStore>())
using (Telemetry.Activities.StartMethod<MongoEventStore>())
{
if (events.Count == 0)
{
@ -102,7 +101,7 @@ namespace Squidex.Infrastructure.EventSourcing
{
Guard.NotNull(commits, nameof(commits));
using (Profiler.TraceMethod<MongoEventStore>())
using (Telemetry.Activities.StartMethod<MongoEventStore>())
{
var writes = new List<WriteModel<MongoEventCommit>>();

4
backend/src/Squidex.Infrastructure.MongoDb/Squidex.Infrastructure.MongoDb.csproj

@ -13,8 +13,8 @@
<ProjectReference Include="..\Squidex.Infrastructure\Squidex.Infrastructure.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MongoDB.Driver" Version="2.12.4" />
<PackageReference Include="MongoDB.Driver.GridFS" Version="2.12.4" />
<PackageReference Include="MongoDB.Driver" Version="2.13.1" />
<PackageReference Include="MongoDB.Driver.GridFS" Version="2.13.1" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.Threading.Tasks.Dataflow" Version="5.0.0" />

11
backend/src/Squidex.Infrastructure.MongoDb/States/MongoSnapshotStore.cs

@ -14,7 +14,6 @@ using MongoDB.Bson;
using MongoDB.Driver;
using Newtonsoft.Json;
using Squidex.Infrastructure.MongoDb;
using Squidex.Log;
namespace Squidex.Infrastructure.States
{
@ -45,7 +44,7 @@ namespace Squidex.Infrastructure.States
public async Task<(T Value, bool Valid, long Version)> ReadAsync(DomainId key)
{
using (Profiler.TraceMethod<MongoSnapshotStore<T>>())
using (Telemetry.Activities.StartMethod<MongoSnapshotStore<T>>())
{
var existing =
await Collection.Find(x => x.DocumentId.Equals(key))
@ -62,7 +61,7 @@ namespace Squidex.Infrastructure.States
public async Task WriteAsync(DomainId key, T value, long oldVersion, long newVersion)
{
using (Profiler.TraceMethod<MongoSnapshotStore<T>>())
using (Telemetry.Activities.StartMethod<MongoSnapshotStore<T>>())
{
await Collection.UpsertVersionedAsync(key, oldVersion, newVersion, u => u.Set(x => x.Doc, value));
}
@ -70,7 +69,7 @@ namespace Squidex.Infrastructure.States
public Task WriteManyAsync(IEnumerable<(DomainId Key, T Value, long Version)> snapshots)
{
using (Profiler.TraceMethod<MongoSnapshotStore<T>>())
using (Telemetry.Activities.StartMethod<MongoSnapshotStore<T>>())
{
var writes = snapshots.Select(x => new ReplaceOneModel<MongoState<T>>(
Filter.Eq(y => y.DocumentId, x.Key),
@ -96,7 +95,7 @@ namespace Squidex.Infrastructure.States
public async Task ReadAllAsync(Func<T, long, Task> callback,
CancellationToken ct = default)
{
using (Profiler.TraceMethod<MongoSnapshotStore<T>>())
using (Telemetry.Activities.StartMethod<MongoSnapshotStore<T>>())
{
await Collection.Find(new BsonDocument(), options: Batching.Options).ForEachAsync(x => callback(x.Doc, x.Version), ct);
}
@ -104,7 +103,7 @@ namespace Squidex.Infrastructure.States
public async Task RemoveAsync(DomainId key)
{
using (Profiler.TraceMethod<MongoSnapshotStore<T>>())
using (Telemetry.Activities.StartMethod<MongoSnapshotStore<T>>())
{
await Collection.DeleteOneAsync(x => x.DocumentId.Equals(key));
}

5
backend/src/Squidex.Infrastructure/Orleans/J{T}.cs

@ -12,7 +12,6 @@ using Orleans.CodeGeneration;
using Orleans.Concurrency;
using Orleans.Serialization;
using Squidex.Infrastructure.Json;
using Squidex.Log;
#pragma warning disable IDE0060 // Remove unused parameter
@ -57,7 +56,7 @@ namespace Squidex.Infrastructure.Orleans
[SerializerMethod]
public static void Serialize(object? input, ISerializationContext context, Type? expected)
{
using (Profiler.TraceMethod(nameof(J)))
using (Telemetry.Activities.StartMethod(nameof(J)))
{
var jsonSerializer = GetSerializer(context);
@ -70,7 +69,7 @@ namespace Squidex.Infrastructure.Orleans
[DeserializerMethod]
public static object? Deserialize(Type expected, IDeserializationContext context)
{
using (Profiler.TraceMethod(nameof(J)))
using (Telemetry.Activities.StartMethod(nameof(J)))
{
var jsonSerializer = GetSerializer(context);

10
backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj

@ -10,11 +10,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="GeoJSON.Net" Version="1.2.19" />
<PackageReference Include="MailKit" Version="2.13.0" />
<PackageReference Include="MailKit" Version="2.14.0" />
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions" Version="5.0.7" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.1.2" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions" Version="5.0.9" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.1.3" />
<PackageReference Include="Microsoft.OData.Core" Version="7.9.0" />
<PackageReference Include="Microsoft.Orleans.CodeGenerator.MSBuild" Version="3.4.3">
<PrivateAssets>all</PrivateAssets>
@ -23,12 +23,12 @@
<PackageReference Include="Microsoft.Orleans.Core" Version="3.4.3" />
<PackageReference Include="Microsoft.Orleans.OrleansRuntime" Version="3.4.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="NJsonSchema" Version="10.4.4" />
<PackageReference Include="NJsonSchema" Version="10.5.2" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="Squidex.Assets" Version="1.8.0" />
<PackageReference Include="Squidex.Caching" Version="1.8.0" />
<PackageReference Include="Squidex.Hosting.Abstractions" Version="1.9.0" />
<PackageReference Include="Squidex.Log" Version="1.4.0" />
<PackageReference Include="Squidex.Log" Version="1.5.0" />
<PackageReference Include="Squidex.Text" Version="1.7.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.Collections.Immutable" Version="5.0.0" />

33
backend/src/Squidex.Infrastructure/Telemetry.cs

@ -0,0 +1,33 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace Squidex.Infrastructure
{
public static class Telemetry
{
public static readonly ActivitySource Activities = new ActivitySource("Notifo");
public static Activity? StartMethod(this ActivitySource activity, Type type, [CallerMemberName] string? memberName = null)
{
return activity.StartActivity($"{type.Name}/{memberName}");
}
public static Activity? StartMethod<T>(this ActivitySource activity, [CallerMemberName] string? memberName = null)
{
return activity.StartActivity($"{typeof(T).Name}/{memberName}");
}
public static Activity? StartMethod(this ActivitySource activity, string objectName, [CallerMemberName] string? memberName = null)
{
return activity.StartActivity($"{objectName}/{memberName}");
}
}
}

4
backend/src/Squidex.Web/ETagExtensions.cs

@ -19,7 +19,7 @@ namespace Squidex.Web
{
public static string ToEtag<T>(this IReadOnlyList<T> items) where T : IEntity, IEntityWithVersion
{
using (Profiler.Trace("CalculateEtag"))
using (Telemetry.Activities.StartActivity("CalculateEtag"))
{
var hash = Create(items, 0);
@ -29,7 +29,7 @@ namespace Squidex.Web
public static string ToEtag<T>(this IResultList<T> entities) where T : IEntity, IEntityWithVersion
{
using (Profiler.Trace("CalculateEtag"))
using (Telemetry.Activities.StartActivity("CalculateEtag"))
{
var hash = Create(entities, entities.Total);

3
backend/src/Squidex.Web/Pipeline/ApiCostsFilter.cs

@ -11,6 +11,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Squidex.Domain.Apps.Entities.Apps.Plans;
using Squidex.Infrastructure;
using Squidex.Log;
namespace Squidex.Web.Pipeline
@ -48,7 +49,7 @@ namespace Squidex.Web.Pipeline
{
if (FilterDefinition.Costs > 0)
{
using (Profiler.Trace("CheckUsage"))
using (Telemetry.Activities.StartActivity("CheckUsage"))
{
var (_, clientId) = context.HttpContext.User.GetClient();

2
backend/src/Squidex.Web/Pipeline/CachingManager.cs

@ -99,7 +99,7 @@ namespace Squidex.Web.Pipeline
{
if (hasDependency && !response.Headers.ContainsKey(HeaderNames.ETag))
{
using (Profiler.Trace("CalculateEtag"))
using (Telemetry.Activities.StartActivity("CalculateEtag"))
{
var cacheBuffer = hasher.GetHashAndReset();
var cacheString = BitConverter.ToString(cacheBuffer).Replace("-", string.Empty).ToUpperInvariant();

6
backend/src/Squidex.Web/Pipeline/MeasureResultFilter.cs

@ -7,7 +7,7 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Filters;
using Squidex.Log;
using Squidex.Infrastructure;
namespace Squidex.Web.Pipeline
{
@ -15,7 +15,7 @@ namespace Squidex.Web.Pipeline
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
using (Profiler.Trace("ExecuteAction"))
using (Telemetry.Activities.StartActivity("ExecuteAction"))
{
await next();
}
@ -23,7 +23,7 @@ namespace Squidex.Web.Pipeline
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
using (Profiler.Trace("ExecuteResult"))
using (Telemetry.Activities.StartActivity("ExecuteResult"))
{
await next();
}

2
backend/src/Squidex.Web/Pipeline/RequestLogOptions.cs

@ -10,7 +10,5 @@ namespace Squidex.Web.Pipeline
public sealed class RequestLogOptions
{
public bool LogRequests { get; set; }
public bool LogProfiler { get; set; }
}
}

37
backend/src/Squidex.Web/Pipeline/RequestLogPerformanceMiddleware.cs

@ -28,79 +28,58 @@ namespace Squidex.Web.Pipeline
public async Task InvokeAsync(HttpContext context, ISemanticLog log)
{
var shouldStartSession = requestLogOptions.LogRequests || Profiler.HasListener;
if (requestLogOptions.LogRequests || shouldStartSession)
if (requestLogOptions.LogRequests)
{
var session =
shouldStartSession ?
Profiler.StartSession() :
default;
var watch =
requestLogOptions.LogRequests ?
ValueStopwatch.StartNew() :
default;
var watch = ValueStopwatch.StartNew();
using (session)
{
try
{
await next(context);
}
finally
{
if (requestLogOptions.LogRequests)
{
var elapsedMs = watch.Stop();
log.LogInformation((elapsedMs, context), (ctx, w) =>
{
if (requestLogOptions.LogProfiler)
{
Profiler.Session?.Write(w);
}
w.WriteObject("filters", ctx.context, LogFilters);
w.WriteProperty("elapsedRequestMs", ctx.elapsedMs);
});
}
}
}
}
else
{
await next(context);
}
}
private static void LogFilters(HttpContext httpContext, IObjectWriter c)
private static void LogFilters(HttpContext httpContext, IObjectWriter obj)
{
var app = httpContext.Context().App;
if (app != null)
{
c.WriteProperty("appId", app.Id.ToString());
c.WriteProperty("appName", app.Name);
obj.WriteProperty("appId", app.Id.ToString());
obj.WriteProperty("appName", app.Name);
}
var userId = httpContext.User.OpenIdSubject();
if (!string.IsNullOrWhiteSpace(userId))
{
c.WriteProperty(nameof(userId), userId);
obj.WriteProperty(nameof(userId), userId);
}
var clientId = httpContext.User.OpenIdClientId();
if (!string.IsNullOrWhiteSpace(clientId))
{
c.WriteProperty(nameof(clientId), clientId);
obj.WriteProperty(nameof(clientId), clientId);
}
var costs = httpContext.Features.Get<IApiCostsFeature>()?.Costs ?? 0;
c.WriteProperty(nameof(costs), costs);
obj.WriteProperty(nameof(costs), costs);
}
}
}

11
backend/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs

@ -18,12 +18,11 @@ using Squidex.Assets;
using Squidex.Domain.Apps.Entities;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Domain.Apps.Entities.Apps.Plans;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.Security;
using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation;
using Squidex.Log;
using Squidex.Shared;
using Squidex.Web;
@ -267,25 +266,25 @@ namespace Squidex.Areas.Api.Controllers.Apps
}
catch (AssetNotFoundException)
{
using (Profiler.Trace("Resize"))
using (Telemetry.Activities.StartActivity("Resize"))
{
using (var sourceStream = GetTempStream())
{
using (var destinationStream = GetTempStream())
{
using (Profiler.Trace("ResizeDownload"))
using (Telemetry.Activities.StartActivity("ResizeDownload"))
{
await appImageStore.DownloadAsync(App.Id, sourceStream);
sourceStream.Position = 0;
}
using (Profiler.Trace("ResizeImage"))
using (Telemetry.Activities.StartActivity("ResizeImage"))
{
await assetThumbnailGenerator.CreateThumbnailAsync(sourceStream, destinationStream, ResizeOptions);
destinationStream.Position = 0;
}
using (Profiler.Trace("ResizeUpload"))
using (Telemetry.Activities.StartActivity("ResizeUpload"))
{
await assetStore.UploadAsync(resizedAsset, destinationStream);
destinationStream.Position = 0;

1
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs

@ -15,7 +15,6 @@ using Squidex.Areas.Api.Controllers.Plans;
using Squidex.Areas.Api.Controllers.Rules;
using Squidex.Areas.Api.Controllers.Schemas;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Apps.Plans;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Json.Objects;
using Squidex.Infrastructure.Reflection;

8
backend/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs

@ -203,19 +203,19 @@ namespace Squidex.Areas.Api.Controllers.Assets
{
var suffix = resizeOptions.ToString();
using (Profiler.Trace("Resize"))
using (Telemetry.Activities.StartActivity("Resize"))
{
using (var sourceStream = GetTempStream())
{
using (var destinationStream = GetTempStream())
{
using (Profiler.Trace("ResizeDownload"))
using (Telemetry.Activities.StartActivity("ResizeDownload"))
{
await assetFileStore.DownloadAsync(asset.AppId.Id, asset.Id, asset.FileVersion, null, sourceStream);
sourceStream.Position = 0;
}
using (Profiler.Trace("ResizeImage"))
using (Telemetry.Activities.StartActivity("ResizeImage"))
{
try
{
@ -231,7 +231,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
try
{
using (Profiler.Trace("ResizeUpload"))
using (Telemetry.Activities.StartActivity("ResizeUpload"))
{
await assetFileStore.UploadAsync(asset.AppId.Id, asset.Id, asset.FileVersion, suffix, destinationStream, overwrite);
destinationStream.Position = 0;

32
backend/src/Squidex/Config/Domain/TelemetryServices.cs

@ -0,0 +1,32 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
namespace Squidex.Config.Domain
{
public static class TelemetryServices
{
public static void AddSquidexTelemetry(this IServiceCollection services)
{
services.AddOpenTelemetryTracing(builder =>
{
builder.SetResourceBuilder(
ResourceBuilder.CreateDefault()
.AddService("Squidex", "Squidex",
typeof(TelemetryServices).Assembly.GetName().Version!.ToString()));
builder.AddSource("Squidex");
builder.AddAspNetCoreInstrumentation();
builder.AddHttpClientInstrumentation();
});
}
}
}

24
backend/src/Squidex/Squidex.csproj

@ -32,16 +32,16 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="AspNet.Security.OAuth.GitHub" Version="5.0.8" />
<PackageReference Include="AspNet.Security.OAuth.GitHub" Version="5.0.9" />
<PackageReference Include="GraphQL.DataLoader" Version="4.5.0" />
<PackageReference Include="GraphQL.Server.Core" Version="5.0.2" />
<PackageReference Include="GraphQL.Server.Transports.AspNetCore.NewtonsoftJson" Version="5.0.2" />
<PackageReference Include="GraphQL.Server.Transports.AspNetCore.SystemTextJson" Version="5.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="5.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.MicrosoftAccount" Version="5.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="5.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="5.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="5.0.9" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.MicrosoftAccount" Version="5.0.9" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="5.0.9" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.9" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="5.0.9" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="5.0.0" />
<PackageReference Include="Microsoft.CodeAnalysis.RulesetToEditorconfigConverter" Version="3.0.0" />
<PackageReference Include="Microsoft.Data.Edm" Version="5.8.4" />
@ -50,18 +50,20 @@
<PackageReference Include="Microsoft.Orleans.Core.Abstractions" Version="3.4.3" />
<PackageReference Include="Microsoft.Orleans.Hosting.Kubernetes" Version="3.4.3" />
<PackageReference Include="Microsoft.Orleans.OrleansRuntime" Version="3.4.3" />
<PackageReference Include="MongoDB.Driver" Version="2.12.4" />
<PackageReference Include="Namotion.Reflection" Version="1.0.23" />
<PackageReference Include="MongoDB.Driver" Version="2.13.1" />
<PackageReference Include="Namotion.Reflection" Version="2.0.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="NJsonSchema" Version="10.4.4" />
<PackageReference Include="NJsonSchema" Version="10.5.2" />
<PackageReference Include="NodaTime.Serialization.JsonNet" Version="3.0.0" />
<PackageReference Include="NSwag.AspNetCore" Version="13.11.3" />
<PackageReference Include="NSwag.AspNetCore" Version="13.13.2" />
<PackageReference Include="OpenCover" Version="4.7.1221" PrivateAssets="all" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.0.0-rc7" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.0.0-rc7" />
<PackageReference Include="Orleans.Providers.MongoDB" Version="3.3.1" />
<PackageReference Include="OrleansDashboard" Version="3.5.2" />
<PackageReference Include="OrleansDashboard.EmbeddedAssets" Version="3.5.2" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="ReportGenerator" Version="4.8.11" PrivateAssets="all" />
<PackageReference Include="ReportGenerator" Version="4.8.12" PrivateAssets="all" />
<PackageReference Include="Squidex.Assets.Azure" Version="1.8.0" />
<PackageReference Include="Squidex.Assets.GoogleCloud" Version="1.8.0" />
<PackageReference Include="Squidex.Assets.FTP" Version="1.8.0" />

1
backend/src/Squidex/Startup.cs

@ -68,6 +68,7 @@ namespace Squidex
services.AddSquidexSerializers();
services.AddSquidexStoreServices(config);
services.AddSquidexSubscriptions(config);
services.AddSquidexTelemetry();
services.AddSquidexTranslation(config);
services.AddSquidexUsageTracking(config);
}

609
backend/src/Squidex/appsettings.json

@ -1,113 +1,78 @@
{
"mode": {
/*
* Use this flag to set Squidex to readonly, e.g. when you deploy a second instance for migration.
*/
// Use this flag to set Squidex to readonly, e.g. when you deploy a second instance for migration.
"isReadonly": false
},
"urls": {
/*
* Set the base url of your application, to generate correct urls in background process.
*/
// Set the base url of your application, to generate correct urls in background process.
"baseUrl": "https://localhost:5001",
/*
* The base path when running Squidex behind a reverse proxy like nginx under a subfolder / subpath.
*/
// The base path when running Squidex behind a reverse proxy like nginx under a subfolder / subpath.
"basePath": "",
/*
* Set it to true to redirect the user from http to https permanently.
*/
// Set it to true to redirect the user from http to https permanently.
"enforceHttps": false,
/*
* Set it to true to return a 400 if the host does not match.
*/
// Set it to true to return a 400 if the host does not match.
"enforceHost": false,
/*
* A list of known proxies to make forward headers safer.
*/
// A list of known proxies to make forward headers safer.
"knownProxies": [],
/*
* Set it to true to use the X-Forwarded- headers for host name and scheme.
*/
// Set it to true to use the X-Forwarded- headers for host name and scheme.
"enableForwardHeaders": true,
/*
* A list of trusted hosts for redirects.
*/
// A list of trusted hosts for redirects.
"trustedHosted": []
},
"fullText": {
/*
* Define the type of the full text store.
*
* Supported: elastic (ElasticSearch). Default: MongoDB
*/
// Define the type of the full text store.
//
// SUPPORTED: elastic (ElasticSearch), default. Default: default
"type": "default",
"elastic": {
/*
* The configuration to your elastic search cluster.
*
* Read More: https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/client-configuration.html
*/
// he configuration to your elastic search cluster.
//
// Read More: https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/client-configuration.html
"configuration": "http://localhost:9200",
/*
* The name of the index.
*/
// The name of the index.
"indexName": "squidex"
}
},
/*
* Define optional paths to plugins.
*/
// Define optional paths to plugins.
"plugins": [
"Squidex.Extensions.dll"
],
"caching": {
/*
* Set to true, to use strong etags.
*/
// Set to true, to use strong etags.
"strongETag": false,
/*
* Restrict the surrogate keys to the number of characters.
*/
// Restrict the surrogate keys to the number of characters.
"maxSurrogateKeysSize": 0,
"replicated": {
/*
* Set to true to enable a replicated cache for app, schemas and rules. Increases performance but reduces consistency.
*/
// Set to true to enable a replicated cache for app, schemas and rules. Increases performance but reduces consistency.
"enable": true
}
},
"languages": {
/*
* Use custom languages where the key is the language code and the value is the english name.
*/
// Use custom languages where the key is the language code and the value is the english name.
"custom": ""
},
"rules": {
/*
* The timeout to execute rule actions.
*/
// The timeout to execute rule actions.
"executionTimeoutInSeconds": 10
},
"ui": {
/*
* Regex suggestions for the UI
*/
// Regex suggestions for the UI
"regexSuggestions": {
// Regex for emails.
"Email": "^[a-zA-Z0-9.!#$%&’*+\\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:.[a-zA-Z0-9-]+)*$",
@ -119,464 +84,318 @@
"Url": "^(?:http(s)?:\\/\\/)?[\\w.-]+(?:\\.[\\w\\.-]+)+[\\w\\-\\._~:\\/?#%[\\]@!\\$&'\\(\\)\\*\\+,;=.]+$"
},
/*
* True if only admins should be able to create apps.
*/
// True if only admins should be able to create apps.
"onlyAdminsCanCreateApps": false,
"map": {
/*
* Define the type of the geolocation service.
*
* Supported: GoogleMaps, OSM
*/
// Define the type of the geolocation service.
//
// SUPPORTED: GoogleMaps, OSM
"type": "OSM",
"googleMaps": {
/*
* The optional google maps API key. CREATE YOUR OWN PLEASE.
*/
// The optional google maps API key. CREATE YOUR OWN PLEASE.
"key": "AIzaSyB_Z8l3nwUxZhMJykiDUJy6bSHXXlwcYMg"
}
},
/*
* Redirect to login automatically.
*/
// Redirect to login automatically.
"redirectToLogin": false,
/*
* Hide the news dialog.
*/
// Hide the news dialog.
"hideNews": false,
/*
* Hide all onboarding tooltips and dialogs.
*/
// Hide all onboarding tooltips and dialogs.
"hideOnboarding": false,
/*
* Hide the today and now button.
*/
// Hide the today and now button.
"hideDateButtons": false,
/*
* Hide the Local/UTC button
*/
// Hide the Local/UTC button
"hideDateTimeModeButton": false,
/*
* Show the exposed values as information on the apps overview page.
*/
// Show the exposed values as information on the apps overview page.
"showInfo": false,
/*
* The number of content items for dropdown selector.
*/
// The number of content items for dropdown selector.
"referencesDropdownItemCount": 100,
"google": {
/*
* The Google analytics ID.
*/
// The Google analytics ID.
"analyticsId": "UA-99989790-2"
}
},
"email": {
"smtp": {
/*
* The host name to your email server.
*/
// The host name to your email server.
"server": "",
/*
* The sender email address.
*/
// The sender email address.
"sender": "hello@squidex.io",
/*
* The username to authenticate to your email server.
*/
// The username to authenticate to your email server.
"username": "",
/*
* The password to authenticate to your email server.
*/
// The password to authenticate to your email server.
"password": "",
/*
* Always use SSL if possible.
*/
// Always use SSL if possible.
"enableSsl": true,
/*
* The port to your email server.
*/
// The port to your email server.
"port": 587
},
"notifications": {
/*
* The email subject when a new user is added as contributor.
*/
// The email subject when a new user is added as contributor.
"newUserSubject": "You have been invited to join Project $APP_NAME at Squidex CMS",
/*
* The email body when a new user is added as contributor.
*/
// The email body when a new user is added as contributor.
"newUserBody": "Welcome to Squidex\r\nDear User,\r\n\r\n$ASSIGNER_NAME ($ASSIGNER_EMAIL) has invited you to join Project (also called an App) $APP_NAME at Squidex Headless CMS. Login with your Github, Google or Microsoft credentials to create a new user account and start editing content now.\r\n\r\nThank you very much,\r\nThe Squidex Team\r\n\r\n<<Start now!>> [$UI_URL]",
/*
* The email subject when an existing user is added as contributor.
*/
// The email subject when an existing user is added as contributor.
"existingUserSubject": "[Squidex CMS] You have been invited to join App $APP_NAME",
/*
* The email body when an existing user is added as contributor.
*/
// The email body when an existing user is added as contributor.
"existingUserBody": "Dear User,\r\n\r\n$ASSIGNER_NAME ($ASSIGNER_EMAIL) has invited you to join App $APP_NAME at Squidex Headless CMS.\r\n\r\nLogin or reload the Management UI to see the App.\r\n\r\nThank you very much,\r\nThe Squidex Team\r\n\r\n<<Start now!>> [$UI_URL]",
/*
* The email subject when app usage reached
*/
// The email subject when app usage reached
"usageSubject": "[Squidex CMS] You you are about to reach your usage limit for App $APP_NAME",
/*
* The email body when app usage reached
*/
// The email body when app usage reached
"usageBody": "Dear User,\r\n\r\nYou you are about to reach your usage limit for App $APP_NAME at Squidex Headless CMS.\r\n\r\nYou have already used $API_CALLS of your monthy limit of $API_CALLS_LIMIT API calls.\r\n\r\nPlease check your clients or upgrade your plan!\r\n\r\n<<Go to Squidex!>> [$UI_URL]"
}
},
/*
* Configure notifo if you want to have support for custom notifications.
*/
// Configure notifo if you want to have support for custom notifications.
"notifo": {
/*
* The id of the app in notifo.
*/
// The id of the app in notifo.
"appId": "",
/*
* The API key for your app in notifo.
*/
// The API key for your app in notifo.
"apiKey": "",
/*
* The API URL.
*/
// The API URL.
"apiUrl": "https://app.notifo.io"
},
"robots": {
/*
* The text for the robots.txt file
*/
// The text for the robots.txt file
"text": "User-agent: *\nAllow: /api/assets/*"
},
"healthz": {
"gc": {
/*
* The maximum number of megabyte that the process can consume until it is marked as not healthy.
*/
// The maximum number of megabyte that the process can consume until it is marked as not healthy.
"threshold": 4096
}
},
"contents": {
/*
* The default page size if not specified by a query.
*/
// The default page size if not specified by a query.
"defaultPageSize": 200,
/*
* The maximum number of items to return for each query.
*
* Warning: Use pagination and not large number of items.
*/
// The maximum number of items to return for each query.
//
// Warning: Use pagination and not large number of items.
"maxResults": 200,
/*
* The timeout when searching for single items in the database.
*/
// The timeout when searching for single items in the database.
"timeoutFind": "00:00:01",
/*
* The timeout when searching for multiple items in the database.
*/
// The timeout when searching for multiple items in the database.
"timeoutQuery": "00:00:05"
},
"assets": {
/*
* The default page size if not specified by a query.
*/
// The default page size if not specified by a query.
"defaultPageSize": 200,
/*
* The maximum number of items to return for each query.
*
* Warning: Use pagination and not large number of items.
*/
// The maximum number of items to return for each query.
//
// Warning: Use pagination and not large number of items.
"maxResults": 200,
/*
* The maximum file size in bytes. Default: 5MB
*/
// The maximum file size in bytes. Default: 5MB
"maxSize": 5242880,
/*
* True to delete assets recursively.
*/
// True to delete assets recursively.
"deleteRecursive": true,
/*
* True to delete assets files permanently.
*/
// True to delete assets files permanently.
"deletePermanent": false,
/*
* The timeout when searching for single items in the database.
*/
// The timeout when searching for single items in the database.
"timeoutFind": "00:00:01",
/*
* The timeout when searching for multiple items in the database.
*/
// The timeout when searching for multiple items in the database.
"timeoutQuery": "00:00:05",
/*
* Create one folder per app.
*
* WARNING: If you change this parameter, previous assets are not available anymore.
*/
// Create one folder per app.
//
// WARNING: If you change this parameter, previous assets are not available anymore.
"folderPerApp": false
},
"logging": {
/*
* The log level.
*
* Trace, Debug, Information, Warning, Error, Fatal
*/
// The log level.
//
// Trace, Debug, Information, Warning, Error, Fatal
"level": "Information",
/*
* Setting the flag to true, enables well formatteds json logs.
*/
// Setting the flag to true, enables well formatteds json logs.
"human": true,
/*
* Set to true, to use colors.
*/
// Set to true, to use colors.
"colors": true,
/*
* Set to false to disable logging of http requests.
*/
// Set to false to disable logging of http requests.
"logRequests": true,
/*
* Set to true to enable logging of profiler information.
*/
"logProfiler": false,
/*
* False to disable the log store.
*/
// False to disable the log store.
"storeEnabled": true,
/*
* The number of days request log items will be stored.
*/
// The number of days request log items will be stored.
"storeRetentationInDays": 90,
/*
* True, to enable datadog integration.
*/
"datadog": false,
"stackdriver": {
// True, to enable stackdriver integration.
"enabled": false
},
"otlp": {
// True, to enable OpenTelemetry Protocol integration.
"enabled": false,
// The endpoint to the agent.
"endpoint": ""
},
"applicationInsights": {
// True, to enable application insights integraon.
"enabled": false,
/*
* True, to enable application insights integraon.
*/
"applicationInsights": false
"connectionString": "InstrumentationKey=[key];IngestionEndpoint=https://[datacenter].in.applicationinsights.azure.com/"
}
},
"assetStore": {
/*
* Define the type of the read store.
*
* Supported: Folder (local folder), MongoDb (GridFS), GoogleCloud (hosted in Google Cloud only), AzureBlob, AmazonS3, FTP (not recommended).
*/
// Define the type of the read store.
//
// SUPPORTED: Folder (local folder), MongoDb (GridFS), GoogleCloud (hosted in Google Cloud only), AzureBlob, AmazonS3, FTP (not recommended).
"type": "Folder",
"folder": {
/*
* The relative or absolute path to the folder to store the assets.
*/
// The relative or absolute path to the folder to store the assets.
"path": "Assets"
},
"googleCloud": {
/*
* The name of the bucket in google cloud store.
*/
// The name of the bucket in google cloud store.
"bucket": "squidex-assets"
},
"azureBlob": {
/*
* The name of the container in the Azure Blob Storage
*/
// The name of the container in the Azure Blob Storage
"containerName": "squidex-assets",
/*
* The connection string to the azure storage service.
*/
// The connection string to the azure storage service.
"connectionString": "UseDevelopmentStorage=true"
},
"AmazonS3": {
/*
* The url of the S3 API service. Leave it empty if using the one provided by Amazon
*/
"amazonS3": {
// The url of the S3 API service. Leave it empty if using the one provided by Amazon
"serviceUrl": "",
/*
* The name of your bucket.
*/
// The name of your bucket.
"bucket": "squidex-test",
/*
* The optional folder within the bucket.
*/
// The optional folder within the bucket.
"bucketFolder": "squidex-assets",
/*
* The region name of your bucket.
*/
// The region name of your bucket.
"regionName": "eu-central-1",
/*
* The access key for your user.
*
* Read More: https://supsystic.com/documentation/id-secret-access-key-amazon-s3/
*/
// The access key for your user.
//
// Read More: https://supsystic.com/documentation/id-secret-access-key-amazon-s3/
"accessKey": "<MY_KEY>",
/*
* The secret key for your user.
*
* Read More: https://supsystic.com/documentation/id-secret-access-key-amazon-s3/
*/
// The secret key for your user.
//
// Read More: https://supsystic.com/documentation/id-secret-access-key-amazon-s3/
"secretKey": "<MY_SECRET>",
/*
* Force path style property for AmazonS3Config
*/
// Force path style property for AmazonS3Config
"forcePathStyle": false
},
"mongoDb": {
/*
* The connection string to your Mongo Server.
*
* Read More: https://docs.mongodb.com/manual/reference/connection-string/
*/
// The connection string to your Mongo Server.
//
// Read More: https://docs.mongodb.com/manual/reference/connection-string/
"configuration": "mongodb://localhost",
/*
* The name of the event store database.
*/
// The name of the event store database.
"database": "SquidexAssets",
/*
* The name of the Mongo Grid FS bucket.
*/
// The name of the Mongo Grid FS bucket.
"bucket": "fs"
},
"ftp": {
/*
*The host of the ftp service
*/
//The host of the ftp service
"serverHost": "",
/*
*The host of the ftp service
*/
//The host of the ftp service
"serverPort": "21",
/*
* Credentials.
*/
// Credentials.
"username": "",
"password": "",
/*
* The relative or absolute path to the folder to store the assets.
*/
// The relative or absolute path to the folder to store the assets.
"path": "Assets"
},
/*
* Allow to expose the url in graph ql url.
*/
// Allow to expose the url in graph ql url.
"exposeSourceUrl": false
},
"orleans": {
/*
* Define the clustering type.
*
* Supported: MongoDB, Development
*/
// Define the clustering type.
//
// SUPPORTED: MongoDB, Development
"clustering": "Development",
/*
* Tell Orleans it is running in kubernetes.
*
* Read more: https://dotnet.github.io/orleans/docs/deployment/kubernetes.html?q=kubernetes
*/
// Tell Orleans it is running in kubernetes.
//
// Read more: https://dotnet.github.io/orleans/docs/deployment/kubernetes.html?q=kubernetes
"kubernetes": false,
/*
* The port is used to share messages between all cluster members. Must be accessible within your cluster or network.
*/
// The port is used to share messages between all cluster members. Must be accessible within your cluster or network.
"siloPort": "11111",
/*
* The ports used by Orleans to connect to external clients. Not used.
*/
// The ports used by Orleans to connect to external clients. Not used.
"gatewayPort": "40000",
/*
* The advertised IP address. Usually not needed.
*/
// The advertised IP address. Usually not needed.
"ipAddress": ""
},
"eventStore": {
/*
* Define the type of the event store.
*
* Supported: MongoDb
*/
// Define the type of the event store.
//
// SUPPORTED: MongoDb
"type": "MongoDb",
"mongoDb": {
/*
* The connection string to your Mongo Server.
*
* Read More: https://docs.mongodb.com/manual/reference/connection-string/
*/
// The connection string to your Mongo Server.
//
// Read More: https://docs.mongodb.com/manual/reference/connection-string/
"configuration": "mongodb://localhost",
/*
* The name of the event store database.
*/
// The name of the event store database.
"database": "Squidex"
}
},
"eventPublishers": {
/*
* Additional event publishers (advanced usage only): (Name => Config)
*/
// Additional event publishers (advanced usage only): (Name => Config)
"allToRabbitMq": {
/*
* Example:: Push all events to RabbitMq.
*/
// Example:: Push all events to RabbitMq.
"type": "RabbitMq",
"configuration": "amqp://guest:guest@localhost/",
"exchange": "squidex",
@ -586,88 +405,62 @@
},
"store": {
/*
* Define the type of the read store.
*
* Supported: MongoDb
*/
// Define the type of the read store.
//
// SUPPORTED: MongoDb
"type": "MongoDb",
"mongoDb": {
/*
* The connection string to your Mongo Server.
*
* Read More: https://docs.mongodb.com/manual/reference/connection-string/
*/
// The connection string to your Mongo Server.
//
// Read More: https://docs.mongodb.com/manual/reference/connection-string/
"configuration": "mongodb://localhost",
/*
* The database for all your content collections (one collection per app).
*/
// The database for all your content collections (one collection per app).
"contentDatabase": "SquidexContent",
/*
* The database for all your other read collections.
*/
// The database for all your other read collections.
"database": "Squidex"
}
},
"identity": {
/*
* Set to true to show PII (Personally Identifiable Information) in the logs.
*/
// Set to true to show PII (Personally Identifiable Information) in the logs.
"showPII": true,
/*
* Enable password auth. Set this to false if you want to disable local login, leaving only 3rd party login options.
*/
// Enable password auth. Set this to false if you want to disable local login, leaving only 3rd party login options.
"allowPasswordAuth": true,
/*
* Initial admin user.
*/
// Initial admin user.
"adminEmail": "",
"adminPassword": "",
/*
* Recreate the admin if it does not exist or the password does not match.
*/
// Recreate the admin if it does not exist or the password does not match.
"adminRecreate": false,
/*
* Client with all admin permissions.
*/
// Client with all admin permissions.
"adminClientId": "",
"adminClientSecret": "",
/*
* The apps which should be visible on the dashboard for the admin.
*/
// The apps which should be visible on the dashboard for the admin.
"adminApps": [],
/*
* Settings for Google auth (keep empty to disable).
*/
// Settings for Google auth (keep empty to disable).
"googleClient": "1006817248705-t3lb3ge808m9am4t7upqth79hulk456l.apps.googleusercontent.com",
"googleSecret": "QsEi-fHqkGw2_PjJmtNHf2wg",
/*
* Settings for Github auth (keep empty to disable).
*/
// Settings for Github auth (keep empty to disable).
"githubClient": "211ea00e726baf754c78",
"githubSecret": "d0a0d0fe2c26469ae20987ac265b3a339fd73132",
/*
* Settings for Microsoft auth (keep empty to disable).
* Tennant is optional for using a specific AzureAD tenant
*/
// Settings for Microsoft auth (keep empty to disable).3
//
// NOTE: Tennant is optional for using a specific AzureAD tenant
"microsoftClient": "b55da740-6648-4502-8746-b9003f29d5f1",
"microsoftSecret": "idWbANxNYEF4cB368WXJhjN",
"microsoftTenant": null,
/*
* Settings for your custom oidc server.
*/
// Settings for your custom oidc server.
"oidcName": "OIDC",
"oidcAuthority": "",
"oidcClient": "",
@ -680,35 +473,25 @@
"oidcGetClaimsFromUserInfoEndpoint": false,
"oidcOnSignoutRedirectUrl": "",
/*
* Lock new users automatically, the administrator must unlock them.
*/
// Lock new users automatically, the administrator must unlock them.
"lockAutomatically": false,
/*
* The url to you privacy statements, if you host squidex by yourself.
*/
// The url to you privacy statements, if you host squidex by yourself.
"privacyUrl": "https://squidex.io/privacy"
},
"news": {
/*
* The app name where the news are stored.
*/
// The app name where the news are stored.
"appName": "squidex-website",
/*
* The credentials to the app (Readonly).
*/
// The credentials to the app (Readonly).
"clientId": "squidex-website:default",
"clientSecret": "QGgqxd7bDHBTEkpC6fj8sbdPWgZrPrPfr3xzb3LKoec="
},
"translations": {
"deepl": {
/*
* The deepl api key if you want to support automated translations.
*/
// The deepl api key if you want to support automated translations.
"authKey": "",
"mapping": {
"zh-TW": "zh-TW",
@ -717,67 +500,45 @@
},
"googleCloud": {
/*
* The google cloud project id if you want to support automated translations.
*/
// The google cloud project id if you want to support automated translations.
"projectId": ""
}
},
"rebuild": {
/*
* Set to true to rebuild apps.
*/
// Set to true to rebuild apps.
"apps": false,
/*
* Set to true to rebuild assets.
*/
// Set to true to rebuild assets.
"assets": false,
/*
* Set to true to create dummy asset files if they do not exist. Useful when a backup fail.
*/
// Set to true to create dummy asset files if they do not exist. Useful when a backup fail.
"assetFiles": false,
/*
* Set to true to rebuild contents.
*/
// Set to true to rebuild contents.
"contents": false,
/*
* Set to true to rebuild rules.
*/
// Set to true to rebuild rules.
"rules": false,
/*
* Set to true to rebuild schemas.
*/
// Set to true to rebuild schemas.
"schemas": false,
/*
* Set to true to rebuild indexes.
*/
// Set to true to rebuild indexes.
"indexes": false
},
/*"
* A list of configuration values that should be exposed from the info endpoint and in the UI.
*/
// A list of configuration values that should be exposed from the info endpoint and in the UI.
"exposedConfiguration": {
"version": "squidex:version"
},
/*
* Kafka Producer configuration
*/
// Kafka Producer configuration
"kafka": {
"bootstrapServers": ""
},
/*
* The client information for twitter.
*/
// The client information for twitter.
"twitter": {
"clientId": "QZhb3HQcGCvE6G8yNNP9ksNet",
"clientSecret": "Pdu9wdN72T33KJRFdFy1w4urBKDRzIyuKpc0OItQC2E616DuZD"

Loading…
Cancel
Save