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

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.Kafka" Version="1.7.0" />
<PackageReference Include="Confluent.SchemaRegistry.Serdes" Version="1.3.0" /> <PackageReference Include="Confluent.SchemaRegistry.Serdes" Version="1.3.0" />
<PackageReference Include="CoreTweet" Version="1.0.0.483" /> <PackageReference Include="CoreTweet" Version="1.0.0.483" />
<PackageReference Include="Datadog.Trace" Version="1.27.1" /> <PackageReference Include="Elasticsearch.Net" Version="7.14.1" />
<PackageReference Include="Elasticsearch.Net" Version="7.13.2" /> <PackageReference Include="Google.Cloud.Diagnostics.AspNetCore" Version="4.0.0" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.17.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.CognitiveServices.Vision.ComputerVision" Version="7.0.0" />
<PackageReference Include="Microsoft.Azure.SignalR.Management" Version="1.9.2" /> <PackageReference Include="Microsoft.Azure.SignalR.Management" Version="1.9.2" />
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
<PackageReference Include="Microsoft.OData.Core" Version="7.9.0" /> <PackageReference Include="Microsoft.OData.Core" Version="7.9.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="NodaTime" Version="3.0.5" /> <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="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="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" /> <PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.ValueTuple" Version="4.5.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="GeoJSON.Net" Version="1.2.19" />
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
<PackageReference Include="Microsoft.OData.Core" Version="7.9.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="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="Squidex.Jint" Version="3.0.0-beta-0" /> <PackageReference Include="Squidex.Jint" Version="3.0.0-beta-0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" /> <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.Domain.Apps.Entities.Assets.Repositories;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.MongoDb; using Squidex.Infrastructure.MongoDb;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.MongoDb.Assets 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, public async Task<IResultList<IAssetFolderEntity>> QueryAsync(DomainId appId, DomainId parentId,
CancellationToken ct = default) CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<MongoAssetFolderRepository>("QueryAsyncByQuery")) using (Telemetry.Activities.StartMethod<MongoAssetFolderRepository>("QueryAsyncByQuery"))
{ {
var filter = BuildFilter(appId, parentId); 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, public async Task<IReadOnlyList<DomainId>> QueryChildIdsAsync(DomainId appId, DomainId parentId,
CancellationToken ct = default) CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<MongoAssetRepository>()) using (Telemetry.Activities.StartMethod<MongoAssetRepository>())
{ {
var filter = BuildFilter(appId, parentId); 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, public async Task<IAssetFolderEntity?> FindAssetFolderAsync(DomainId appId, DomainId id,
CancellationToken ct = default) CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<MongoAssetFolderRepository>()) using (Telemetry.Activities.StartMethod<MongoAssetFolderRepository>())
{ {
var documentId = DomainId.Combine(appId, id); 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.MongoDb;
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.States; using Squidex.Infrastructure.States;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.MongoDb.Assets 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) 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 = var existing =
await Collection.Find(x => x.DocumentId == key) 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) 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); 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) 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 => var updates = snapshots.Select(Map).Select(x =>
new ReplaceOneModel<MongoAssetFolderEntity>( 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, async Task ISnapshotStore<AssetFolderDomainObject.State>.ReadAllAsync(Func<AssetFolderDomainObject.State, long, Task> callback,
CancellationToken ct) 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); 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) async Task ISnapshotStore<AssetFolderDomainObject.State>.RemoveAsync(DomainId key)
{ {
using (Profiler.TraceMethod<MongoAssetFolderRepository>()) using (Telemetry.Activities.StartMethod<MongoAssetFolderRepository>())
{ {
await Collection.DeleteOneAsync(x => x.DocumentId == key); 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;
using Squidex.Infrastructure.MongoDb.Queries; using Squidex.Infrastructure.MongoDb.Queries;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.MongoDb.Assets 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, public async Task<IResultList<IAssetEntity>> QueryAsync(DomainId appId, DomainId? parentId, Q q,
CancellationToken ct = default) CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<MongoAssetRepository>("QueryAsyncByQuery")) using (Telemetry.Activities.StartMethod<MongoAssetRepository>("QueryAsyncByQuery"))
{ {
try try
{ {
@ -153,7 +152,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
public async Task<IReadOnlyList<DomainId>> QueryIdsAsync(DomainId appId, HashSet<DomainId> ids, public async Task<IReadOnlyList<DomainId>> QueryIdsAsync(DomainId appId, HashSet<DomainId> ids,
CancellationToken ct = default) CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<MongoAssetRepository>("QueryAsyncByIds")) using (Telemetry.Activities.StartMethod<MongoAssetRepository>("QueryAsyncByIds"))
{ {
var assetEntities = var assetEntities =
await Collection.Find(BuildFilter(appId, ids)).Only(x => x.Id) 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, public async Task<IReadOnlyList<DomainId>> QueryChildIdsAsync(DomainId appId, DomainId parentId,
CancellationToken ct = default) CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<MongoAssetRepository>()) using (Telemetry.Activities.StartMethod<MongoAssetRepository>())
{ {
var assetEntities = var assetEntities =
await Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && x.ParentId == parentId).Only(x => x.Id) 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, public async Task<IAssetEntity?> FindAssetByHashAsync(DomainId appId, string hash, string fileName, long fileSize,
CancellationToken ct = default) CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<MongoAssetRepository>()) using (Telemetry.Activities.StartMethod<MongoAssetRepository>())
{ {
var assetEntity = var assetEntity =
await Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && x.FileHash == hash && x.FileName == fileName && x.FileSize == fileSize) 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, public async Task<IAssetEntity?> FindAssetBySlugAsync(DomainId appId, string slug,
CancellationToken ct = default) CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<MongoAssetRepository>()) using (Telemetry.Activities.StartMethod<MongoAssetRepository>())
{ {
var assetEntity = var assetEntity =
await Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && x.Slug == slug) 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, public async Task<IAssetEntity?> FindAssetAsync(DomainId appId, DomainId id,
CancellationToken ct = default) CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<MongoAssetRepository>()) using (Telemetry.Activities.StartMethod<MongoAssetRepository>())
{ {
var documentId = DomainId.Combine(appId, id); var documentId = DomainId.Combine(appId, id);
@ -224,7 +223,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
public async Task<IAssetEntity?> FindAssetAsync(DomainId id, public async Task<IAssetEntity?> FindAssetAsync(DomainId id,
CancellationToken ct = default) CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<MongoAssetRepository>()) using (Telemetry.Activities.StartMethod<MongoAssetRepository>())
{ {
var assetEntity = var assetEntity =
await Collection.Find(x => x.Id == id && !x.IsDeleted) 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.MongoDb;
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.States; using Squidex.Infrastructure.States;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.MongoDb.Assets 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) 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 = var existing =
await Collection.Find(x => x.DocumentId == key) 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) 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); 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) 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 => var updates = snapshots.Select(Map).Select(x =>
new ReplaceOneModel<MongoAssetEntity>( 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, async Task ISnapshotStore<AssetDomainObject.State>.ReadAllAsync(Func<AssetDomainObject.State, long, Task> callback,
CancellationToken ct) 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); 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) async Task ISnapshotStore<AssetDomainObject.State>.RemoveAsync(DomainId key)
{ {
using (Profiler.TraceMethod<MongoAssetRepository>()) using (Telemetry.Activities.StartMethod<MongoAssetRepository>())
{ {
await Collection.DeleteOneAsync(x => x.DocumentId == key); 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;
using Squidex.Infrastructure.MongoDb; using Squidex.Infrastructure.MongoDb;
using Squidex.Infrastructure.Queries; using Squidex.Infrastructure.Queries;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.MongoDb.Contents 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, public async Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, List<ISchemaEntity> schemas, Q q,
CancellationToken ct) CancellationToken ct)
{ {
using (Profiler.TraceMethod<MongoContentRepository>()) using (Telemetry.Activities.StartMethod<MongoContentRepository>())
{ {
if (q.Ids != null && q.Ids.Count > 0) 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, public async Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, Q q,
CancellationToken ct) CancellationToken ct)
{ {
using (Profiler.TraceMethod<MongoContentRepository>()) using (Telemetry.Activities.StartMethod<MongoContentRepository>())
{ {
if (q.Ids != null && q.Ids.Count > 0) 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, public async Task<IContentEntity?> FindContentAsync(ISchemaEntity schema, DomainId id,
CancellationToken ct) CancellationToken ct)
{ {
using (Profiler.TraceMethod<MongoContentRepository>()) using (Telemetry.Activities.StartMethod<MongoContentRepository>())
{ {
return await queryBdId.QueryAsync(schema, id, ct); 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, public async Task QueryScheduledWithoutDataAsync(Instant now, Func<IContentEntity, Task> callback,
CancellationToken ct) CancellationToken ct)
{ {
using (Profiler.TraceMethod<MongoContentRepository>()) using (Telemetry.Activities.StartMethod<MongoContentRepository>())
{ {
await queryScheduled.QueryAsync(now, callback, ct); 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, public async Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, HashSet<DomainId> ids,
CancellationToken ct) CancellationToken ct)
{ {
using (Profiler.TraceMethod<MongoContentRepository>()) using (Telemetry.Activities.StartMethod<MongoContentRepository>())
{ {
return await queryByIds.QueryIdsAsync(appId, ids, ct); 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, public async Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, DomainId schemaId, FilterNode<ClrValue> filterNode,
CancellationToken ct) CancellationToken ct)
{ {
using (Profiler.TraceMethod<MongoContentRepository>()) using (Telemetry.Activities.StartMethod<MongoContentRepository>())
{ {
return await queryByQuery.QueryIdsAsync(appId, schemaId, filterNode, ct); 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, public async Task<bool> HasReferrersAsync(DomainId appId, DomainId contentId,
CancellationToken ct) CancellationToken ct)
{ {
using (Profiler.TraceMethod<MongoContentRepository>()) using (Telemetry.Activities.StartMethod<MongoContentRepository>())
{ {
return await queryReferrers.CheckExistsAsync(appId, contentId, ct); 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;
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.States; using Squidex.Infrastructure.States;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.MongoDb.Contents 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) 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); var version = await collectionAll.FindVersionAsync(key);
@ -39,7 +38,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
async Task ISnapshotStore<ContentDomainObject.State>.ClearAsync() async Task ISnapshotStore<ContentDomainObject.State>.ClearAsync()
{ {
using (Profiler.TraceMethod<MongoContentRepository>()) using (Telemetry.Activities.StartMethod<MongoContentRepository>())
{ {
await collectionAll.ClearAsync(); await collectionAll.ClearAsync();
await collectionPublished.ClearAsync(); await collectionPublished.ClearAsync();
@ -48,7 +47,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
async Task ISnapshotStore<ContentDomainObject.State>.RemoveAsync(DomainId key) async Task ISnapshotStore<ContentDomainObject.State>.RemoveAsync(DomainId key)
{ {
using (Profiler.TraceMethod<MongoContentRepository>()) using (Telemetry.Activities.StartMethod<MongoContentRepository>())
{ {
await collectionAll.RemoveAsync(key); await collectionAll.RemoveAsync(key);
await collectionPublished.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) 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) 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) 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 entitiesPublished = new List<MongoContentEntity>();
var entitiesAll = 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" /> <ProjectReference Include="..\Squidex.Domain.Apps.Entities\Squidex.Domain.Apps.Entities.csproj" />
</ItemGroup> </ItemGroup>
<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="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" /> <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" /> <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 // Squidex Headless CMS
// ========================================================================== // ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt) // Copyright (c) Squidex UG (haftungsbeschraenkt)
@ -19,7 +19,6 @@ using Squidex.Infrastructure.Orleans;
using Squidex.Infrastructure.Security; using Squidex.Infrastructure.Security;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
using Squidex.Log;
using Squidex.Shared; using Squidex.Shared;
using Squidex.Text; using Squidex.Text;
@ -77,7 +76,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes
public async Task<List<IAppEntity>> GetAppsAsync() public async Task<List<IAppEntity>> GetAppsAsync()
{ {
using (Profiler.TraceMethod<AppsIndex>()) using (Telemetry.Activities.StartMethod<AppsIndex>())
{ {
var ids = await GetAppIdsAsync(); 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) public async Task<List<IAppEntity>> GetAppsForUserAsync(string userId, PermissionSet permissions)
{ {
using (Profiler.TraceMethod<AppsIndex>()) using (Telemetry.Activities.StartMethod<AppsIndex>())
{ {
var ids = var ids =
await Task.WhenAll( await Task.WhenAll(
@ -109,7 +108,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes
public async Task<IAppEntity?> GetAppByNameAsync(string name, bool canCache = false) public async Task<IAppEntity?> GetAppByNameAsync(string name, bool canCache = false)
{ {
using (Profiler.TraceMethod<AppsIndex>()) using (Telemetry.Activities.StartMethod<AppsIndex>())
{ {
if (canCache) if (canCache)
{ {
@ -132,7 +131,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes
public async Task<IAppEntity?> GetAppAsync(DomainId appId, bool canCache) public async Task<IAppEntity?> GetAppAsync(DomainId appId, bool canCache)
{ {
using (Profiler.TraceMethod<AppsIndex>()) using (Telemetry.Activities.StartMethod<AppsIndex>())
{ {
if (canCache) if (canCache)
{ {
@ -155,7 +154,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes
private async Task<List<DomainId>> GetAppIdsByUserAsync(string userId) private async Task<List<DomainId>> GetAppIdsByUserAsync(string userId)
{ {
using (Profiler.TraceMethod<AppProvider>()) using (Telemetry.Activities.StartMethod<AppProvider>())
{ {
return await grainFactory.GetGrain<IAppsByUserIndexGrain>(userId).GetIdsAsync(); return await grainFactory.GetGrain<IAppsByUserIndexGrain>(userId).GetIdsAsync();
} }
@ -163,7 +162,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes
private async Task<List<DomainId>> GetAppIdsAsync() private async Task<List<DomainId>> GetAppIdsAsync()
{ {
using (Profiler.TraceMethod<AppProvider>()) using (Telemetry.Activities.StartMethod<AppProvider>())
{ {
return await grainFactory.GetGrain<IAppsByNameIndexGrain>(SingleGrain.Id).GetIdsAsync(); 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) 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); 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) 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); 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;
using Squidex.Infrastructure.Caching; using Squidex.Infrastructure.Caching;
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Assets.Queries 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(assets, nameof(assets));
Guard.NotNull(context, nameof(context)); 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(); 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 Orleans;
using Squidex.Domain.Apps.Entities.Assets.DomainObject; using Squidex.Domain.Apps.Entities.Assets.DomainObject;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Assets.Queries 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) 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); 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.Queries.OData;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
using Squidex.Log;
using Squidex.Text; using Squidex.Text;
namespace Squidex.Domain.Apps.Entities.Assets.Queries 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(context, nameof(context));
Guard.NotNull(q, nameof(q)); Guard.NotNull(q, nameof(q));
using (Profiler.TraceMethod<AssetQueryParser>()) using (Telemetry.Activities.StartMethod<AssetQueryParser>())
{ {
var query = ParseClrQuery(q); 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 Microsoft.Extensions.Options;
using Squidex.Domain.Apps.Entities.Assets.Repositories; using Squidex.Domain.Apps.Entities.Assets.Repositories;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Assets.Queries 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, public async Task<IReadOnlyList<IAssetFolderEntity>> FindAssetFolderAsync(DomainId appId, DomainId id,
CancellationToken ct = default) CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<AssetQueryService>()) using (Telemetry.Activities.StartMethod<AssetQueryService>())
{ {
var result = new List<IAssetFolderEntity>(); 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, public async Task<IResultList<IAssetFolderEntity>> QueryAssetFoldersAsync(DomainId appId, DomainId parentId,
CancellationToken ct = default) CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<AssetQueryService>()) using (Telemetry.Activities.StartMethod<AssetQueryService>())
{ {
var assetFolders = await QueryFoldersCoreAsync(appId, parentId, ct); 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, public async Task<IResultList<IAssetFolderEntity>> QueryAssetFoldersAsync(Context context, DomainId parentId,
CancellationToken ct = default) CancellationToken ct = default)
{ {
using (Profiler.TraceMethod<AssetQueryService>()) using (Telemetry.Activities.StartMethod<AssetQueryService>())
{ {
var assetFolders = await QueryFoldersCoreAsync(context, parentId, ct); var assetFolders = await QueryFoldersCoreAsync(context, parentId, ct);
@ -95,7 +94,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
{ {
Guard.NotNull(context, nameof(context)); Guard.NotNull(context, nameof(context));
using (Profiler.TraceMethod<AssetQueryService>()) using (Telemetry.Activities.StartMethod<AssetQueryService>())
{ {
var asset = await FindByHashCoreAsync(context, hash, fileName, fileSize, ct); 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)); Guard.NotNull(context, nameof(context));
using (Profiler.TraceMethod<AssetQueryService>()) using (Telemetry.Activities.StartMethod<AssetQueryService>())
{ {
var asset = await FindBySlugCoreAsync(context, slug, ct); var asset = await FindBySlugCoreAsync(context, slug, ct);
@ -131,7 +130,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
{ {
Guard.NotNull(context, nameof(context)); Guard.NotNull(context, nameof(context));
using (Profiler.TraceMethod<AssetQueryService>()) using (Telemetry.Activities.StartMethod<AssetQueryService>())
{ {
var asset = await FindCoreAsync(id, ct); var asset = await FindCoreAsync(id, ct);
@ -149,7 +148,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
{ {
Guard.NotNull(context, nameof(context)); Guard.NotNull(context, nameof(context));
using (Profiler.TraceMethod<AssetQueryService>()) using (Telemetry.Activities.StartMethod<AssetQueryService>())
{ {
IAssetEntity? asset; IAssetEntity? asset;
@ -181,7 +180,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
return EmptyAssets; return EmptyAssets;
} }
using (Profiler.TraceMethod<AssetQueryService>()) using (Telemetry.Activities.StartMethod<AssetQueryService>())
{ {
q = await queryParser.ParseAsync(context, q); 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, private async Task<IReadOnlyList<IEnrichedAssetEntity>> TransformCoreAsync(Context context, IEnumerable<IAssetEntity> assets,
CancellationToken ct) CancellationToken ct)
{ {
using (Profiler.TraceMethod<AssetQueryService>()) using (Telemetry.Activities.StartMethod<AssetQueryService>())
{ {
return await assetEnricher.EnrichAsync(assets, context, ct); 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() jobUrl: CurrentJob.Url.ToString()
); );
using (Profiler.StartSession()) using (Telemetry.Activities.StartActivity("RestoreBackup"))
{ {
try try
{ {
@ -156,14 +156,14 @@ namespace Squidex.Domain.Apps.Entities.Backup
{ {
await reader.CheckCompatibilityAsync(); await reader.CheckCompatibilityAsync();
using (Profiler.Trace("ReadEvents")) using (Telemetry.Activities.StartActivity("ReadEvents"))
{ {
await ReadEventsAsync(reader, handlers); await ReadEventsAsync(reader, handlers);
} }
foreach (var handler in 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); await handler.RestoreAsync(runningContext);
} }
@ -173,7 +173,7 @@ namespace Squidex.Domain.Apps.Entities.Backup
foreach (var handler in handlers) 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); await handler.CompleteRestoreAsync(runningContext);
} }
@ -194,8 +194,6 @@ namespace Squidex.Domain.Apps.Entities.Backup
w.WriteProperty("status", "completed"); w.WriteProperty("status", "completed");
w.WriteProperty("operationId", ctx.jobId); w.WriteProperty("operationId", ctx.jobId);
w.WriteProperty("url", ctx.jobUrl); w.WriteProperty("url", ctx.jobUrl);
Profiler.Session?.Write(w);
}); });
} }
catch (Exception ex) catch (Exception ex)
@ -223,8 +221,6 @@ namespace Squidex.Domain.Apps.Entities.Backup
w.WriteProperty("status", "failed"); w.WriteProperty("status", "failed");
w.WriteProperty("operationId", ctx.jobId); w.WriteProperty("operationId", ctx.jobId);
w.WriteProperty("url", ctx.jobUrl); w.WriteProperty("url", ctx.jobUrl);
Profiler.Session?.Write(w);
}); });
} }
finally finally
@ -294,7 +290,7 @@ namespace Squidex.Domain.Apps.Entities.Backup
private async Task<IBackupReader> DownloadAsync() private async Task<IBackupReader> DownloadAsync()
{ {
using (Profiler.Trace("Download")) using (Telemetry.Activities.StartActivity("Download"))
{ {
Log("Downloading Backup"); Log("Downloading Backup");
@ -421,7 +417,7 @@ namespace Squidex.Domain.Apps.Entities.Backup
{ {
var userMapping = new UserMapping(CurrentJob.Actor); var userMapping = new UserMapping(CurrentJob.Actor);
using (Profiler.Trace("CreateUsers")) using (Telemetry.Activities.StartActivity("CreateUsers"))
{ {
Log("Creating Users"); 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.Domain.Apps.Entities.Schemas;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Contents.Queries 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, private async Task<IReadOnlyList<IEnrichedContentEntity>> EnrichInternalAsync(IEnumerable<IContentEntity> contents, bool cloneData, Context context,
CancellationToken ct) CancellationToken ct)
{ {
using (Profiler.TraceMethod<ContentEnricher>()) using (Telemetry.Activities.StartMethod<ContentEnricher>())
{ {
var results = new List<ContentEntity>(); var results = new List<ContentEntity>();
@ -102,7 +101,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{ {
ct.ThrowIfCancellationRequested(); ct.ThrowIfCancellationRequested();
using (Profiler.TraceMethod(step.ToString()!)) using (Telemetry.Activities.StartMethod(step.ToString()!))
{ {
await step.EnrichAsync(context, results, GetSchema, ct); 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 Orleans;
using Squidex.Domain.Apps.Entities.Contents.DomainObject; using Squidex.Domain.Apps.Entities.Contents.DomainObject;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Contents.Queries 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) 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(); 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.Queries.OData;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
using Squidex.Log;
using Squidex.Text; using Squidex.Text;
namespace Squidex.Domain.Apps.Entities.Contents.Queries 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(context, nameof(context));
Guard.NotNull(q, nameof(q)); Guard.NotNull(q, nameof(q));
using (Profiler.TraceMethod<ContentQueryParser>()) using (Telemetry.Activities.StartMethod<ContentQueryParser>())
{ {
var query = await ParseClrQueryAsync(context, q, schema); 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;
using Squidex.Infrastructure.Security; using Squidex.Infrastructure.Security;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Log;
using Squidex.Shared; using Squidex.Shared;
using Squidex.Shared.Identity; using Squidex.Shared.Identity;
@ -53,7 +52,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{ {
Guard.NotNull(context, nameof(context)); Guard.NotNull(context, nameof(context));
using (Profiler.TraceMethod<ContentQueryService>()) using (Telemetry.Activities.StartMethod<ContentQueryService>())
{ {
var schema = await GetSchemaOrThrowAsync(context, schemaIdOrName); var schema = await GetSchemaOrThrowAsync(context, schemaIdOrName);
@ -82,7 +81,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{ {
Guard.NotNull(context, nameof(context)); Guard.NotNull(context, nameof(context));
using (Profiler.TraceMethod<ContentQueryService>()) using (Telemetry.Activities.StartMethod<ContentQueryService>())
{ {
if (q == null) if (q == null)
{ {
@ -114,7 +113,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{ {
Guard.NotNull(context, nameof(context)); Guard.NotNull(context, nameof(context));
using (Profiler.TraceMethod<ContentQueryService>()) using (Telemetry.Activities.StartMethod<ContentQueryService>())
{ {
if (q == null) 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, private async Task<IReadOnlyList<IEnrichedContentEntity>> TransformCoreAsync(Context context, IEnumerable<IContentEntity> contents,
CancellationToken ct) CancellationToken ct)
{ {
using (Profiler.TraceMethod<ContentQueryService>()) using (Telemetry.Activities.StartMethod<ContentQueryService>())
{ {
return await contentEnricher.EnrichAsync(contents, context, ct); 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.Domain.Apps.Entities.Rules.DomainObject;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Commands;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Rules.Indexes 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) public async Task<List<IRuleEntity>> GetRulesAsync(DomainId appId)
{ {
using (Profiler.TraceMethod<RulesIndex>()) using (Telemetry.Activities.StartMethod<RulesIndex>())
{ {
var ids = await GetRuleIdsAsync(appId); var ids = await GetRuleIdsAsync(appId);
@ -47,7 +46,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Indexes
private async Task<List<DomainId>> GetRuleIdsAsync(DomainId appId) private async Task<List<DomainId>> GetRuleIdsAsync(DomainId appId)
{ {
using (Profiler.TraceMethod<RulesIndex>()) using (Telemetry.Activities.StartMethod<RulesIndex>())
{ {
return await Index(appId).GetIdsAsync(); 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;
using Squidex.Infrastructure.Caching; using Squidex.Infrastructure.Caching;
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Rules.Queries 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(rules, nameof(rules));
Guard.NotNull(context, nameof(context)); Guard.NotNull(context, nameof(context));
using (Profiler.TraceMethod<RuleEnricher>()) using (Telemetry.Activities.StartMethod<RuleEnricher>())
{ {
var results = new List<RuleEntity>(); 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.Commands;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
using Squidex.Log;
using Squidex.Text; using Squidex.Text;
namespace Squidex.Domain.Apps.Entities.Schemas.Indexes 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) public async Task<List<ISchemaEntity>> GetSchemasAsync(DomainId appId)
{ {
using (Profiler.TraceMethod<SchemasIndex>()) using (Telemetry.Activities.StartMethod<SchemasIndex>())
{ {
var ids = await GetSchemaIdsAsync(appId); 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) 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); 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) 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); 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) private async Task<DomainId> GetSchemaIdAsync(DomainId appId, string name)
{ {
using (Profiler.TraceMethod<SchemasIndex>()) using (Telemetry.Activities.StartMethod<SchemasIndex>())
{ {
return await Index(appId).GetIdAsync(name); 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) private async Task<List<DomainId>> GetSchemaIdsAsync(DomainId appId)
{ {
using (Profiler.TraceMethod<SchemasIndex>()) using (Telemetry.Activities.StartMethod<SchemasIndex>())
{ {
return await Index(appId).GetIdsAsync(); return await Index(appId).GetIdsAsync();
} }

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

@ -18,7 +18,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="CsvHelper" Version="27.1.1" /> <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="Equals.Fody" Version="4.0.1" PrivateAssets="all" />
<PackageReference Include="Fody" Version="6.5.2"> <PackageReference Include="Fody" Version="6.5.2">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>

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

@ -19,7 +19,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" /> <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="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" /> <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.Security.Principal.Windows" Version="5.0.0" /> <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>
<ItemGroup> <ItemGroup>
<PackageReference Include="IdentityModel" Version="5.1.0" /> <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="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="OpenIddict.AspNetCore" Version="3.1.0" /> <PackageReference Include="OpenIddict.AspNetCore" Version="3.1.0" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" /> <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 MongoDB.Driver;
using NodaTime; using NodaTime;
using Squidex.Infrastructure.MongoDb; using Squidex.Infrastructure.MongoDb;
using Squidex.Log;
using EventFilter = MongoDB.Driver.FilterDefinition<Squidex.Infrastructure.EventSourcing.MongoEventCommit>; using EventFilter = MongoDB.Driver.FilterDefinition<Squidex.Infrastructure.EventSourcing.MongoEventCommit>;
namespace Squidex.Infrastructure.EventSourcing namespace Squidex.Infrastructure.EventSourcing
@ -48,7 +47,7 @@ namespace Squidex.Infrastructure.EventSourcing
return EmptyEvents; return EmptyEvents;
} }
using (Profiler.TraceMethod<MongoEventStore>()) using (Telemetry.Activities.StartMethod<MongoEventStore>())
{ {
var commits = var commits =
await Collection.Find( await Collection.Find(
@ -65,7 +64,7 @@ namespace Squidex.Infrastructure.EventSourcing
{ {
Guard.NotNullOrEmpty(streamName, nameof(streamName)); Guard.NotNullOrEmpty(streamName, nameof(streamName));
using (Profiler.TraceMethod<MongoEventStore>()) using (Telemetry.Activities.StartMethod<MongoEventStore>())
{ {
var commits = var commits =
await Collection.Find( await Collection.Find(
@ -84,7 +83,7 @@ namespace Squidex.Infrastructure.EventSourcing
{ {
Guard.NotNull(streamNames, nameof(streamNames)); Guard.NotNull(streamNames, nameof(streamNames));
using (Profiler.TraceMethod<MongoEventStore>()) using (Telemetry.Activities.StartMethod<MongoEventStore>())
{ {
var position = EtagVersion.Empty; 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 System.Threading.Tasks;
using MongoDB.Bson; using MongoDB.Bson;
using MongoDB.Driver; using MongoDB.Driver;
using Squidex.Log;
namespace Squidex.Infrastructure.EventSourcing namespace Squidex.Infrastructure.EventSourcing
{ {
@ -40,7 +39,7 @@ namespace Squidex.Infrastructure.EventSourcing
Guard.LessThan(events.Count, MaxCommitSize, "events.Count"); Guard.LessThan(events.Count, MaxCommitSize, "events.Count");
Guard.GreaterEquals(expectedVersion, EtagVersion.Any, nameof(expectedVersion)); Guard.GreaterEquals(expectedVersion, EtagVersion.Any, nameof(expectedVersion));
using (Profiler.TraceMethod<MongoEventStore>()) using (Telemetry.Activities.StartMethod<MongoEventStore>())
{ {
if (events.Count == 0) if (events.Count == 0)
{ {
@ -102,7 +101,7 @@ namespace Squidex.Infrastructure.EventSourcing
{ {
Guard.NotNull(commits, nameof(commits)); Guard.NotNull(commits, nameof(commits));
using (Profiler.TraceMethod<MongoEventStore>()) using (Telemetry.Activities.StartMethod<MongoEventStore>())
{ {
var writes = new List<WriteModel<MongoEventCommit>>(); 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" /> <ProjectReference Include="..\Squidex.Infrastructure\Squidex.Infrastructure.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MongoDB.Driver" Version="2.12.4" /> <PackageReference Include="MongoDB.Driver" Version="2.13.1" />
<PackageReference Include="MongoDB.Driver.GridFS" Version="2.12.4" /> <PackageReference Include="MongoDB.Driver.GridFS" Version="2.13.1" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" /> <PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" /> <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.Threading.Tasks.Dataflow" Version="5.0.0" /> <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 MongoDB.Driver;
using Newtonsoft.Json; using Newtonsoft.Json;
using Squidex.Infrastructure.MongoDb; using Squidex.Infrastructure.MongoDb;
using Squidex.Log;
namespace Squidex.Infrastructure.States namespace Squidex.Infrastructure.States
{ {
@ -45,7 +44,7 @@ namespace Squidex.Infrastructure.States
public async Task<(T Value, bool Valid, long Version)> ReadAsync(DomainId key) 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 = var existing =
await Collection.Find(x => x.DocumentId.Equals(key)) 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) 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)); 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) 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>>( var writes = snapshots.Select(x => new ReplaceOneModel<MongoState<T>>(
Filter.Eq(y => y.DocumentId, x.Key), Filter.Eq(y => y.DocumentId, x.Key),
@ -96,7 +95,7 @@ namespace Squidex.Infrastructure.States
public async Task ReadAllAsync(Func<T, long, Task> callback, public async Task ReadAllAsync(Func<T, long, Task> callback,
CancellationToken ct = default) 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); 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) 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)); 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.Concurrency;
using Orleans.Serialization; using Orleans.Serialization;
using Squidex.Infrastructure.Json; using Squidex.Infrastructure.Json;
using Squidex.Log;
#pragma warning disable IDE0060 // Remove unused parameter #pragma warning disable IDE0060 // Remove unused parameter
@ -57,7 +56,7 @@ namespace Squidex.Infrastructure.Orleans
[SerializerMethod] [SerializerMethod]
public static void Serialize(object? input, ISerializationContext context, Type? expected) 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); var jsonSerializer = GetSerializer(context);
@ -70,7 +69,7 @@ namespace Squidex.Infrastructure.Orleans
[DeserializerMethod] [DeserializerMethod]
public static object? Deserialize(Type expected, IDeserializationContext context) public static object? Deserialize(Type expected, IDeserializationContext context)
{ {
using (Profiler.TraceMethod(nameof(J))) using (Telemetry.Activities.StartMethod(nameof(J)))
{ {
var jsonSerializer = GetSerializer(context); var jsonSerializer = GetSerializer(context);

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

@ -10,11 +10,11 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="GeoJSON.Net" Version="1.2.19" /> <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="McMaster.NETCore.Plugins" Version="1.4.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="5.0.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.Extensions.Diagnostics.HealthChecks.Abstractions" Version="5.0.9" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.1.2" /> <PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.1.3" />
<PackageReference Include="Microsoft.OData.Core" Version="7.9.0" /> <PackageReference Include="Microsoft.OData.Core" Version="7.9.0" />
<PackageReference Include="Microsoft.Orleans.CodeGenerator.MSBuild" Version="3.4.3"> <PackageReference Include="Microsoft.Orleans.CodeGenerator.MSBuild" Version="3.4.3">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
@ -23,12 +23,12 @@
<PackageReference Include="Microsoft.Orleans.Core" Version="3.4.3" /> <PackageReference Include="Microsoft.Orleans.Core" Version="3.4.3" />
<PackageReference Include="Microsoft.Orleans.OrleansRuntime" Version="3.4.3" /> <PackageReference Include="Microsoft.Orleans.OrleansRuntime" Version="3.4.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <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="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="Squidex.Assets" Version="1.8.0" /> <PackageReference Include="Squidex.Assets" Version="1.8.0" />
<PackageReference Include="Squidex.Caching" Version="1.8.0" /> <PackageReference Include="Squidex.Caching" Version="1.8.0" />
<PackageReference Include="Squidex.Hosting.Abstractions" Version="1.9.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="Squidex.Text" Version="1.7.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" /> <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.Collections.Immutable" Version="5.0.0" /> <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 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); 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 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); 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;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
using Squidex.Domain.Apps.Entities.Apps.Plans; using Squidex.Domain.Apps.Entities.Apps.Plans;
using Squidex.Infrastructure;
using Squidex.Log; using Squidex.Log;
namespace Squidex.Web.Pipeline namespace Squidex.Web.Pipeline
@ -48,7 +49,7 @@ namespace Squidex.Web.Pipeline
{ {
if (FilterDefinition.Costs > 0) if (FilterDefinition.Costs > 0)
{ {
using (Profiler.Trace("CheckUsage")) using (Telemetry.Activities.StartActivity("CheckUsage"))
{ {
var (_, clientId) = context.HttpContext.User.GetClient(); 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)) if (hasDependency && !response.Headers.ContainsKey(HeaderNames.ETag))
{ {
using (Profiler.Trace("CalculateEtag")) using (Telemetry.Activities.StartActivity("CalculateEtag"))
{ {
var cacheBuffer = hasher.GetHashAndReset(); var cacheBuffer = hasher.GetHashAndReset();
var cacheString = BitConverter.ToString(cacheBuffer).Replace("-", string.Empty).ToUpperInvariant(); 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 System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
using Squidex.Log; using Squidex.Infrastructure;
namespace Squidex.Web.Pipeline namespace Squidex.Web.Pipeline
{ {
@ -15,7 +15,7 @@ namespace Squidex.Web.Pipeline
{ {
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{ {
using (Profiler.Trace("ExecuteAction")) using (Telemetry.Activities.StartActivity("ExecuteAction"))
{ {
await next(); await next();
} }
@ -23,7 +23,7 @@ namespace Squidex.Web.Pipeline
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{ {
using (Profiler.Trace("ExecuteResult")) using (Telemetry.Activities.StartActivity("ExecuteResult"))
{ {
await next(); await next();
} }

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

@ -10,7 +10,5 @@ namespace Squidex.Web.Pipeline
public sealed class RequestLogOptions public sealed class RequestLogOptions
{ {
public bool LogRequests { get; set; } 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) public async Task InvokeAsync(HttpContext context, ISemanticLog log)
{ {
var shouldStartSession = requestLogOptions.LogRequests || Profiler.HasListener; if (requestLogOptions.LogRequests)
if (requestLogOptions.LogRequests || shouldStartSession)
{ {
var session = var watch = ValueStopwatch.StartNew();
shouldStartSession ?
Profiler.StartSession() :
default;
var watch =
requestLogOptions.LogRequests ?
ValueStopwatch.StartNew() :
default;
using (session)
{
try try
{ {
await next(context); await next(context);
} }
finally finally
{
if (requestLogOptions.LogRequests)
{ {
var elapsedMs = watch.Stop(); var elapsedMs = watch.Stop();
log.LogInformation((elapsedMs, context), (ctx, w) => log.LogInformation((elapsedMs, context), (ctx, w) =>
{ {
if (requestLogOptions.LogProfiler)
{
Profiler.Session?.Write(w);
}
w.WriteObject("filters", ctx.context, LogFilters); w.WriteObject("filters", ctx.context, LogFilters);
w.WriteProperty("elapsedRequestMs", ctx.elapsedMs); w.WriteProperty("elapsedRequestMs", ctx.elapsedMs);
}); });
} }
} }
}
}
else else
{ {
await next(context); await next(context);
} }
} }
private static void LogFilters(HttpContext httpContext, IObjectWriter c) private static void LogFilters(HttpContext httpContext, IObjectWriter obj)
{ {
var app = httpContext.Context().App; var app = httpContext.Context().App;
if (app != null) if (app != null)
{ {
c.WriteProperty("appId", app.Id.ToString()); obj.WriteProperty("appId", app.Id.ToString());
c.WriteProperty("appName", app.Name); obj.WriteProperty("appName", app.Name);
} }
var userId = httpContext.User.OpenIdSubject(); var userId = httpContext.User.OpenIdSubject();
if (!string.IsNullOrWhiteSpace(userId)) if (!string.IsNullOrWhiteSpace(userId))
{ {
c.WriteProperty(nameof(userId), userId); obj.WriteProperty(nameof(userId), userId);
} }
var clientId = httpContext.User.OpenIdClientId(); var clientId = httpContext.User.OpenIdClientId();
if (!string.IsNullOrWhiteSpace(clientId)) if (!string.IsNullOrWhiteSpace(clientId))
{ {
c.WriteProperty(nameof(clientId), clientId); obj.WriteProperty(nameof(clientId), clientId);
} }
var costs = httpContext.Features.Get<IApiCostsFeature>()?.Costs ?? 0; 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;
using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Domain.Apps.Entities.Apps.Plans; using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.Security; using Squidex.Infrastructure.Security;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
using Squidex.Log;
using Squidex.Shared; using Squidex.Shared;
using Squidex.Web; using Squidex.Web;
@ -267,25 +266,25 @@ namespace Squidex.Areas.Api.Controllers.Apps
} }
catch (AssetNotFoundException) catch (AssetNotFoundException)
{ {
using (Profiler.Trace("Resize")) using (Telemetry.Activities.StartActivity("Resize"))
{ {
using (var sourceStream = GetTempStream()) using (var sourceStream = GetTempStream())
{ {
using (var destinationStream = GetTempStream()) using (var destinationStream = GetTempStream())
{ {
using (Profiler.Trace("ResizeDownload")) using (Telemetry.Activities.StartActivity("ResizeDownload"))
{ {
await appImageStore.DownloadAsync(App.Id, sourceStream); await appImageStore.DownloadAsync(App.Id, sourceStream);
sourceStream.Position = 0; sourceStream.Position = 0;
} }
using (Profiler.Trace("ResizeImage")) using (Telemetry.Activities.StartActivity("ResizeImage"))
{ {
await assetThumbnailGenerator.CreateThumbnailAsync(sourceStream, destinationStream, ResizeOptions); await assetThumbnailGenerator.CreateThumbnailAsync(sourceStream, destinationStream, ResizeOptions);
destinationStream.Position = 0; destinationStream.Position = 0;
} }
using (Profiler.Trace("ResizeUpload")) using (Telemetry.Activities.StartActivity("ResizeUpload"))
{ {
await assetStore.UploadAsync(resizedAsset, destinationStream); await assetStore.UploadAsync(resizedAsset, destinationStream);
destinationStream.Position = 0; 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.Rules;
using Squidex.Areas.Api.Controllers.Schemas; using Squidex.Areas.Api.Controllers.Schemas;
using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Apps.Plans;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Json.Objects;
using Squidex.Infrastructure.Reflection; 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(); var suffix = resizeOptions.ToString();
using (Profiler.Trace("Resize")) using (Telemetry.Activities.StartActivity("Resize"))
{ {
using (var sourceStream = GetTempStream()) using (var sourceStream = GetTempStream())
{ {
using (var destinationStream = 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); await assetFileStore.DownloadAsync(asset.AppId.Id, asset.Id, asset.FileVersion, null, sourceStream);
sourceStream.Position = 0; sourceStream.Position = 0;
} }
using (Profiler.Trace("ResizeImage")) using (Telemetry.Activities.StartActivity("ResizeImage"))
{ {
try try
{ {
@ -231,7 +231,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
try try
{ {
using (Profiler.Trace("ResizeUpload")) using (Telemetry.Activities.StartActivity("ResizeUpload"))
{ {
await assetFileStore.UploadAsync(asset.AppId.Id, asset.Id, asset.FileVersion, suffix, destinationStream, overwrite); await assetFileStore.UploadAsync(asset.AppId.Id, asset.Id, asset.FileVersion, suffix, destinationStream, overwrite);
destinationStream.Position = 0; 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>
<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.DataLoader" Version="4.5.0" />
<PackageReference Include="GraphQL.Server.Core" Version="5.0.2" /> <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.NewtonsoftJson" Version="5.0.2" />
<PackageReference Include="GraphQL.Server.Transports.AspNetCore.SystemTextJson" 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.Google" Version="5.0.9" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.MicrosoftAccount" Version="5.0.7" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.MicrosoftAccount" Version="5.0.9" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="5.0.7" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="5.0.9" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.7" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.9" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="5.0.7" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="5.0.9" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="5.0.0" /> <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="5.0.0" />
<PackageReference Include="Microsoft.CodeAnalysis.RulesetToEditorconfigConverter" Version="3.0.0" /> <PackageReference Include="Microsoft.CodeAnalysis.RulesetToEditorconfigConverter" Version="3.0.0" />
<PackageReference Include="Microsoft.Data.Edm" Version="5.8.4" /> <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.Core.Abstractions" Version="3.4.3" />
<PackageReference Include="Microsoft.Orleans.Hosting.Kubernetes" 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="Microsoft.Orleans.OrleansRuntime" Version="3.4.3" />
<PackageReference Include="MongoDB.Driver" Version="2.12.4" /> <PackageReference Include="MongoDB.Driver" Version="2.13.1" />
<PackageReference Include="Namotion.Reflection" Version="1.0.23" /> <PackageReference Include="Namotion.Reflection" Version="2.0.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <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="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="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="Orleans.Providers.MongoDB" Version="3.3.1" />
<PackageReference Include="OrleansDashboard" Version="3.5.2" /> <PackageReference Include="OrleansDashboard" Version="3.5.2" />
<PackageReference Include="OrleansDashboard.EmbeddedAssets" Version="3.5.2" /> <PackageReference Include="OrleansDashboard.EmbeddedAssets" Version="3.5.2" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" /> <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.Azure" Version="1.8.0" />
<PackageReference Include="Squidex.Assets.GoogleCloud" Version="1.8.0" /> <PackageReference Include="Squidex.Assets.GoogleCloud" Version="1.8.0" />
<PackageReference Include="Squidex.Assets.FTP" 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.AddSquidexSerializers();
services.AddSquidexStoreServices(config); services.AddSquidexStoreServices(config);
services.AddSquidexSubscriptions(config); services.AddSquidexSubscriptions(config);
services.AddSquidexTelemetry();
services.AddSquidexTranslation(config); services.AddSquidexTranslation(config);
services.AddSquidexUsageTracking(config); services.AddSquidexUsageTracking(config);
} }

609
backend/src/Squidex/appsettings.json

@ -1,113 +1,78 @@
{ {
"mode": { "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 "isReadonly": false
}, },
"urls": { "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", "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": "", "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, "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, "enforceHost": false,
/* // A list of known proxies to make forward headers safer.
* A list of known proxies to make forward headers safer.
*/
"knownProxies": [], "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, "enableForwardHeaders": true,
/* // A list of trusted hosts for redirects.
* A list of trusted hosts for redirects.
*/
"trustedHosted": [] "trustedHosted": []
}, },
"fullText": { "fullText": {
/* // Define the type of the full text store.
* Define the type of the full text store. //
* // SUPPORTED: elastic (ElasticSearch), default. Default: default
* Supported: elastic (ElasticSearch). Default: MongoDB
*/
"type": "default", "type": "default",
"elastic": { "elastic": {
/* // he configuration to your elastic search cluster.
* The configuration to your elastic search cluster. //
* // Read More: https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/client-configuration.html
* Read More: https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/client-configuration.html
*/
"configuration": "http://localhost:9200", "configuration": "http://localhost:9200",
/* // The name of the index.
* The name of the index.
*/
"indexName": "squidex" "indexName": "squidex"
} }
}, },
/* // Define optional paths to plugins.
* Define optional paths to plugins.
*/
"plugins": [ "plugins": [
"Squidex.Extensions.dll" "Squidex.Extensions.dll"
], ],
"caching": { "caching": {
/* // Set to true, to use strong etags.
* Set to true, to use strong etags.
*/
"strongETag": false, "strongETag": false,
/* // Restrict the surrogate keys to the number of characters.
* Restrict the surrogate keys to the number of characters.
*/
"maxSurrogateKeysSize": 0, "maxSurrogateKeysSize": 0,
"replicated": { "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 "enable": true
} }
}, },
"languages": { "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": "" "custom": ""
}, },
"rules": { "rules": {
/* // The timeout to execute rule actions.
* The timeout to execute rule actions.
*/
"executionTimeoutInSeconds": 10 "executionTimeoutInSeconds": 10
}, },
"ui": { "ui": {
/* // Regex suggestions for the UI
* Regex suggestions for the UI
*/
"regexSuggestions": { "regexSuggestions": {
// Regex for emails. // Regex for emails.
"Email": "^[a-zA-Z0-9.!#$%&’*+\\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:.[a-zA-Z0-9-]+)*$", "Email": "^[a-zA-Z0-9.!#$%&’*+\\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:.[a-zA-Z0-9-]+)*$",
@ -119,464 +84,318 @@
"Url": "^(?:http(s)?:\\/\\/)?[\\w.-]+(?:\\.[\\w\\.-]+)+[\\w\\-\\._~:\\/?#%[\\]@!\\$&'\\(\\)\\*\\+,;=.]+$" "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, "onlyAdminsCanCreateApps": false,
"map": { "map": {
/* // Define the type of the geolocation service.
* Define the type of the geolocation service. //
* // SUPPORTED: GoogleMaps, OSM
* Supported: GoogleMaps, OSM
*/
"type": "OSM", "type": "OSM",
"googleMaps": { "googleMaps": {
/* // The optional google maps API key. CREATE YOUR OWN PLEASE.
* The optional google maps API key. CREATE YOUR OWN PLEASE.
*/
"key": "AIzaSyB_Z8l3nwUxZhMJykiDUJy6bSHXXlwcYMg" "key": "AIzaSyB_Z8l3nwUxZhMJykiDUJy6bSHXXlwcYMg"
} }
}, },
/* // Redirect to login automatically.
* Redirect to login automatically.
*/
"redirectToLogin": false, "redirectToLogin": false,
/* // Hide the news dialog.
* Hide the news dialog.
*/
"hideNews": false, "hideNews": false,
/* // Hide all onboarding tooltips and dialogs.
* Hide all onboarding tooltips and dialogs.
*/
"hideOnboarding": false, "hideOnboarding": false,
/* // Hide the today and now button.
* Hide the today and now button.
*/
"hideDateButtons": false, "hideDateButtons": false,
/* // Hide the Local/UTC button
* Hide the Local/UTC button
*/
"hideDateTimeModeButton": false, "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, "showInfo": false,
/* // The number of content items for dropdown selector.
* The number of content items for dropdown selector.
*/
"referencesDropdownItemCount": 100, "referencesDropdownItemCount": 100,
"google": { "google": {
/* // The Google analytics ID.
* The Google analytics ID.
*/
"analyticsId": "UA-99989790-2" "analyticsId": "UA-99989790-2"
} }
}, },
"email": { "email": {
"smtp": { "smtp": {
/* // The host name to your email server.
* The host name to your email server.
*/
"server": "", "server": "",
/* // The sender email address.
* The sender email address.
*/
"sender": "hello@squidex.io", "sender": "hello@squidex.io",
/* // The username to authenticate to your email server.
* The username to authenticate to your email server.
*/
"username": "", "username": "",
/* // The password to authenticate to your email server.
* The password to authenticate to your email server.
*/
"password": "", "password": "",
/* // Always use SSL if possible.
* Always use SSL if possible.
*/
"enableSsl": true, "enableSsl": true,
/* // The port to your email server.
* The port to your email server.
*/
"port": 587 "port": 587
}, },
"notifications": { "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", "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]", "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", "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]", "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", "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]" "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": { "notifo": {
/* // The id of the app in notifo.
* The id of the app in notifo.
*/
"appId": "", "appId": "",
/* // The API key for your app in notifo.
* The API key for your app in notifo.
*/
"apiKey": "", "apiKey": "",
/* // The API URL.
* The API URL.
*/
"apiUrl": "https://app.notifo.io" "apiUrl": "https://app.notifo.io"
}, },
"robots": { "robots": {
/* // The text for the robots.txt file
* The text for the robots.txt file
*/
"text": "User-agent: *\nAllow: /api/assets/*" "text": "User-agent: *\nAllow: /api/assets/*"
}, },
"healthz": { "healthz": {
"gc": { "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 "threshold": 4096
} }
}, },
"contents": { "contents": {
/* // The default page size if not specified by a query.
* The default page size if not specified by a query.
*/
"defaultPageSize": 200, "defaultPageSize": 200,
/* // The maximum number of items to return for each query.
* The maximum number of items to return for each query. //
* // Warning: Use pagination and not large number of items.
* Warning: Use pagination and not large number of items.
*/
"maxResults": 200, "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", "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" "timeoutQuery": "00:00:05"
}, },
"assets": { "assets": {
/* // The default page size if not specified by a query.
* The default page size if not specified by a query.
*/
"defaultPageSize": 200, "defaultPageSize": 200,
/* // The maximum number of items to return for each query.
* The maximum number of items to return for each query. //
* // Warning: Use pagination and not large number of items.
* Warning: Use pagination and not large number of items.
*/
"maxResults": 200, "maxResults": 200,
/* // The maximum file size in bytes. Default: 5MB
* The maximum file size in bytes. Default: 5MB
*/
"maxSize": 5242880, "maxSize": 5242880,
/* // True to delete assets recursively.
* True to delete assets recursively.
*/
"deleteRecursive": true, "deleteRecursive": true,
/* // True to delete assets files permanently.
* True to delete assets files permanently.
*/
"deletePermanent": false, "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", "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", "timeoutQuery": "00:00:05",
/* // Create one folder per app.
* Create one folder per app. //
* // WARNING: If you change this parameter, previous assets are not available anymore.
* WARNING: If you change this parameter, previous assets are not available anymore.
*/
"folderPerApp": false "folderPerApp": false
}, },
"logging": { "logging": {
/* // The log level.
* The log level. //
* // Trace, Debug, Information, Warning, Error, Fatal
* Trace, Debug, Information, Warning, Error, Fatal
*/
"level": "Information", "level": "Information",
/* // Setting the flag to true, enables well formatteds json logs.
* Setting the flag to true, enables well formatteds json logs.
*/
"human": true, "human": true,
/* // Set to true, to use colors.
* Set to true, to use colors.
*/
"colors": true, "colors": true,
/* // Set to false to disable logging of http requests.
* Set to false to disable logging of http requests.
*/
"logRequests": true, "logRequests": true,
/* // False to disable the log store.
* Set to true to enable logging of profiler information.
*/
"logProfiler": false,
/*
* False to disable the log store.
*/
"storeEnabled": true, "storeEnabled": true,
/* // The number of days request log items will be stored.
* The number of days request log items will be stored.
*/
"storeRetentationInDays": 90, "storeRetentationInDays": 90,
/* "stackdriver": {
* True, to enable datadog integration. // True, to enable stackdriver integration.
*/ "enabled": false
"datadog": 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,
/* "connectionString": "InstrumentationKey=[key];IngestionEndpoint=https://[datacenter].in.applicationinsights.azure.com/"
* True, to enable application insights integraon. }
*/
"applicationInsights": false
}, },
"assetStore": { "assetStore": {
/* // Define the type of the read store.
* Define the type of the read store. //
* // SUPPORTED: Folder (local folder), MongoDb (GridFS), GoogleCloud (hosted in Google Cloud only), AzureBlob, AmazonS3, FTP (not recommended).
* Supported: Folder (local folder), MongoDb (GridFS), GoogleCloud (hosted in Google Cloud only), AzureBlob, AmazonS3, FTP (not recommended).
*/
"type": "Folder", "type": "Folder",
"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" "path": "Assets"
}, },
"googleCloud": { "googleCloud": {
/* // The name of the bucket in google cloud store.
* The name of the bucket in google cloud store.
*/
"bucket": "squidex-assets" "bucket": "squidex-assets"
}, },
"azureBlob": { "azureBlob": {
/* // The name of the container in the Azure Blob Storage
* The name of the container in the Azure Blob Storage
*/
"containerName": "squidex-assets", "containerName": "squidex-assets",
/* // The connection string to the azure storage service.
* The connection string to the azure storage service.
*/
"connectionString": "UseDevelopmentStorage=true" "connectionString": "UseDevelopmentStorage=true"
}, },
"AmazonS3": { "amazonS3": {
/* // The url of the S3 API service. Leave it empty if using the one provided by Amazon
* The url of the S3 API service. Leave it empty if using the one provided by Amazon
*/
"serviceUrl": "", "serviceUrl": "",
/* // The name of your bucket.
* The name of your bucket.
*/
"bucket": "squidex-test", "bucket": "squidex-test",
/* // The optional folder within the bucket.
* The optional folder within the bucket.
*/
"bucketFolder": "squidex-assets", "bucketFolder": "squidex-assets",
/* // The region name of your bucket.
* The region name of your bucket.
*/
"regionName": "eu-central-1", "regionName": "eu-central-1",
/* // The access key for your user.
* The access key for your user. //
* // Read More: https://supsystic.com/documentation/id-secret-access-key-amazon-s3/
* Read More: https://supsystic.com/documentation/id-secret-access-key-amazon-s3/
*/
"accessKey": "<MY_KEY>", "accessKey": "<MY_KEY>",
/* // The secret key for your user.
* The secret key for your user. //
* // Read More: https://supsystic.com/documentation/id-secret-access-key-amazon-s3/
* Read More: https://supsystic.com/documentation/id-secret-access-key-amazon-s3/
*/
"secretKey": "<MY_SECRET>", "secretKey": "<MY_SECRET>",
/* // Force path style property for AmazonS3Config
* Force path style property for AmazonS3Config
*/
"forcePathStyle": false "forcePathStyle": false
}, },
"mongoDb": { "mongoDb": {
/* // The connection string to your Mongo Server.
* The connection string to your Mongo Server. //
* // Read More: https://docs.mongodb.com/manual/reference/connection-string/
* Read More: https://docs.mongodb.com/manual/reference/connection-string/
*/
"configuration": "mongodb://localhost", "configuration": "mongodb://localhost",
/* // The name of the event store database.
* The name of the event store database.
*/
"database": "SquidexAssets", "database": "SquidexAssets",
/* // The name of the Mongo Grid FS bucket.
* The name of the Mongo Grid FS bucket.
*/
"bucket": "fs" "bucket": "fs"
}, },
"ftp": { "ftp": {
/* //The host of the ftp service
*The host of the ftp service
*/
"serverHost": "", "serverHost": "",
/* //The host of the ftp service
*The host of the ftp service
*/
"serverPort": "21", "serverPort": "21",
/* // Credentials.
* Credentials.
*/
"username": "", "username": "",
"password": "", "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" "path": "Assets"
}, },
/* // Allow to expose the url in graph ql url.
* Allow to expose the url in graph ql url.
*/
"exposeSourceUrl": false "exposeSourceUrl": false
}, },
"orleans": { "orleans": {
/* // Define the clustering type.
* Define the clustering type. //
* // SUPPORTED: MongoDB, Development
* Supported: MongoDB, Development
*/
"clustering": "Development", "clustering": "Development",
/* // Tell Orleans it is running in kubernetes.
* Tell Orleans it is running in kubernetes. //
* // Read more: https://dotnet.github.io/orleans/docs/deployment/kubernetes.html?q=kubernetes
* Read more: https://dotnet.github.io/orleans/docs/deployment/kubernetes.html?q=kubernetes
*/
"kubernetes": false, "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", "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", "gatewayPort": "40000",
/* // The advertised IP address. Usually not needed.
* The advertised IP address. Usually not needed.
*/
"ipAddress": "" "ipAddress": ""
}, },
"eventStore": { "eventStore": {
/* // Define the type of the event store.
* Define the type of the event store. //
* // SUPPORTED: MongoDb
* Supported: MongoDb
*/
"type": "MongoDb", "type": "MongoDb",
"mongoDb": { "mongoDb": {
/* // The connection string to your Mongo Server.
* The connection string to your Mongo Server. //
* // Read More: https://docs.mongodb.com/manual/reference/connection-string/
* Read More: https://docs.mongodb.com/manual/reference/connection-string/
*/
"configuration": "mongodb://localhost", "configuration": "mongodb://localhost",
/* // The name of the event store database.
* The name of the event store database.
*/
"database": "Squidex" "database": "Squidex"
} }
}, },
"eventPublishers": { "eventPublishers": {
/* // Additional event publishers (advanced usage only): (Name => Config)
* Additional event publishers (advanced usage only): (Name => Config)
*/
"allToRabbitMq": { "allToRabbitMq": {
/* // Example:: Push all events to RabbitMq.
* Example:: Push all events to RabbitMq.
*/
"type": "RabbitMq", "type": "RabbitMq",
"configuration": "amqp://guest:guest@localhost/", "configuration": "amqp://guest:guest@localhost/",
"exchange": "squidex", "exchange": "squidex",
@ -586,88 +405,62 @@
}, },
"store": { "store": {
/* // Define the type of the read store.
* Define the type of the read store. //
* // SUPPORTED: MongoDb
* Supported: MongoDb
*/
"type": "MongoDb", "type": "MongoDb",
"mongoDb": { "mongoDb": {
/* // The connection string to your Mongo Server.
* The connection string to your Mongo Server. //
* // Read More: https://docs.mongodb.com/manual/reference/connection-string/
* Read More: https://docs.mongodb.com/manual/reference/connection-string/
*/
"configuration": "mongodb://localhost", "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", "contentDatabase": "SquidexContent",
/* // The database for all your other read collections.
* The database for all your other read collections.
*/
"database": "Squidex" "database": "Squidex"
} }
}, },
"identity": { "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, "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, "allowPasswordAuth": true,
/* // Initial admin user.
* Initial admin user.
*/
"adminEmail": "", "adminEmail": "",
"adminPassword": "", "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, "adminRecreate": false,
/* // Client with all admin permissions.
* Client with all admin permissions.
*/
"adminClientId": "", "adminClientId": "",
"adminClientSecret": "", "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": [], "adminApps": [],
/* // Settings for Google auth (keep empty to disable).
* Settings for Google auth (keep empty to disable).
*/
"googleClient": "1006817248705-t3lb3ge808m9am4t7upqth79hulk456l.apps.googleusercontent.com", "googleClient": "1006817248705-t3lb3ge808m9am4t7upqth79hulk456l.apps.googleusercontent.com",
"googleSecret": "QsEi-fHqkGw2_PjJmtNHf2wg", "googleSecret": "QsEi-fHqkGw2_PjJmtNHf2wg",
/* // Settings for Github auth (keep empty to disable).
* Settings for Github auth (keep empty to disable).
*/
"githubClient": "211ea00e726baf754c78", "githubClient": "211ea00e726baf754c78",
"githubSecret": "d0a0d0fe2c26469ae20987ac265b3a339fd73132", "githubSecret": "d0a0d0fe2c26469ae20987ac265b3a339fd73132",
/* // Settings for Microsoft auth (keep empty to disable).3
* Settings for Microsoft auth (keep empty to disable). //
* Tennant is optional for using a specific AzureAD tenant // NOTE: Tennant is optional for using a specific AzureAD tenant
*/
"microsoftClient": "b55da740-6648-4502-8746-b9003f29d5f1", "microsoftClient": "b55da740-6648-4502-8746-b9003f29d5f1",
"microsoftSecret": "idWbANxNYEF4cB368WXJhjN", "microsoftSecret": "idWbANxNYEF4cB368WXJhjN",
"microsoftTenant": null, "microsoftTenant": null,
/* // Settings for your custom oidc server.
* Settings for your custom oidc server.
*/
"oidcName": "OIDC", "oidcName": "OIDC",
"oidcAuthority": "", "oidcAuthority": "",
"oidcClient": "", "oidcClient": "",
@ -680,35 +473,25 @@
"oidcGetClaimsFromUserInfoEndpoint": false, "oidcGetClaimsFromUserInfoEndpoint": false,
"oidcOnSignoutRedirectUrl": "", "oidcOnSignoutRedirectUrl": "",
/* // Lock new users automatically, the administrator must unlock them.
* Lock new users automatically, the administrator must unlock them.
*/
"lockAutomatically": false, "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" "privacyUrl": "https://squidex.io/privacy"
}, },
"news": { "news": {
/* // The app name where the news are stored.
* The app name where the news are stored.
*/
"appName": "squidex-website", "appName": "squidex-website",
/* // The credentials to the app (Readonly).
* The credentials to the app (Readonly).
*/
"clientId": "squidex-website:default", "clientId": "squidex-website:default",
"clientSecret": "QGgqxd7bDHBTEkpC6fj8sbdPWgZrPrPfr3xzb3LKoec=" "clientSecret": "QGgqxd7bDHBTEkpC6fj8sbdPWgZrPrPfr3xzb3LKoec="
}, },
"translations": { "translations": {
"deepl": { "deepl": {
/* // The deepl api key if you want to support automated translations.
* The deepl api key if you want to support automated translations.
*/
"authKey": "", "authKey": "",
"mapping": { "mapping": {
"zh-TW": "zh-TW", "zh-TW": "zh-TW",
@ -717,67 +500,45 @@
}, },
"googleCloud": { "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": "" "projectId": ""
} }
}, },
"rebuild": { "rebuild": {
/* // Set to true to rebuild apps.
* Set to true to rebuild apps.
*/
"apps": false, "apps": false,
/* // Set to true to rebuild assets.
* Set to true to rebuild assets.
*/
"assets": false, "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, "assetFiles": false,
/* // Set to true to rebuild contents.
* Set to true to rebuild contents.
*/
"contents": false, "contents": false,
/* // Set to true to rebuild rules.
* Set to true to rebuild rules.
*/
"rules": false, "rules": false,
/* // Set to true to rebuild schemas.
* Set to true to rebuild schemas.
*/
"schemas": false, "schemas": false,
/* // Set to true to rebuild indexes.
* Set to true to rebuild indexes.
*/
"indexes": false "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": { "exposedConfiguration": {
"version": "squidex:version" "version": "squidex:version"
}, },
/* // Kafka Producer configuration
* Kafka Producer configuration
*/
"kafka": { "kafka": {
"bootstrapServers": "" "bootstrapServers": ""
}, },
/* // The client information for twitter.
* The client information for twitter.
*/
"twitter": { "twitter": {
"clientId": "QZhb3HQcGCvE6G8yNNP9ksNet", "clientId": "QZhb3HQcGCvE6G8yNNP9ksNet",
"clientSecret": "Pdu9wdN72T33KJRFdFy1w4urBKDRzIyuKpc0OItQC2E616DuZD" "clientSecret": "Pdu9wdN72T33KJRFdFy1w4urBKDRzIyuKpc0OItQC2E616DuZD"

Loading…
Cancel
Save