Browse Source

Refactoring/logs (#842)

* Tus simplified.

* Update package.

* Refactored logging.

* Get rid of using.
pull/843/head
Sebastian Stehle 4 years ago
committed by GitHub
parent
commit
5990416301
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 36
      backend/extensions/Squidex.Extensions/Actions/Kafka/KafkaProducer.cs
  2. 11
      backend/extensions/Squidex.Extensions/Assets/Azure/AzureMetadataSource.cs
  3. 7
      backend/i18n/frontend_en.json
  4. 7
      backend/i18n/frontend_it.json
  5. 7
      backend/i18n/frontend_nl.json
  6. 5
      backend/i18n/frontend_zh.json
  7. 2
      backend/i18n/source/backend_en.json
  8. 7
      backend/i18n/source/frontend_en.json
  9. 2
      backend/i18n/source/frontend_nl.json
  10. 2
      backend/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldCollection.cs
  11. 14
      backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleService.cs
  12. 1
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Internal/Parser.cs
  13. 7
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs
  14. 11
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/AggregateValidator.cs
  15. 8
      backend/src/Squidex.Domain.Apps.Entities/Apps/DomainObject/AppDomainObject.cs
  16. 19
      backend/src/Squidex.Domain.Apps.Entities/Apps/Invitation/InvitationEventConsumer.cs
  17. 1
      backend/src/Squidex.Domain.Apps.Entities/Assets/AssetsFluidExtension.cs
  18. 4
      backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetDomainObject.cs
  19. 4
      backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetFolderDomainObject.cs
  20. 22
      backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetsBulkUpdateCommandMiddleware.cs
  21. 1
      backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetQueryParser.cs
  22. 11
      backend/src/Squidex.Domain.Apps.Entities/Assets/RecursiveDeleter.cs
  23. 24
      backend/src/Squidex.Domain.Apps.Entities/Backup/BackupGrain.cs
  24. 44
      backend/src/Squidex.Domain.Apps.Entities/Backup/RestoreGrain.cs
  25. 11
      backend/src/Squidex.Domain.Apps.Entities/Contents/ContentSchedulerGrain.cs
  26. 4
      backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs
  27. 23
      backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentsBulkUpdateCommandMiddleware.cs
  28. 4
      backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/ValidationExtensions.cs
  29. 14
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Resolvers.cs
  30. 1
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryParser.cs
  31. 26
      backend/src/Squidex.Domain.Apps.Entities/FodyWeavers.xsd
  32. 24
      backend/src/Squidex.Domain.Apps.Entities/History/NotifoService.cs
  33. 23
      backend/src/Squidex.Domain.Apps.Entities/Notifications/NotificationEmailSender.cs
  34. 4
      backend/src/Squidex.Domain.Apps.Entities/Rules/DomainObject/RuleDomainObject.cs
  35. 25
      backend/src/Squidex.Domain.Apps.Entities/Rules/RuleDequeuerGrain.cs
  36. 19
      backend/src/Squidex.Domain.Apps.Entities/Rules/Runner/RuleRunnerGrain.cs
  37. 4
      backend/src/Squidex.Domain.Apps.Entities/Schemas/DomainObject/SchemaDomainObject.cs
  38. 2
      backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasIndex.cs
  39. 12
      backend/src/Squidex.Domain.Apps.Entities/Search/SearchManager.cs
  40. 10
      backend/src/Squidex.Domain.Users/DefaultUserService.cs
  41. 11
      backend/src/Squidex.Domain.Users/UserManagerExtensions.cs
  42. 3
      backend/src/Squidex.Infrastructure.GetEventStore/EventSourcing/GetEventStoreSubscription.cs
  43. 2
      backend/src/Squidex.Infrastructure.MongoDb/MongoDb/Queries/FilterBuilder.cs
  44. 23
      backend/src/Squidex.Infrastructure/Commands/DomainObject.cs
  45. 49
      backend/src/Squidex.Infrastructure/Commands/LogCommandMiddleware.cs
  46. 14
      backend/src/Squidex.Infrastructure/Commands/Rebuilder.cs
  47. 41
      backend/src/Squidex.Infrastructure/EventSourcing/Grains/EventConsumerGrain.cs
  48. 10
      backend/src/Squidex.Infrastructure/Log/BackgroundRequestLogStore.cs
  49. 33
      backend/src/Squidex.Infrastructure/Migrations/Migrator.cs
  50. 16
      backend/src/Squidex.Infrastructure/Orleans/LoggingFilter.cs
  51. 1
      backend/src/Squidex.Infrastructure/Plugins/PluginManager.cs
  52. 11
      backend/src/Squidex.Infrastructure/UsageTracking/BackgroundUsageTracker.cs
  53. 6
      backend/src/Squidex.Shared/Texts.it.resx
  54. 6
      backend/src/Squidex.Shared/Texts.nl.resx
  55. 6
      backend/src/Squidex.Shared/Texts.resx
  56. 6
      backend/src/Squidex.Shared/Texts.zh.resx
  57. 7
      backend/src/Squidex.Web/ApiExceptionFilterAttribute.cs
  58. 18
      backend/src/Squidex.Web/Pipeline/AppResolver.cs
  59. 9
      backend/src/Squidex.Web/Pipeline/RequestExceptionMiddleware.cs
  60. 3
      backend/src/Squidex.Web/Pipeline/RequestLogPerformanceMiddleware.cs
  61. 9
      backend/src/Squidex.Web/Pipeline/UsageMiddleware.cs
  62. 17
      backend/src/Squidex/Areas/Api/Controllers/Users/UsersController.cs
  63. 7
      backend/src/Squidex/Areas/IdentityServer/Config/CreateAdminInitializer.cs
  64. 2
      backend/src/Squidex/Areas/IdentityServer/Controllers/Account/AccountController.cs
  65. 1
      backend/src/Squidex/Config/Domain/InfrastructureServices.cs
  66. 4
      backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleServiceTests.cs
  67. 17
      backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ValidationTestExtensions.cs
  68. 4
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DefaultAppImageStoreTests.cs
  69. 10
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppDomainObjectTests.cs
  70. 6
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InvitationEventConsumerTests.cs
  71. 4
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetDomainObjectTests.cs
  72. 4
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetFolderDomainObjectTests.cs
  73. 6
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetsBulkUpdateCommandMiddlewareTests.cs
  74. 6
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/RecursiveDeleterTests.cs
  75. 6
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentSchedulerGrainTests.cs
  76. 5
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentDomainObjectTests.cs
  77. 6
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentsBulkUpdateCommandMiddlewareTests.cs
  78. 5
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs
  79. 1
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/MongoTextIndexTests.cs
  80. 6
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Notifications/NotificationEmailSenderTests.cs
  81. 6
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/RuleDomainObjectTests.cs
  82. 12
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleDequeuerGrainTests.cs
  83. 6
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/DomainObject/SchemaDomainObjectTests.cs
  84. 6
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Search/SearchManagerTests.cs
  85. 4
      backend/tests/Squidex.Domain.Users.Tests/DefaultUserPictureStoreTests.cs
  86. 6
      backend/tests/Squidex.Domain.Users.Tests/DefaultUserServiceTests.cs
  87. 70
      backend/tests/Squidex.Infrastructure.Tests/Commands/LogCommandMiddlewareTests.cs
  88. 7
      backend/tests/Squidex.Infrastructure.Tests/EventSourcing/Grains/EventConsumerGrainTests.cs
  89. 6
      backend/tests/Squidex.Infrastructure.Tests/EventSourcing/MongoParallelInsertTests.cs
  90. 6
      backend/tests/Squidex.Infrastructure.Tests/Log/BackgroundRequestLogStoreTests.cs
  91. 6
      backend/tests/Squidex.Infrastructure.Tests/Migrations/MigratorTests.cs
  92. 23
      backend/tests/Squidex.Infrastructure.Tests/Orleans/LoggingFilterTests.cs
  93. 4
      backend/tests/Squidex.Infrastructure.Tests/TestHelpers/MyDomainObject.cs
  94. 5
      backend/tests/Squidex.Infrastructure.Tests/UsageTracking/BackgroundUsageTrackerTests.cs
  95. 30
      backend/tests/Squidex.Web.Tests/ApiExceptionFilterAttributeTests.cs
  96. 6
      backend/tests/Squidex.Web.Tests/Pipeline/RequestExceptionMiddlewareTests.cs
  97. 2
      frontend/src/app/features/schemas/pages/schema/fields/types/assets-validation.component.html

36
backend/extensions/Squidex.Extensions/Actions/Kafka/KafkaProducer.cs

@ -11,10 +11,10 @@ using Avro.Generic;
using Confluent.Kafka; using Confluent.Kafka;
using Confluent.SchemaRegistry; using Confluent.SchemaRegistry;
using Confluent.SchemaRegistry.Serdes; using Confluent.SchemaRegistry.Serdes;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Squidex.Infrastructure.Json; using Squidex.Infrastructure.Json;
using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Json.Objects;
using Squidex.Log;
using Schema = Avro.Schema; using Schema = Avro.Schema;
namespace Squidex.Extensions.Actions.Kafka namespace Squidex.Extensions.Actions.Kafka
@ -26,7 +26,8 @@ namespace Squidex.Extensions.Actions.Kafka
private readonly ISchemaRegistryClient schemaRegistry; private readonly ISchemaRegistryClient schemaRegistry;
private readonly IJsonSerializer jsonSerializer; private readonly IJsonSerializer jsonSerializer;
public KafkaProducer(IOptions<KafkaProducerOptions> options, ISemanticLog log, IJsonSerializer jsonSerializer) public KafkaProducer(IOptions<KafkaProducerOptions> options, IJsonSerializer jsonSerializer,
ILogger<KafkaProducer> log)
{ {
this.jsonSerializer = jsonSerializer; this.jsonSerializer = jsonSerializer;
@ -62,49 +63,44 @@ namespace Squidex.Extensions.Actions.Kafka
} }
} }
private static void LogMessage(ISemanticLog log, LogMessage message) private static void LogMessage(ILogger<KafkaProducer> log, LogMessage message)
{ {
var level = SemanticLogLevel.Information; var level = LogLevel.Information;
switch (message.Level) switch (message.Level)
{ {
case SyslogLevel.Emergency: case SyslogLevel.Emergency:
level = SemanticLogLevel.Error; level = LogLevel.Error;
break; break;
case SyslogLevel.Alert: case SyslogLevel.Alert:
level = SemanticLogLevel.Error; level = LogLevel.Error;
break; break;
case SyslogLevel.Critical: case SyslogLevel.Critical:
level = SemanticLogLevel.Error; level = LogLevel.Error;
break; break;
case SyslogLevel.Error: case SyslogLevel.Error:
level = SemanticLogLevel.Error; level = LogLevel.Error;
break; break;
case SyslogLevel.Warning: case SyslogLevel.Warning:
level = SemanticLogLevel.Warning; level = LogLevel.Warning;
break; break;
case SyslogLevel.Notice: case SyslogLevel.Notice:
level = SemanticLogLevel.Information; level = LogLevel.Information;
break; break;
case SyslogLevel.Info: case SyslogLevel.Info:
level = SemanticLogLevel.Information; level = LogLevel.Information;
break; break;
case SyslogLevel.Debug: case SyslogLevel.Debug:
level = SemanticLogLevel.Debug; level = LogLevel.Debug;
break; break;
} }
log.Log(level, null, w => w log.Log(level, "Kafka log {name}: {message}.", message.Name, message.Message);
.WriteProperty("action", "KafkaAction")
.WriteProperty("name", message.Name)
.WriteProperty("message", message.Message));
} }
private static void LogError(ISemanticLog log, Error error) private static void LogError(ILogger<KafkaProducer> log, Error error)
{ {
log.LogWarning(w => w log.LogWarning("Kafka error with {code} and {reason}.", error.Code, error.Reason);
.WriteProperty("action", "KafkaError")
.WriteProperty("reason", error.Reason));
} }
public async Task SendAsync(KafkaJob job, public async Task SendAsync(KafkaJob job,

11
backend/extensions/Squidex.Extensions/Assets/Azure/AzureMetadataSource.cs

@ -7,19 +7,19 @@
using Microsoft.Azure.CognitiveServices.Vision.ComputerVision; using Microsoft.Azure.CognitiveServices.Vision.ComputerVision;
using Microsoft.Azure.CognitiveServices.Vision.ComputerVision.Models; using Microsoft.Azure.CognitiveServices.Vision.ComputerVision.Models;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Squidex.Domain.Apps.Core.Assets; using Squidex.Domain.Apps.Core.Assets;
using Squidex.Domain.Apps.Entities.Assets; using Squidex.Domain.Apps.Entities.Assets;
using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Json.Objects;
using Squidex.Log;
namespace Squidex.Extensions.Assets.Azure namespace Squidex.Extensions.Assets.Azure
{ {
public sealed class AzureMetadataSource : IAssetMetadataSource public sealed class AzureMetadataSource : IAssetMetadataSource
{ {
private const long MaxSize = 5 * 1025 * 1024; private const long MaxSize = 5 * 1025 * 1024;
private readonly ISemanticLog log; private readonly ILogger<AzureMetadataSource> log;
private readonly ComputerVisionClient client; private readonly ComputerVisionClient client;
private readonly char[] trimChars = private readonly char[] trimChars =
{ {
@ -36,7 +36,8 @@ namespace Squidex.Extensions.Assets.Azure
public int Order => int.MaxValue; public int Order => int.MaxValue;
public AzureMetadataSource(IOptions<AzureMetadataSourceOptions> options, ISemanticLog log) public AzureMetadataSource(IOptions<AzureMetadataSourceOptions> options,
ILogger<AzureMetadataSource> log)
{ {
client = new ComputerVisionClient(new ApiKeyServiceClientCredentials(options.Value.ApiKey)) client = new ComputerVisionClient(new ApiKeyServiceClientCredentials(options.Value.ApiKey))
{ {
@ -82,9 +83,7 @@ namespace Squidex.Extensions.Assets.Azure
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, w => w log.LogError(ex, "Failed to enrich asset.");
.WriteProperty("action", "EnrichWithAzure")
.WriteProperty("status", "Failed"));
} }
} }

7
backend/i18n/frontend_en.json

@ -12,6 +12,7 @@
"apps.appNameWarning": "The app name cannot be changed later.", "apps.appNameWarning": "The app name cannot be changed later.",
"apps.appsButtonCreate": "Apps Overview", "apps.appsButtonCreate": "Apps Overview",
"apps.appsButtonFallbackTitle": "Apps Overview", "apps.appsButtonFallbackTitle": "Apps Overview",
"apps.archiveFailed": "Failed to archive app.",
"apps.create": "Create App", "apps.create": "Create App",
"apps.createBlankApp": "New App", "apps.createBlankApp": "New App",
"apps.createBlankAppDescription": "Create a new blank app without content and schemas.", "apps.createBlankAppDescription": "Create a new blank app without content and schemas.",
@ -36,12 +37,14 @@
"apps.leaveConfirmTitle": "Leave app.", "apps.leaveConfirmTitle": "Leave app.",
"apps.leaveFailed": "Failed to leave app. Please reload.", "apps.leaveFailed": "Failed to leave app. Please reload.",
"apps.listPageTitle": "Apps", "apps.listPageTitle": "Apps",
"apps.loadAssetScriptsFailed": "Failed to load asset scripts. Please reload.",
"apps.loadFailed": "Failed to load apps. Please reload.", "apps.loadFailed": "Failed to load apps. Please reload.",
"apps.loadSettingsFailed": "Failed to update UI settings. Please reload.", "apps.loadSettingsFailed": "Failed to update UI settings. Please reload.",
"apps.removeImage": "Remove image", "apps.removeImage": "Remove image",
"apps.removeImageFailed": "Failed to remove app image. Please reload.", "apps.removeImageFailed": "Failed to remove app image. Please reload.",
"apps.updateAssetScriptsFailed": "Failed to update asset scripts. Please reload.",
"apps.updateFailed": "Failed to update app. Please reload.", "apps.updateFailed": "Failed to update app. Please reload.",
"apps.updateSettingsFailed": "Faield to update UI settings. Please reload.", "apps.updateSettingsFailed": "Failed to update UI settings. Please reload.",
"apps.uploadImage": "Drop an file to replace the app image. Use a square size.", "apps.uploadImage": "Drop an file to replace the app image. Use a square size.",
"apps.uploadImageButton": "Upload File", "apps.uploadImageButton": "Upload File",
"apps.uploadImageFailed": "Failed to upload image. Please reload.", "apps.uploadImageFailed": "Failed to upload image. Please reload.",
@ -125,6 +128,7 @@
"assets.uploaderUploadHere": "No upload in progress, drop files here.", "assets.uploaderUploadHere": "No upload in progress, drop files here.",
"assets.uploadFailed": "Failed to upload asset. Please reload.", "assets.uploadFailed": "Failed to upload asset. Please reload.",
"assets.uploadHint": "Drop file on existing item to replace the asset with a newer version.", "assets.uploadHint": "Drop file on existing item to replace the asset with a newer version.",
"assetScripts.reloaded": "Asset Scripts reloaded.",
"backups.backupCountAssetsLabel": "Assets", "backups.backupCountAssetsLabel": "Assets",
"backups.backupCountAssetsTooltip": "Archived assets", "backups.backupCountAssetsTooltip": "Archived assets",
"backups.backupCountEventsLabel": "Events", "backups.backupCountEventsLabel": "Events",
@ -314,6 +318,7 @@
"common.name": "Name", "common.name": "Name",
"common.no": "No", "common.no": "No",
"common.nothingChanged": "Nothing has been changed.", "common.nothingChanged": "Nothing has been changed.",
"common.notSupported": "Not Supported",
"common.noValue": "- No value -", "common.noValue": "- No value -",
"common.openAPI": "Open API", "common.openAPI": "Open API",
"common.or": "or", "common.or": "or",

7
backend/i18n/frontend_it.json

@ -12,6 +12,7 @@
"apps.appNameWarning": "Il nome della app non potrà essere cambiato in un secondo momento.", "apps.appNameWarning": "Il nome della app non potrà essere cambiato in un secondo momento.",
"apps.appsButtonCreate": "Nuova App", "apps.appsButtonCreate": "Nuova App",
"apps.appsButtonFallbackTitle": "Lista App", "apps.appsButtonFallbackTitle": "Lista App",
"apps.archiveFailed": "Failed to archive app.",
"apps.create": "Crea un'App", "apps.create": "Crea un'App",
"apps.createBlankApp": "Nuova App.", "apps.createBlankApp": "Nuova App.",
"apps.createBlankAppDescription": "Crea una app vuota senza contenuti o schema.", "apps.createBlankAppDescription": "Crea una app vuota senza contenuti o schema.",
@ -36,12 +37,14 @@
"apps.leaveConfirmTitle": "Esci dall'app.", "apps.leaveConfirmTitle": "Esci dall'app.",
"apps.leaveFailed": "Non è stato possibile uscire dall'app. Per favore ricarica.", "apps.leaveFailed": "Non è stato possibile uscire dall'app. Per favore ricarica.",
"apps.listPageTitle": "App", "apps.listPageTitle": "App",
"apps.loadAssetScriptsFailed": "Failed to load asset scripts. Please reload.",
"apps.loadFailed": "Non è stato possibile caricare le App. Per favore ricarica.", "apps.loadFailed": "Non è stato possibile caricare le App. Per favore ricarica.",
"apps.loadSettingsFailed": "Failed to update UI settings. Please reload.", "apps.loadSettingsFailed": "Failed to update UI settings. Please reload.",
"apps.removeImage": "Rimuovi l'immagine", "apps.removeImage": "Rimuovi l'immagine",
"apps.removeImageFailed": "Non è stato possibile rimuovere l'immagine dell'app. Per favore ricarica.", "apps.removeImageFailed": "Non è stato possibile rimuovere l'immagine dell'app. Per favore ricarica.",
"apps.updateAssetScriptsFailed": "Failed to update asset scripts. Please reload.",
"apps.updateFailed": "Non è stato possibile aggiornare l'app. Per favore ricarica.", "apps.updateFailed": "Non è stato possibile aggiornare l'app. Per favore ricarica.",
"apps.updateSettingsFailed": "Faield to update UI settings. Please reload.", "apps.updateSettingsFailed": "Failed to update UI settings. Please reload.",
"apps.uploadImage": "Trascina il file per sostituire l'immagine dell'app. Utilizza una dimensione quadrata.", "apps.uploadImage": "Trascina il file per sostituire l'immagine dell'app. Utilizza una dimensione quadrata.",
"apps.uploadImageButton": "Carica il File", "apps.uploadImageButton": "Carica il File",
"apps.uploadImageFailed": "Non è stato possibile caricare l'immagine. Per favore ricarica.", "apps.uploadImageFailed": "Non è stato possibile caricare l'immagine. Per favore ricarica.",
@ -125,6 +128,7 @@
"assets.uploaderUploadHere": "Nessun caricamento in corso, trascina qui i file.", "assets.uploaderUploadHere": "Nessun caricamento in corso, trascina qui i file.",
"assets.uploadFailed": "Non è stato possibile caricare la risorsa. Per favore ricarica.", "assets.uploadFailed": "Non è stato possibile caricare la risorsa. Per favore ricarica.",
"assets.uploadHint": "Trascina il file sull'elemento esistente per poterlo sostituire con una versione più recente.", "assets.uploadHint": "Trascina il file sull'elemento esistente per poterlo sostituire con una versione più recente.",
"assetScripts.reloaded": "Asset Scripts reloaded.",
"backups.backupCountAssetsLabel": "Risorse", "backups.backupCountAssetsLabel": "Risorse",
"backups.backupCountAssetsTooltip": "Risorse archiviate", "backups.backupCountAssetsTooltip": "Risorse archiviate",
"backups.backupCountEventsLabel": "Eventi", "backups.backupCountEventsLabel": "Eventi",
@ -314,6 +318,7 @@
"common.name": "Nome", "common.name": "Nome",
"common.no": "No", "common.no": "No",
"common.nothingChanged": "Non è stato cambiato niente.", "common.nothingChanged": "Non è stato cambiato niente.",
"common.notSupported": "Not Supported",
"common.noValue": "- Nessun valore -", "common.noValue": "- Nessun valore -",
"common.openAPI": "Open API", "common.openAPI": "Open API",
"common.or": "o", "common.or": "o",

7
backend/i18n/frontend_nl.json

@ -12,6 +12,7 @@
"apps.appNameWarning": "De app-naam kan later niet worden gewijzigd.", "apps.appNameWarning": "De app-naam kan later niet worden gewijzigd.",
"apps.appsButtonCreate": "Apps-overzicht", "apps.appsButtonCreate": "Apps-overzicht",
"apps.appsButtonFallbackTitle": "Apps-overzicht", "apps.appsButtonFallbackTitle": "Apps-overzicht",
"apps.archiveFailed": "Failed to archive app.",
"apps.create": "App maken", "apps.create": "App maken",
"apps.createBlankApp": "Nieuwe app.", "apps.createBlankApp": "Nieuwe app.",
"apps.createBlankAppDescription": "Maak een nieuwe lege app zonder inhoud en schema's.", "apps.createBlankAppDescription": "Maak een nieuwe lege app zonder inhoud en schema's.",
@ -36,12 +37,14 @@
"apps.leaveConfirmTitle": "Verlaat app.", "apps.leaveConfirmTitle": "Verlaat app.",
"apps.leaveFailed": "Het verlaten van de app is mislukt. Herlaad de pagina.", "apps.leaveFailed": "Het verlaten van de app is mislukt. Herlaad de pagina.",
"apps.listPageTitle": "Apps", "apps.listPageTitle": "Apps",
"apps.loadAssetScriptsFailed": "Failed to load asset scripts. Please reload.",
"apps.loadFailed": "Laden van apps is mislukt. Laad opnieuw.", "apps.loadFailed": "Laden van apps is mislukt. Laad opnieuw.",
"apps.loadSettingsFailed": "Failed to update UI settings. Please reload.", "apps.loadSettingsFailed": "Failed to update UI settings. Please reload.",
"apps.removeImage": "Afbeelding verwijderen", "apps.removeImage": "Afbeelding verwijderen",
"apps.removeImageFailed": "Verwijderen van app-afbeelding is mislukt. Laad opnieuw.", "apps.removeImageFailed": "Verwijderen van app-afbeelding is mislukt. Laad opnieuw.",
"apps.updateAssetScriptsFailed": "Failed to update asset scripts. Please reload.",
"apps.updateFailed": "Update app mislukt. Laad opnieuw.", "apps.updateFailed": "Update app mislukt. Laad opnieuw.",
"apps.updateSettingsFailed": "Faield to update UI settings. Please reload.", "apps.updateSettingsFailed": "Failed to update UI settings. Please reload.",
"apps.uploadImage": "Zet een bestand neer om de app-afbeelding te vervangen. Gebruik een vierkant formaat.", "apps.uploadImage": "Zet een bestand neer om de app-afbeelding te vervangen. Gebruik een vierkant formaat.",
"apps.uploadImageButton": "Upload bestand", "apps.uploadImageButton": "Upload bestand",
"apps.uploadImageFailed": "Uploaden van afbeelding is mislukt. Laad opnieuw.", "apps.uploadImageFailed": "Uploaden van afbeelding is mislukt. Laad opnieuw.",
@ -125,6 +128,7 @@
"assets.uploaderUploadHere": "Geen upload bezig, zet bestanden hier neer.", "assets.uploaderUploadHere": "Geen upload bezig, zet bestanden hier neer.",
"assets.uploadFailed": "Uploaden van item is mislukt. Laad opnieuw.", "assets.uploadFailed": "Uploaden van item is mislukt. Laad opnieuw.",
"assets.uploadHint": "Zet het bestand neer op bestaand item om het bestand te vervangen door een nieuwere versie.", "assets.uploadHint": "Zet het bestand neer op bestaand item om het bestand te vervangen door een nieuwere versie.",
"assetScripts.reloaded": "Asset Scripts reloaded.",
"backups.backupCountAssetsLabel": "Bestanden", "backups.backupCountAssetsLabel": "Bestanden",
"backups.backupCountAssetsTooltip": "Gearchiveerde middelen", "backups.backupCountAssetsTooltip": "Gearchiveerde middelen",
"backups.backupCountEventsLabel": "Evenementen", "backups.backupCountEventsLabel": "Evenementen",
@ -314,6 +318,7 @@
"common.name": "Naam", "common.name": "Naam",
"common.no": "Nee", "common.no": "Nee",
"common.nothingChanged": "Er is niets veranderd.", "common.nothingChanged": "Er is niets veranderd.",
"common.notSupported": "Not Supported",
"common.noValue": "- Geen waarde -", "common.noValue": "- Geen waarde -",
"common.openAPI": "Open API", "common.openAPI": "Open API",
"common.or": "of", "common.or": "of",

5
backend/i18n/frontend_zh.json

@ -12,6 +12,7 @@
"apps.appNameWarning": "以后不能更改应用名称。", "apps.appNameWarning": "以后不能更改应用名称。",
"apps.appsButtonCreate": "应用概览", "apps.appsButtonCreate": "应用概览",
"apps.appsButtonFallbackTitle": "应用概览", "apps.appsButtonFallbackTitle": "应用概览",
"apps.archiveFailed": "Failed to archive app.",
"apps.create": "创建应用程序", "apps.create": "创建应用程序",
"apps.createBlankApp": "新应用程序", "apps.createBlankApp": "新应用程序",
"apps.createBlankAppDescription": "创建一个没有内容和Schemas的新空白应用程序。", "apps.createBlankAppDescription": "创建一个没有内容和Schemas的新空白应用程序。",
@ -36,10 +37,12 @@
"apps.leaveConfirmTitle": "离开应用程序。", "apps.leaveConfirmTitle": "离开应用程序。",
"apps.leaveFailed": "退出应用失败,请重新加载。", "apps.leaveFailed": "退出应用失败,请重新加载。",
"apps.listPageTitle": "应用程序", "apps.listPageTitle": "应用程序",
"apps.loadAssetScriptsFailed": "Failed to load asset scripts. Please reload.",
"apps.loadFailed": "加载应用失败。请重新加载。", "apps.loadFailed": "加载应用失败。请重新加载。",
"apps.loadSettingsFailed": "更新界面设置失败。请重新加载。", "apps.loadSettingsFailed": "更新界面设置失败。请重新加载。",
"apps.removeImage": "删除图片", "apps.removeImage": "删除图片",
"apps.removeImageFailed": "删除应用图片失败。请重新加载。", "apps.removeImageFailed": "删除应用图片失败。请重新加载。",
"apps.updateAssetScriptsFailed": "Failed to update asset scripts. Please reload.",
"apps.updateFailed": "更新应用失败。请重新加载。", "apps.updateFailed": "更新应用失败。请重新加载。",
"apps.updateSettingsFailed": "更新界面设置失败。请重新加载。", "apps.updateSettingsFailed": "更新界面设置失败。请重新加载。",
"apps.uploadImage": "拖放文件以替换应用图片。使用正方形大小。", "apps.uploadImage": "拖放文件以替换应用图片。使用正方形大小。",
@ -125,6 +128,7 @@
"assets.uploaderUploadHere": "没有正在进行的上传,将文件拖到这里。", "assets.uploaderUploadHere": "没有正在进行的上传,将文件拖到这里。",
"assets.uploadFailed": "资源上传失败,请重新加载。", "assets.uploadFailed": "资源上传失败,请重新加载。",
"assets.uploadHint": "在现有项目上放置文件以使用更新版本替换资源。", "assets.uploadHint": "在现有项目上放置文件以使用更新版本替换资源。",
"assetScripts.reloaded": "Asset Scripts reloaded.",
"backups.backupCountAssetsLabel": "资源", "backups.backupCountAssetsLabel": "资源",
"backups.backupCountAssetsTooltip": "存档资源", "backups.backupCountAssetsTooltip": "存档资源",
"backups.backupCountEventsLabel": "事件", "backups.backupCountEventsLabel": "事件",
@ -314,6 +318,7 @@
"common.name": "名称", "common.name": "名称",
"common.no": "不", "common.no": "不",
"common.nothingChanged": "什么都没有改变。", "common.nothingChanged": "什么都没有改变。",
"common.notSupported": "Not Supported",
"common.noValue": "- 无值 -", "common.noValue": "- 无值 -",
"common.openAPI": "Open API", "common.openAPI": "Open API",
"common.or": "或", "common.or": "或",

2
backend/i18n/source/backend_en.json

@ -250,7 +250,6 @@
"history.schemas.updated": "updated schema {[Name]}.", "history.schemas.updated": "updated schema {[Name]}.",
"history.statusChanged": "changed status of {[Schema]} content to {[Status]}.", "history.statusChanged": "changed status of {[Schema]} content to {[Status]}.",
"login.githubPrivateEmail": "Your email address is set to private in Github. Please set it to public to use Github login.", "login.githubPrivateEmail": "Your email address is set to private in Github. Please set it to public to use Github login.",
"login.noEmailAddress": "We cannot get the email address from authentication provider.",
"rules.ruleAlreadyRunning": "Another rule is already running.", "rules.ruleAlreadyRunning": "Another rule is already running.",
"schemas.dateTimeCalculatedDefaultAndDefaultError": "Calculated default value and default value cannot be used together.", "schemas.dateTimeCalculatedDefaultAndDefaultError": "Calculated default value and default value cannot be used together.",
"schemas.duplicateFieldName": "Field '{field}' has been added twice.", "schemas.duplicateFieldName": "Field '{field}' has been added twice.",
@ -335,6 +334,7 @@
"users.logout.headline": "Logged out!", "users.logout.headline": "Logged out!",
"users.logout.text": "!Please close this popup.", "users.logout.text": "!Please close this popup.",
"users.logout.title": "Logout", "users.logout.title": "Logout",
"users.noEmailAddress": "We cannot get the email address from authentication provider.",
"users.profile.addLoginDone": "Login added successfully.", "users.profile.addLoginDone": "Login added successfully.",
"users.profile.changePassword": "Change Password", "users.profile.changePassword": "Change Password",
"users.profile.changePasswordDone": "Password changed successfully.", "users.profile.changePasswordDone": "Password changed successfully.",

7
backend/i18n/source/frontend_en.json

@ -12,6 +12,7 @@
"apps.appNameWarning": "The app name cannot be changed later.", "apps.appNameWarning": "The app name cannot be changed later.",
"apps.appsButtonCreate": "Apps Overview", "apps.appsButtonCreate": "Apps Overview",
"apps.appsButtonFallbackTitle": "Apps Overview", "apps.appsButtonFallbackTitle": "Apps Overview",
"apps.archiveFailed": "Failed to archive app.",
"apps.create": "Create App", "apps.create": "Create App",
"apps.createBlankApp": "New App", "apps.createBlankApp": "New App",
"apps.createBlankAppDescription": "Create a new blank app without content and schemas.", "apps.createBlankAppDescription": "Create a new blank app without content and schemas.",
@ -36,12 +37,14 @@
"apps.leaveConfirmTitle": "Leave app.", "apps.leaveConfirmTitle": "Leave app.",
"apps.leaveFailed": "Failed to leave app. Please reload.", "apps.leaveFailed": "Failed to leave app. Please reload.",
"apps.listPageTitle": "Apps", "apps.listPageTitle": "Apps",
"apps.loadAssetScriptsFailed": "Failed to load asset scripts. Please reload.",
"apps.loadFailed": "Failed to load apps. Please reload.", "apps.loadFailed": "Failed to load apps. Please reload.",
"apps.loadSettingsFailed": "Failed to update UI settings. Please reload.", "apps.loadSettingsFailed": "Failed to update UI settings. Please reload.",
"apps.removeImage": "Remove image", "apps.removeImage": "Remove image",
"apps.removeImageFailed": "Failed to remove app image. Please reload.", "apps.removeImageFailed": "Failed to remove app image. Please reload.",
"apps.updateAssetScriptsFailed": "Failed to update asset scripts. Please reload.",
"apps.updateFailed": "Failed to update app. Please reload.", "apps.updateFailed": "Failed to update app. Please reload.",
"apps.updateSettingsFailed": "Faield to update UI settings. Please reload.", "apps.updateSettingsFailed": "Failed to update UI settings. Please reload.",
"apps.uploadImage": "Drop an file to replace the app image. Use a square size.", "apps.uploadImage": "Drop an file to replace the app image. Use a square size.",
"apps.uploadImageButton": "Upload File", "apps.uploadImageButton": "Upload File",
"apps.uploadImageFailed": "Failed to upload image. Please reload.", "apps.uploadImageFailed": "Failed to upload image. Please reload.",
@ -125,6 +128,7 @@
"assets.uploaderUploadHere": "No upload in progress, drop files here.", "assets.uploaderUploadHere": "No upload in progress, drop files here.",
"assets.uploadFailed": "Failed to upload asset. Please reload.", "assets.uploadFailed": "Failed to upload asset. Please reload.",
"assets.uploadHint": "Drop file on existing item to replace the asset with a newer version.", "assets.uploadHint": "Drop file on existing item to replace the asset with a newer version.",
"assetScripts.reloaded": "Asset Scripts reloaded.",
"backups.backupCountAssetsLabel": "Assets", "backups.backupCountAssetsLabel": "Assets",
"backups.backupCountAssetsTooltip": "Archived assets", "backups.backupCountAssetsTooltip": "Archived assets",
"backups.backupCountEventsLabel": "Events", "backups.backupCountEventsLabel": "Events",
@ -314,6 +318,7 @@
"common.name": "Name", "common.name": "Name",
"common.no": "No", "common.no": "No",
"common.nothingChanged": "Nothing has been changed.", "common.nothingChanged": "Nothing has been changed.",
"common.notSupported": "Not Supported",
"common.noValue": "- No value -", "common.noValue": "- No value -",
"common.openAPI": "Open API", "common.openAPI": "Open API",
"common.or": "or", "common.or": "or",

2
backend/i18n/source/frontend_nl.json

@ -41,7 +41,7 @@
"apps.removeImage": "Afbeelding verwijderen", "apps.removeImage": "Afbeelding verwijderen",
"apps.removeImageFailed": "Verwijderen van app-afbeelding is mislukt. Laad opnieuw.", "apps.removeImageFailed": "Verwijderen van app-afbeelding is mislukt. Laad opnieuw.",
"apps.updateFailed": "Update app mislukt. Laad opnieuw.", "apps.updateFailed": "Update app mislukt. Laad opnieuw.",
"apps.updateSettingsFailed": "Faield to update UI settings. Please reload.", "apps.updateSettingsFailed": "Failed to update UI settings. Please reload.",
"apps.uploadImage": "Zet een bestand neer om de app-afbeelding te vervangen. Gebruik een vierkant formaat.", "apps.uploadImage": "Zet een bestand neer om de app-afbeelding te vervangen. Gebruik een vierkant formaat.",
"apps.uploadImageButton": "Upload bestand", "apps.uploadImageButton": "Upload bestand",
"apps.uploadImageFailed": "Uploaden van afbeelding is mislukt. Laad opnieuw.", "apps.uploadImageFailed": "Uploaden van afbeelding is mislukt. Laad opnieuw.",

2
backend/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldCollection.cs

@ -124,7 +124,7 @@ namespace Squidex.Domain.Apps.Core.Schemas
if (ById.ContainsKey(field.Id)) if (ById.ContainsKey(field.Id))
{ {
throw new ArgumentException($"A field with id {field.Id} already exists.", nameof(field)); throw new ArgumentException($"A field with ID {field.Id} already exists.", nameof(field));
} }
return new FieldCollection<T>(fieldsOrdered.Union(Enumerable.Repeat(field, 1))); return new FieldCollection<T>(fieldsOrdered.Union(Enumerable.Repeat(field, 1)));

14
backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleService.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using NodaTime; using NodaTime;
using Squidex.Domain.Apps.Core.Rules; using Squidex.Domain.Apps.Core.Rules;
@ -16,7 +17,6 @@ using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Json; using Squidex.Infrastructure.Json;
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Tasks; using Squidex.Infrastructure.Tasks;
using Squidex.Log;
namespace Squidex.Domain.Apps.Core.HandleRules namespace Squidex.Domain.Apps.Core.HandleRules
{ {
@ -29,7 +29,7 @@ namespace Squidex.Domain.Apps.Core.HandleRules
private readonly IEventEnricher eventEnricher; private readonly IEventEnricher eventEnricher;
private readonly IJsonSerializer jsonSerializer; private readonly IJsonSerializer jsonSerializer;
private readonly IClock clock; private readonly IClock clock;
private readonly ISemanticLog log; private readonly ILogger<RuleService> log;
public RuleService( public RuleService(
IOptions<RuleOptions> ruleOptions, IOptions<RuleOptions> ruleOptions,
@ -38,7 +38,7 @@ namespace Squidex.Domain.Apps.Core.HandleRules
IEventEnricher eventEnricher, IEventEnricher eventEnricher,
IJsonSerializer jsonSerializer, IJsonSerializer jsonSerializer,
IClock clock, IClock clock,
ISemanticLog log, ILogger<RuleService> log,
TypeNameRegistry typeNameRegistry) TypeNameRegistry typeNameRegistry)
{ {
this.typeNameRegistry = typeNameRegistry; this.typeNameRegistry = typeNameRegistry;
@ -286,9 +286,7 @@ namespace Squidex.Domain.Apps.Core.HandleRules
}); });
} }
log.LogError(ex, w => w log.LogError(ex, "Failed to create rule jobs from event.");
.WriteProperty("action", "createRuleJobFromEvent")
.WriteProperty("status", "Failed"));
} }
} }
} }
@ -296,9 +294,7 @@ namespace Squidex.Domain.Apps.Core.HandleRules
{ {
jobs.Add(JobResult.Failed(ex)); jobs.Add(JobResult.Failed(ex));
log.LogError(ex, w => w log.LogError(ex, "Failed to create rule job.");
.WriteProperty("action", "createRuleJob")
.WriteProperty("status", "Failed"));
} }
} }

1
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Internal/Parser.cs

@ -8,7 +8,6 @@
using Esprima; using Esprima;
using Esprima.Ast; using Esprima.Ast;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Core.Scripting.Internal namespace Squidex.Domain.Apps.Core.Scripting.Internal
{ {

7
backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs

@ -6,13 +6,13 @@
// ========================================================================== // ==========================================================================
using System.Collections.Concurrent; using System.Collections.Concurrent;
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.ValidateContent.Validators; using Squidex.Domain.Apps.Core.ValidateContent.Validators;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Json.Objects;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
using Squidex.Log;
namespace Squidex.Domain.Apps.Core.ValidateContent namespace Squidex.Domain.Apps.Core.ValidateContent
{ {
@ -21,7 +21,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
private readonly PartitionResolver partitionResolver; private readonly PartitionResolver partitionResolver;
private readonly ValidationContext context; private readonly ValidationContext context;
private readonly IEnumerable<IValidatorsFactory> factories; private readonly IEnumerable<IValidatorsFactory> factories;
private readonly ISemanticLog log; private readonly ILogger<ContentValidator> log;
private readonly ConcurrentBag<ValidationError> errors = new ConcurrentBag<ValidationError>(); private readonly ConcurrentBag<ValidationError> errors = new ConcurrentBag<ValidationError>();
public IReadOnlyCollection<ValidationError> Errors public IReadOnlyCollection<ValidationError> Errors
@ -29,7 +29,8 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
get => errors; get => errors;
} }
public ContentValidator(PartitionResolver partitionResolver, ValidationContext context, IEnumerable<IValidatorsFactory> factories, ISemanticLog log) public ContentValidator(PartitionResolver partitionResolver, ValidationContext context, IEnumerable<IValidatorsFactory> factories,
ILogger<ContentValidator> log)
{ {
Guard.NotNull(context); Guard.NotNull(context);
Guard.NotNull(factories); Guard.NotNull(factories);

11
backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/AggregateValidator.cs

@ -5,18 +5,19 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using Microsoft.Extensions.Logging;
using Squidex.Infrastructure.Tasks; using Squidex.Infrastructure.Tasks;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Log;
namespace Squidex.Domain.Apps.Core.ValidateContent.Validators namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
{ {
public sealed class AggregateValidator : IValidator public sealed class AggregateValidator : IValidator
{ {
private readonly IValidator[]? validators; private readonly IValidator[]? validators;
private readonly ISemanticLog log; private readonly ILogger<ContentValidator> log;
public AggregateValidator(IEnumerable<IValidator>? validators, ISemanticLog log) public AggregateValidator(IEnumerable<IValidator>? validators,
ILogger<ContentValidator> log)
{ {
this.validators = validators?.ToArray(); this.validators = validators?.ToArray();
@ -34,9 +35,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, w => w log.LogError(ex, "Failed to validate fields.");
.WriteProperty("action", "validateField")
.WriteProperty("status", "Failed"));
addError(context.Path, T.Get("contents.validation.error")); addError(context.Path, T.Get("contents.validation.error"));
} }

8
backend/src/Squidex.Domain.Apps.Entities/Apps/DomainObject/AppDomainObject.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Core.Apps; using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Domain.Apps.Entities.Apps.DomainObject.Guards; using Squidex.Domain.Apps.Entities.Apps.DomainObject.Guards;
@ -16,7 +17,6 @@ using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.States; using Squidex.Infrastructure.States;
using Squidex.Log;
using Squidex.Shared.Users; using Squidex.Shared.Users;
namespace Squidex.Domain.Apps.Entities.Apps.DomainObject namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
@ -28,8 +28,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
private readonly IAppPlanBillingManager appPlansBillingManager; private readonly IAppPlanBillingManager appPlansBillingManager;
private readonly IUserResolver userResolver; private readonly IUserResolver userResolver;
public AppDomainObject(IPersistenceFactory<State> persistence, ISemanticLog log, public AppDomainObject(IPersistenceFactory<State> persistence, ILogger<AppDomainObject> log,
InitialSettings initialPatterns, InitialSettings initialSettings,
IAppPlansProvider appPlansProvider, IAppPlansProvider appPlansProvider,
IAppPlanBillingManager appPlansBillingManager, IAppPlanBillingManager appPlansBillingManager,
IUserResolver userResolver) IUserResolver userResolver)
@ -38,7 +38,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
this.userResolver = userResolver; this.userResolver = userResolver;
this.appPlansProvider = appPlansProvider; this.appPlansProvider = appPlansProvider;
this.appPlansBillingManager = appPlansBillingManager; this.appPlansBillingManager = appPlansBillingManager;
this.initialSettings = initialPatterns; this.initialSettings = initialSettings;
} }
protected override bool IsDeleted(State snapshot) protected override bool IsDeleted(State snapshot)

19
backend/src/Squidex.Domain.Apps.Entities/Apps/Invitation/InvitationEventConsumer.cs

@ -5,11 +5,11 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using Microsoft.Extensions.Logging;
using NodaTime; using NodaTime;
using Squidex.Domain.Apps.Entities.Notifications; using Squidex.Domain.Apps.Entities.Notifications;
using Squidex.Domain.Apps.Events.Apps; using Squidex.Domain.Apps.Events.Apps;
using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.EventSourcing;
using Squidex.Log;
using Squidex.Shared.Users; using Squidex.Shared.Users;
namespace Squidex.Domain.Apps.Entities.Apps.Invitation namespace Squidex.Domain.Apps.Entities.Apps.Invitation
@ -19,7 +19,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation
private static readonly Duration MaxAge = Duration.FromDays(2); private static readonly Duration MaxAge = Duration.FromDays(2);
private readonly INotificationSender emailSender; private readonly INotificationSender emailSender;
private readonly IUserResolver userResolver; private readonly IUserResolver userResolver;
private readonly ISemanticLog log; private readonly ILogger<InvitationEventConsumer> log;
public string Name public string Name
{ {
@ -31,7 +31,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation
get { return "^app-"; } get { return "^app-"; }
} }
public InvitationEventConsumer(INotificationSender emailSender, IUserResolver userResolver, ISemanticLog log) public InvitationEventConsumer(INotificationSender emailSender, IUserResolver userResolver,
ILogger<InvitationEventConsumer> log)
{ {
this.emailSender = emailSender; this.emailSender = emailSender;
this.userResolver = userResolver; this.userResolver = userResolver;
@ -74,7 +75,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation
if (assigner == null) if (assigner == null)
{ {
LogWarning($"Assigner {assignerId} not found"); log.LogWarning("Failed to invite user: Assigner {assignerId} not found.", assignerId);
return; return;
} }
@ -82,7 +83,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation
if (assignee == null) if (assignee == null)
{ {
LogWarning($"Assignee {assigneeId} not found"); log.LogWarning("Failed to invite user: Assignee {assigneeId} not found.", assigneeId);
return; return;
} }
@ -91,13 +92,5 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation
await emailSender.SendInviteAsync(assigner, assignee, appName); await emailSender.SendInviteAsync(assigner, assignee, appName);
} }
} }
private void LogWarning(string reason)
{
log.LogWarning(w => w
.WriteProperty("action", "InviteUser")
.WriteProperty("status", "Failed")
.WriteProperty("reason", reason));
}
} }
} }

1
backend/src/Squidex.Domain.Apps.Entities/Assets/AssetsFluidExtension.cs

@ -9,7 +9,6 @@ using System.Text.Encodings.Web;
using Fluid; using Fluid;
using Fluid.Ast; using Fluid.Ast;
using Fluid.Values; using Fluid.Values;
using GraphQL.Utilities;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Squidex.Domain.Apps.Core.Rules.EnrichedEvents; using Squidex.Domain.Apps.Core.Rules.EnrichedEvents;
using Squidex.Domain.Apps.Core.Templates; using Squidex.Domain.Apps.Core.Templates;

4
backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetDomainObject.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Domain.Apps.Entities.Assets.DomainObject.Guards; using Squidex.Domain.Apps.Entities.Assets.DomainObject.Guards;
using Squidex.Domain.Apps.Events; using Squidex.Domain.Apps.Events;
@ -14,7 +15,6 @@ using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.States; using Squidex.Infrastructure.States;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Assets.DomainObject namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
{ {
@ -22,7 +22,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
{ {
private readonly IServiceProvider serviceProvider; private readonly IServiceProvider serviceProvider;
public AssetDomainObject(IPersistenceFactory<State> factory, ISemanticLog log, public AssetDomainObject(IPersistenceFactory<State> factory, ILogger<AssetDomainObject> log,
IServiceProvider serviceProvider) IServiceProvider serviceProvider)
: base(factory, log) : base(factory, log)
{ {

4
backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetFolderDomainObject.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Domain.Apps.Entities.Assets.DomainObject.Guards; using Squidex.Domain.Apps.Entities.Assets.DomainObject.Guards;
using Squidex.Domain.Apps.Events; using Squidex.Domain.Apps.Events;
@ -13,7 +14,6 @@ using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.States; using Squidex.Infrastructure.States;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Assets.DomainObject namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
{ {
@ -21,7 +21,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
{ {
private readonly IServiceProvider serviceProvider; private readonly IServiceProvider serviceProvider;
public AssetFolderDomainObject(IPersistenceFactory<State> factory, ISemanticLog log, public AssetFolderDomainObject(IPersistenceFactory<State> factory, ILogger<AssetFolderDomainObject> log,
IServiceProvider serviceProvider) IServiceProvider serviceProvider)
: base(factory, log) : base(factory, log)
{ {

22
backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetsBulkUpdateCommandMiddleware.cs

@ -7,13 +7,13 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Threading.Tasks.Dataflow; using System.Threading.Tasks.Dataflow;
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Domain.Apps.Entities.Contents; using Squidex.Domain.Apps.Entities.Contents;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Tasks; using Squidex.Infrastructure.Tasks;
using Squidex.Log;
using Squidex.Shared; using Squidex.Shared;
#pragma warning disable SA1313 // Parameter names should begin with lower-case letter #pragma warning disable SA1313 // Parameter names should begin with lower-case letter
@ -24,7 +24,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
public sealed class AssetsBulkUpdateCommandMiddleware : ICommandMiddleware public sealed class AssetsBulkUpdateCommandMiddleware : ICommandMiddleware
{ {
private readonly IContextProvider contextProvider; private readonly IContextProvider contextProvider;
private readonly ISemanticLog log; private readonly ILogger<AssetsBulkUpdateCommandMiddleware> log;
private sealed record BulkTaskCommand(BulkTask Task, DomainId Id, ICommand Command) private sealed record BulkTaskCommand(BulkTask Task, DomainId Id, ICommand Command)
{ {
@ -40,7 +40,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
{ {
} }
public AssetsBulkUpdateCommandMiddleware(IContextProvider contextProvider, ISemanticLog log) public AssetsBulkUpdateCommandMiddleware(IContextProvider contextProvider, ILogger<AssetsBulkUpdateCommandMiddleware> log)
{ {
this.contextProvider = contextProvider; this.contextProvider = contextProvider;
this.log = log; this.log = log;
@ -139,11 +139,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, w => w log.LogError(ex, "Faield to execute asset bulk job with index {index} of type {type}.",
.WriteProperty("action", "BulkContent") task.JobIndex,
.WriteProperty("status", "Failed") task.CommandJob.Type);
.WriteProperty("jobIndex", task.JobIndex)
.WriteProperty("jobType", task.CommandJob.Type.ToString()));
task.Results.Add(new BulkUpdateResultItem(id, task.JobIndex, ex)); task.Results.Add(new BulkUpdateResultItem(id, task.JobIndex, ex));
} }
@ -163,11 +161,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, w => w log.LogError(ex, "Faield to execute asset bulk job with index {index} of type {type}.",
.WriteProperty("action", "BulkContent") task.JobIndex,
.WriteProperty("status", "Failed") task.CommandJob.Type);
.WriteProperty("jobIndex", task.JobIndex)
.WriteProperty("jobType", task.CommandJob.Type.ToString()));
task.Results.Add(new BulkUpdateResultItem(id, task.JobIndex, ex)); task.Results.Add(new BulkUpdateResultItem(id, task.JobIndex, ex));
return null; return null;

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

@ -8,7 +8,6 @@
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.OData; using Microsoft.OData;
using Microsoft.OData.Edm; using Microsoft.OData.Edm;
using NJsonSchema;
using Squidex.Domain.Apps.Core.GenerateFilters; using Squidex.Domain.Apps.Core.GenerateFilters;
using Squidex.Domain.Apps.Core.Tags; using Squidex.Domain.Apps.Core.Tags;
using Squidex.Infrastructure; using Squidex.Infrastructure;

11
backend/src/Squidex.Domain.Apps.Entities/Assets/RecursiveDeleter.cs

@ -5,13 +5,13 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Domain.Apps.Entities.Assets.Repositories; using Squidex.Domain.Apps.Entities.Assets.Repositories;
using Squidex.Domain.Apps.Events.Assets; using Squidex.Domain.Apps.Events.Assets;
using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Assets namespace Squidex.Domain.Apps.Entities.Assets
{ {
@ -20,7 +20,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
private readonly ICommandBus commandBus; private readonly ICommandBus commandBus;
private readonly IAssetRepository assetRepository; private readonly IAssetRepository assetRepository;
private readonly IAssetFolderRepository assetFolderRepository; private readonly IAssetFolderRepository assetFolderRepository;
private readonly ISemanticLog log; private readonly ILogger<RecursiveDeleter> log;
private readonly HashSet<string> consumingTypes; private readonly HashSet<string> consumingTypes;
public string Name public string Name
@ -38,11 +38,12 @@ namespace Squidex.Domain.Apps.Entities.Assets
IAssetRepository assetRepository, IAssetRepository assetRepository,
IAssetFolderRepository assetFolderRepository, IAssetFolderRepository assetFolderRepository,
TypeNameRegistry typeNameRegistry, TypeNameRegistry typeNameRegistry,
ISemanticLog log) ILogger<RecursiveDeleter> log)
{ {
this.commandBus = commandBus; this.commandBus = commandBus;
this.assetRepository = assetRepository; this.assetRepository = assetRepository;
this.assetFolderRepository = assetFolderRepository; this.assetFolderRepository = assetFolderRepository;
this.log = log; this.log = log;
// Compute the event types names once for performance reasons and use hashset for extensibility. // Compute the event types names once for performance reasons and use hashset for extensibility.
@ -76,9 +77,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, w => w log.LogError(ex, "Failed to delete asset recursively.");
.WriteProperty("action", "DeleteAssetsRecursive")
.WriteProperty("status", "Failed"));
} }
} }

24
backend/src/Squidex.Domain.Apps.Entities/Backup/BackupGrain.cs

@ -7,6 +7,7 @@
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NodaTime; using NodaTime;
using Orleans.Concurrency; using Orleans.Concurrency;
using Squidex.Domain.Apps.Entities.Backup.State; using Squidex.Domain.Apps.Entities.Backup.State;
@ -16,7 +17,6 @@ using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Orleans; using Squidex.Infrastructure.Orleans;
using Squidex.Infrastructure.Tasks; using Squidex.Infrastructure.Tasks;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Log;
using Squidex.Shared.Users; using Squidex.Shared.Users;
namespace Squidex.Domain.Apps.Entities.Backup namespace Squidex.Domain.Apps.Entities.Backup
@ -26,14 +26,14 @@ namespace Squidex.Domain.Apps.Entities.Backup
{ {
private const int MaxBackups = 10; private const int MaxBackups = 10;
private static readonly Duration UpdateDuration = Duration.FromSeconds(1); private static readonly Duration UpdateDuration = Duration.FromSeconds(1);
private readonly IGrainState<BackupState> state;
private readonly IBackupArchiveLocation backupArchiveLocation; private readonly IBackupArchiveLocation backupArchiveLocation;
private readonly IBackupArchiveStore backupArchiveStore; private readonly IBackupArchiveStore backupArchiveStore;
private readonly IClock clock; private readonly IClock clock;
private readonly IServiceProvider serviceProvider; private readonly IServiceProvider serviceProvider;
private readonly IEventDataFormatter eventDataFormatter; private readonly IEventDataFormatter eventDataFormatter;
private readonly IEventStore eventStore; private readonly IEventStore eventStore;
private readonly ISemanticLog log; private readonly ILogger<BackupGrain> log;
private readonly IGrainState<BackupState> state;
private readonly IUserResolver userResolver; private readonly IUserResolver userResolver;
private CancellationTokenSource? currentJobToken; private CancellationTokenSource? currentJobToken;
private BackupJob? currentJob; private BackupJob? currentJob;
@ -46,8 +46,8 @@ namespace Squidex.Domain.Apps.Entities.Backup
IEventStore eventStore, IEventStore eventStore,
IGrainState<BackupState> state, IGrainState<BackupState> state,
IServiceProvider serviceProvider, IServiceProvider serviceProvider,
ISemanticLog log, IUserResolver userResolver,
IUserResolver userResolver) ILogger<BackupGrain> log)
{ {
this.backupArchiveLocation = backupArchiveLocation; this.backupArchiveLocation = backupArchiveLocation;
this.backupArchiveStore = backupArchiveStore; this.backupArchiveStore = backupArchiveStore;
@ -79,9 +79,7 @@ namespace Squidex.Domain.Apps.Entities.Backup
{ {
foreach (var backup in state.Value.Jobs) foreach (var backup in state.Value.Jobs)
{ {
#pragma warning disable MA0040 // Flow the cancellation token await backupArchiveStore.DeleteAsync(backup.Id, default);
await backupArchiveStore.DeleteAsync(backup.Id);
#pragma warning restore MA0040 // Flow the cancellation token
} }
TryDeactivateOnIdle(); TryDeactivateOnIdle();
@ -201,10 +199,7 @@ namespace Squidex.Domain.Apps.Entities.Backup
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, job.Id.ToString(), (ctx, w) => w log.LogError(ex, "Faield to make backup with backup id '{backupId}'.", job.Id);
.WriteProperty("action", "makeBackup")
.WriteProperty("status", "failed")
.WriteProperty("backupId", ctx));
job.Status = JobStatus.Failed; job.Status = JobStatus.Failed;
} }
@ -275,10 +270,7 @@ namespace Squidex.Domain.Apps.Entities.Backup
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, job.Id.ToString(), (logOperationId, w) => w log.LogError(ex, "Failed to make remove with backup id '{backupId}'.", job.Id);
.WriteProperty("action", "deleteBackup")
.WriteProperty("status", "failed")
.WriteProperty("operationId", logOperationId));
} }
state.Value.Jobs.Remove(job); state.Value.Jobs.Remove(job);

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

@ -7,6 +7,7 @@
using System.Threading.Tasks.Dataflow; using System.Threading.Tasks.Dataflow;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NodaTime; using NodaTime;
using Squidex.Domain.Apps.Core.Apps; using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.Apps.Commands;
@ -20,7 +21,6 @@ using Squidex.Infrastructure.Orleans;
using Squidex.Infrastructure.States; using Squidex.Infrastructure.States;
using Squidex.Infrastructure.Tasks; using Squidex.Infrastructure.Tasks;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Log;
using Squidex.Shared.Users; using Squidex.Shared.Users;
namespace Squidex.Domain.Apps.Entities.Backup namespace Squidex.Domain.Apps.Entities.Backup
@ -32,7 +32,7 @@ namespace Squidex.Domain.Apps.Entities.Backup
private readonly ICommandBus commandBus; private readonly ICommandBus commandBus;
private readonly IEventStore eventStore; private readonly IEventStore eventStore;
private readonly IEventDataFormatter eventDataFormatter; private readonly IEventDataFormatter eventDataFormatter;
private readonly ISemanticLog log; private readonly ILogger<RestoreGrain> log;
private readonly IServiceProvider serviceProvider; private readonly IServiceProvider serviceProvider;
private readonly IStreamNameResolver streamNameResolver; private readonly IStreamNameResolver streamNameResolver;
private readonly IUserResolver userResolver; private readonly IUserResolver userResolver;
@ -55,7 +55,7 @@ namespace Squidex.Domain.Apps.Entities.Backup
IServiceProvider serviceProvider, IServiceProvider serviceProvider,
IStreamNameResolver streamNameResolver, IStreamNameResolver streamNameResolver,
IUserResolver userResolver, IUserResolver userResolver,
ISemanticLog log) ILogger<RestoreGrain> log)
{ {
this.backupArchiveLocation = backupArchiveLocation; this.backupArchiveLocation = backupArchiveLocation;
this.clock = clock; this.clock = clock;
@ -129,11 +129,6 @@ namespace Squidex.Domain.Apps.Entities.Backup
{ {
var handlers = CreateHandlers(); var handlers = CreateHandlers();
var logContext = (
jobId: CurrentJob.Id.ToString(),
jobUrl: CurrentJob.Url.ToString()
);
var ct = default(CancellationToken); var ct = default(CancellationToken);
using (Telemetry.Activities.StartActivity("RestoreBackup")) using (Telemetry.Activities.StartActivity("RestoreBackup"))
@ -146,11 +141,9 @@ namespace Squidex.Domain.Apps.Entities.Backup
Log(" * Restore all objects like app, schemas and contents"); Log(" * Restore all objects like app, schemas and contents");
Log(" * Complete the restore operation for all objects"); Log(" * Complete the restore operation for all objects");
log.LogInformation(logContext, (ctx, w) => w log.LogInformation("Backup with job id {backupId} with from URL '{url}' started.",
.WriteProperty("action", "restore") CurrentJob.Id,
.WriteProperty("status", "started") CurrentJob.Url);
.WriteProperty("operationId", ctx.jobId)
.WriteProperty("url", ctx.jobUrl));
using (var reader = await DownloadAsync()) using (var reader = await DownloadAsync())
{ {
@ -188,13 +181,9 @@ namespace Squidex.Domain.Apps.Entities.Backup
Log("Completed, Yeah!"); Log("Completed, Yeah!");
log.LogInformation(logContext, (ctx, w) => log.LogInformation("Backup with job id {backupId} from URL '{url}' completed.",
{ CurrentJob.Id,
w.WriteProperty("action", "restore"); CurrentJob.Url);
w.WriteProperty("status", "completed");
w.WriteProperty("operationId", ctx.jobId);
w.WriteProperty("url", ctx.jobUrl);
});
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -215,13 +204,9 @@ namespace Squidex.Domain.Apps.Entities.Backup
CurrentJob.Status = JobStatus.Failed; CurrentJob.Status = JobStatus.Failed;
log.LogError(ex, logContext, (ctx, w) => log.LogError(ex, "Backup with job id {backupId} from URL '{url}' failed.",
{ CurrentJob.Id,
w.WriteProperty("action", "restore"); CurrentJob.Url);
w.WriteProperty("status", "failed");
w.WriteProperty("operationId", ctx.jobId);
w.WriteProperty("url", ctx.jobUrl);
});
} }
finally finally
{ {
@ -279,10 +264,7 @@ namespace Squidex.Domain.Apps.Entities.Backup
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, appId.ToString(), (logOperationId, w) => w log.LogError(ex, "Failed to clean up restore.");
.WriteProperty("action", "cleanupRestore")
.WriteProperty("status", "failed")
.WriteProperty("operationId", logOperationId));
} }
} }
} }

11
backend/src/Squidex.Domain.Apps.Entities/Contents/ContentSchedulerGrain.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using Microsoft.Extensions.Logging;
using NodaTime; using NodaTime;
using Orleans; using Orleans;
using Orleans.Runtime; using Orleans.Runtime;
@ -12,7 +13,6 @@ using Squidex.Domain.Apps.Entities.Contents.Commands;
using Squidex.Domain.Apps.Entities.Contents.Repositories; using Squidex.Domain.Apps.Entities.Contents.Repositories;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Commands;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Contents namespace Squidex.Domain.Apps.Entities.Contents
{ {
@ -21,13 +21,13 @@ namespace Squidex.Domain.Apps.Entities.Contents
private readonly IContentRepository contentRepository; private readonly IContentRepository contentRepository;
private readonly ICommandBus commandBus; private readonly ICommandBus commandBus;
private readonly IClock clock; private readonly IClock clock;
private readonly ISemanticLog log; private readonly ILogger<ContentSchedulerGrain> log;
public ContentSchedulerGrain( public ContentSchedulerGrain(
IContentRepository contentRepository, IContentRepository contentRepository,
ICommandBus commandBus, ICommandBus commandBus,
IClock clock, IClock clock,
ISemanticLog log) ILogger<ContentSchedulerGrain> log)
{ {
this.clock = clock; this.clock = clock;
@ -91,10 +91,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, content.Id.ToString(), (logContentId, w) => w log.LogError(ex, "Failed to execute scheduled status change for content '{contentId}'.", content.Id);
.WriteProperty("action", "ChangeStatusScheduled")
.WriteProperty("status", "Failed")
.WriteProperty("contentId", logContentId));
} }
} }

4
backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using Microsoft.Extensions.Logging;
using NodaTime; using NodaTime;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
@ -17,7 +18,6 @@ using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.States; using Squidex.Infrastructure.States;
using Squidex.Log;
using Squidex.Shared; using Squidex.Shared;
namespace Squidex.Domain.Apps.Entities.Contents.DomainObject namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
@ -26,7 +26,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
{ {
private readonly IServiceProvider serviceProvider; private readonly IServiceProvider serviceProvider;
public ContentDomainObject(IPersistenceFactory<State> persistence, ISemanticLog log, public ContentDomainObject(IPersistenceFactory<State> persistence, ILogger<ContentDomainObject> log,
IServiceProvider serviceProvider) IServiceProvider serviceProvider)
: base(persistence, log) : base(persistence, log)
{ {

23
backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentsBulkUpdateCommandMiddleware.cs

@ -7,6 +7,7 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Threading.Tasks.Dataflow; using System.Threading.Tasks.Dataflow;
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Domain.Apps.Entities.Contents.Commands;
using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.Schemas;
@ -15,7 +16,6 @@ using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Tasks; using Squidex.Infrastructure.Tasks;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Log;
using Squidex.Shared; using Squidex.Shared;
#pragma warning disable SA1313 // Parameter names should begin with lower-case letter #pragma warning disable SA1313 // Parameter names should begin with lower-case letter
@ -27,7 +27,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
{ {
private readonly IContentQueryService contentQuery; private readonly IContentQueryService contentQuery;
private readonly IContextProvider contextProvider; private readonly IContextProvider contextProvider;
private readonly ISemanticLog log; private readonly ILogger<ContentsBulkUpdateCommandMiddleware> log;
private sealed record BulkTaskCommand(BulkTask Task, DomainId Id, ICommand Command) private sealed record BulkTaskCommand(BulkTask Task, DomainId Id, ICommand Command)
{ {
@ -47,10 +47,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
public ContentsBulkUpdateCommandMiddleware( public ContentsBulkUpdateCommandMiddleware(
IContentQueryService contentQuery, IContentQueryService contentQuery,
IContextProvider contextProvider, IContextProvider contextProvider,
ISemanticLog log) ILogger<ContentsBulkUpdateCommandMiddleware> log)
{ {
this.contentQuery = contentQuery; this.contentQuery = contentQuery;
this.contextProvider = contextProvider; this.contextProvider = contextProvider;
this.log = log; this.log = log;
} }
@ -148,11 +149,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, w => w log.LogError(ex, "Failed to execute content bulk job with index {index} of type {type}.",
.WriteProperty("action", "BulkContent") task.JobIndex,
.WriteProperty("status", "Failed") task.CommandJob.Type);
.WriteProperty("jobIndex", task.JobIndex)
.WriteProperty("jobType", task.CommandJob.Type.ToString()));
task.Results.Add(new BulkUpdateResultItem(id, task.JobIndex, ex)); task.Results.Add(new BulkUpdateResultItem(id, task.JobIndex, ex));
} }
@ -183,11 +182,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, w => w log.LogError(ex, "Failed to execute content bulk job with index {index} of type {type}.",
.WriteProperty("action", "BulkContent") task.JobIndex,
.WriteProperty("status", "Failed") task.CommandJob.Type);
.WriteProperty("jobIndex", task.JobIndex)
.WriteProperty("jobType", task.CommandJob.Type.ToString()));
task.Results.Add(new BulkUpdateResultItem(id, task.JobIndex, ex)); task.Results.Add(new BulkUpdateResultItem(id, task.JobIndex, ex));
} }

4
backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/ValidationExtensions.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.DefaultValues; using Squidex.Domain.Apps.Core.DefaultValues;
@ -16,7 +17,6 @@ using Squidex.Infrastructure;
using Squidex.Infrastructure.Json; using Squidex.Infrastructure.Json;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
{ {
@ -117,7 +117,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
new ContentValidator(operation.Partition(), new ContentValidator(operation.Partition(),
validationContext, validationContext,
operation.Resolve<IEnumerable<IValidatorsFactory>>(), operation.Resolve<IEnumerable<IValidatorsFactory>>(),
operation.Resolve<ISemanticLog>()); operation.Resolve<ILogger<ContentValidator>>());
return validator; return validator;
} }

14
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Resolvers.cs

@ -7,9 +7,9 @@
using GraphQL; using GraphQL;
using GraphQL.Resolvers; using GraphQL.Resolvers;
using Microsoft.Extensions.Logging;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
{ {
@ -62,11 +62,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
} }
catch (Exception ex) catch (Exception ex)
{ {
executionContext.Resolve<ISemanticLog>().LogWarning(ex, w => w var logFactory = executionContext.Resolve<ILoggerFactory>();
.WriteProperty("action", "resolveField")
.WriteProperty("status", "failed")
.WriteProperty("field", context.FieldDefinition.Name));
logFactory.CreateLogger("GraphQL").LogError(ex, "Failed to resolve field {field}.", context.FieldDefinition.Name);
throw; throw;
} }
} }
@ -104,11 +102,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
} }
catch (Exception ex) catch (Exception ex)
{ {
executionContext.Resolve<ISemanticLog>().LogWarning(ex, w => w var logFactory = executionContext.Resolve<ILoggerFactory>();
.WriteProperty("action", "resolveField")
.WriteProperty("status", "failed")
.WriteProperty("field", context.FieldDefinition.Name));
logFactory.CreateLogger("GraphQL").LogError(ex, "Failed to resolve field {field}.", context.FieldDefinition.Name);
throw; throw;
} }
} }

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

@ -9,7 +9,6 @@ using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.OData; using Microsoft.OData;
using Microsoft.OData.Edm; using Microsoft.OData.Edm;
using NJsonSchema;
using Squidex.Domain.Apps.Core.GenerateFilters; using Squidex.Domain.Apps.Core.GenerateFilters;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Apps;

26
backend/src/Squidex.Domain.Apps.Entities/FodyWeavers.xsd

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="Equals" minOccurs="0" maxOccurs="1" type="xs:anyType" />
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

24
backend/src/Squidex.Domain.Apps.Entities/History/NotifoService.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using NodaTime; using NodaTime;
using Notifo.SDK; using Notifo.SDK;
@ -16,7 +17,6 @@ using Squidex.Domain.Apps.Events.Contents;
using Squidex.Domain.Users; using Squidex.Domain.Users;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.EventSourcing;
using Squidex.Log;
using Squidex.Shared.Identity; using Squidex.Shared.Identity;
using Squidex.Shared.Users; using Squidex.Shared.Users;
@ -30,14 +30,14 @@ namespace Squidex.Domain.Apps.Entities.History
private readonly NotifoOptions options; private readonly NotifoOptions options;
private readonly IUrlGenerator urlGenerator; private readonly IUrlGenerator urlGenerator;
private readonly IUserResolver userResolver; private readonly IUserResolver userResolver;
private readonly ISemanticLog log; private readonly ILogger<NotifoService> log;
private readonly IClock clock; private readonly IClock clock;
private readonly INotifoClient? client; private readonly INotifoClient? client;
public NotifoService(IOptions<NotifoOptions> options, public NotifoService(IOptions<NotifoOptions> options,
IUrlGenerator urlGenerator, IUrlGenerator urlGenerator,
IUserResolver userResolver, IUserResolver userResolver,
ISemanticLog log, ILogger<NotifoService> log,
IClock clock) IClock clock)
{ {
this.options = options.Value; this.options = options.Value;
@ -136,16 +136,11 @@ namespace Squidex.Domain.Apps.Entities.History
} }
catch (NotifoException ex) catch (NotifoException ex)
{ {
log.LogError(ex, w => w log.LogError(ex, "Failed to register user in notifo: {details}.", ex.ToString());
.WriteProperty("action", "RegisterToNotifo")
.WriteProperty("status", "Failed")
.WriteProperty("details", ex.ToString()));
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, w => w log.LogError(ex, "Failed to register user in notifo.");
.WriteProperty("action", "RegisterToNotifo")
.WriteProperty("status", "Failed"));
} }
} }
@ -196,16 +191,11 @@ namespace Squidex.Domain.Apps.Entities.History
} }
catch (NotifoException ex) catch (NotifoException ex)
{ {
log.LogError(ex, w => w log.LogError(ex, "Failed to push user to notifo: {details}.", ex.ToString());
.WriteProperty("action", "RegisterToNotifo")
.WriteProperty("status", "Failed")
.WriteProperty("details", ex.ToString()));
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, w => w log.LogError(ex, "Failed to push user to notifo.");
.WriteProperty("action", "RegisterToNotifo")
.WriteProperty("status", "Failed"));
} }
} }

23
backend/src/Squidex.Domain.Apps.Entities/Notifications/NotificationEmailSender.cs

@ -5,11 +5,11 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Email; using Squidex.Infrastructure.Email;
using Squidex.Log;
using Squidex.Shared.Identity; using Squidex.Shared.Identity;
using Squidex.Shared.Users; using Squidex.Shared.Users;
@ -19,7 +19,7 @@ namespace Squidex.Domain.Apps.Entities.Notifications
{ {
private readonly IEmailSender emailSender; private readonly IEmailSender emailSender;
private readonly IUrlGenerator urlGenerator; private readonly IUrlGenerator urlGenerator;
private readonly ISemanticLog log; private readonly ILogger<NotificationEmailSender> log;
private readonly NotificationEmailTextOptions texts; private readonly NotificationEmailTextOptions texts;
private sealed class TemplatesVars private sealed class TemplatesVars
@ -46,7 +46,7 @@ namespace Squidex.Domain.Apps.Entities.Notifications
IOptions<NotificationEmailTextOptions> texts, IOptions<NotificationEmailTextOptions> texts,
IEmailSender emailSender, IEmailSender emailSender,
IUrlGenerator urlGenerator, IUrlGenerator urlGenerator,
ISemanticLog log) ILogger<NotificationEmailSender> log)
{ {
this.texts = texts.Value; this.texts = texts.Value;
this.emailSender = emailSender; this.emailSender = emailSender;
@ -101,13 +101,13 @@ namespace Squidex.Domain.Apps.Entities.Notifications
{ {
if (string.IsNullOrWhiteSpace(emailBody)) if (string.IsNullOrWhiteSpace(emailBody))
{ {
LogWarning($"No email subject configured for {template}"); log.LogWarning("Cannot send email to {email}: No email subject configured for template {template}.", template, user.Email);
return; return;
} }
if (string.IsNullOrWhiteSpace(emailSubj)) if (string.IsNullOrWhiteSpace(emailSubj))
{ {
LogWarning($"No email body configured for {template}"); log.LogWarning("Cannot send email to {email}: No email body configured for template {template}.", template, user.Email);
return; return;
} }
@ -124,22 +124,11 @@ namespace Squidex.Domain.Apps.Entities.Notifications
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, w => w log.LogError(ex, "Failed to send notification to {email}.", user.Email);
.WriteProperty("action", "SendNotification")
.WriteProperty("status", "Failed"));
throw; throw;
} }
} }
private void LogWarning(string reason)
{
log.LogWarning(w => w
.WriteProperty("action", "SendNotification")
.WriteProperty("status", "Failed")
.WriteProperty("reason", reason));
}
private static string Format(string text, TemplatesVars vars) private static string Format(string text, TemplatesVars vars)
{ {
text = text.Replace("$APP_NAME", vars.AppName, StringComparison.Ordinal); text = text.Replace("$APP_NAME", vars.AppName, StringComparison.Ordinal);

4
backend/src/Squidex.Domain.Apps.Entities/Rules/DomainObject/RuleDomainObject.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Entities.Rules.Commands; using Squidex.Domain.Apps.Entities.Rules.Commands;
using Squidex.Domain.Apps.Entities.Rules.DomainObject.Guards; using Squidex.Domain.Apps.Entities.Rules.DomainObject.Guards;
using Squidex.Domain.Apps.Events; using Squidex.Domain.Apps.Events;
@ -13,7 +14,6 @@ using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.States; using Squidex.Infrastructure.States;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Rules.DomainObject namespace Squidex.Domain.Apps.Entities.Rules.DomainObject
{ {
@ -22,7 +22,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.DomainObject
private readonly IAppProvider appProvider; private readonly IAppProvider appProvider;
private readonly IRuleEnqueuer ruleEnqueuer; private readonly IRuleEnqueuer ruleEnqueuer;
public RuleDomainObject(IPersistenceFactory<State> factory, ISemanticLog log, public RuleDomainObject(IPersistenceFactory<State> factory, ILogger<RuleDomainObject> log,
IAppProvider appProvider, IRuleEnqueuer ruleEnqueuer) IAppProvider appProvider, IRuleEnqueuer ruleEnqueuer)
: base(factory, log) : base(factory, log)
{ {

25
backend/src/Squidex.Domain.Apps.Entities/Rules/RuleDequeuerGrain.cs

@ -7,6 +7,7 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Threading.Tasks.Dataflow; using System.Threading.Tasks.Dataflow;
using Microsoft.Extensions.Logging;
using NodaTime; using NodaTime;
using Orleans; using Orleans;
using Orleans.Runtime; using Orleans.Runtime;
@ -15,7 +16,6 @@ using Squidex.Domain.Apps.Core.Rules;
using Squidex.Domain.Apps.Entities.Rules.Repositories; using Squidex.Domain.Apps.Entities.Rules.Repositories;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Tasks; using Squidex.Infrastructure.Tasks;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Rules namespace Squidex.Domain.Apps.Entities.Rules
{ {
@ -26,12 +26,13 @@ namespace Squidex.Domain.Apps.Entities.Rules
private readonly IRuleService ruleService; private readonly IRuleService ruleService;
private readonly ConcurrentDictionary<DomainId, bool> executing = new ConcurrentDictionary<DomainId, bool>(); private readonly ConcurrentDictionary<DomainId, bool> executing = new ConcurrentDictionary<DomainId, bool>();
private readonly IClock clock; private readonly IClock clock;
private readonly ISemanticLog log; private readonly ILogger<RuleDequeuerGrain> log;
public RuleDequeuerGrain( public RuleDequeuerGrain(
IRuleService ruleService, IRuleService ruleService,
IRuleEventRepository ruleEventRepository, IRuleEventRepository ruleEventRepository,
ISemanticLog log, IClock clock) ILogger<RuleDequeuerGrain> log,
IClock clock)
{ {
this.ruleEventRepository = ruleEventRepository; this.ruleEventRepository = ruleEventRepository;
this.ruleService = ruleService; this.ruleService = ruleService;
@ -77,9 +78,7 @@ namespace Squidex.Domain.Apps.Entities.Rules
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, w => w log.LogError(ex, "Failed to query rule events.");
.WriteProperty("action", "QueryRuleEvents")
.WriteProperty("status", "Failed"));
} }
} }
@ -115,19 +114,15 @@ namespace Squidex.Domain.Apps.Entities.Rules
if (response.Status == RuleResult.Failed) if (response.Status == RuleResult.Failed)
{ {
log.LogWarning(response.Exception!, w => w log.LogWarning(response.Exception, "Failed to execute rule event with rule id {ruleId}/{description}: {dump}",
.WriteProperty("action", "SendRuleEvent") @event.Job.RuleId,
.WriteProperty("status", "Failed") @event.Job.Description,
.WriteProperty("ruleId", @event.Job.RuleId.ToString()) response.Dump);
.WriteProperty("ruleDescription", @event.Job.Description)
.WriteProperty("dump", response.Dump));
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, w => w log.LogError(ex, "Failed to execute rule event with internal error.");
.WriteProperty("action", "SendRuleEvent")
.WriteProperty("status", "Failed"));
} }
finally finally
{ {

19
backend/src/Squidex.Domain.Apps.Entities/Rules/Runner/RuleRunnerGrain.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using Microsoft.Extensions.Logging;
using Orleans; using Orleans;
using Orleans.Runtime; using Orleans.Runtime;
using Squidex.Caching; using Squidex.Caching;
@ -15,7 +16,6 @@ using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Orleans; using Squidex.Infrastructure.Orleans;
using Squidex.Infrastructure.States; using Squidex.Infrastructure.States;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Log;
using TaskExtensions = Squidex.Infrastructure.Tasks.TaskExtensions; using TaskExtensions = Squidex.Infrastructure.Tasks.TaskExtensions;
#pragma warning disable RECS0015 // If an extension method is called as static method convert it to method syntax #pragma warning disable RECS0015 // If an extension method is called as static method convert it to method syntax
@ -32,7 +32,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Runner
private readonly IEventDataFormatter eventDataFormatter; private readonly IEventDataFormatter eventDataFormatter;
private readonly IRuleEventRepository ruleEventRepository; private readonly IRuleEventRepository ruleEventRepository;
private readonly IRuleService ruleService; private readonly IRuleService ruleService;
private readonly ISemanticLog log; private readonly ILogger<RuleRunnerGrain> log;
private CancellationTokenSource? currentJobToken; private CancellationTokenSource? currentJobToken;
private IGrainReminder? currentReminder; private IGrainReminder? currentReminder;
private bool isStopping; private bool isStopping;
@ -55,7 +55,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Runner
IEventDataFormatter eventDataFormatter, IEventDataFormatter eventDataFormatter,
IRuleEventRepository ruleEventRepository, IRuleEventRepository ruleEventRepository,
IRuleService ruleService, IRuleService ruleService,
ISemanticLog log) ILogger<RuleRunnerGrain> log)
{ {
this.state = state; this.state = state;
this.appProvider = appProvider; this.appProvider = appProvider;
@ -187,10 +187,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Runner
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, w => w log.LogError(ex, "Failed to run rule with ID {ruleId}.", currentState.RuleId);
.WriteProperty("action", "runRule")
.WriteProperty("status", "failed")
.WriteProperty("ruleId", currentState.RuleId?.ToString()));
} }
finally finally
{ {
@ -234,9 +231,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Runner
throw job.EnrichmentError; throw job.EnrichmentError;
} }
log.LogWarning(job.EnrichmentError, w => w log.LogWarning(job.EnrichmentError, "Failed to run rule with ID {ruleId}, continue with next job.", context.RuleId);
.WriteProperty("action", "runRule")
.WriteProperty("status", "failedPartially"));
} }
} }
} }
@ -276,9 +271,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.Runner
throw; throw;
} }
log.LogWarning(ex, w => w log.LogWarning(ex, "Failed to run rule with ID {ruleId}, continue with next job.", context.RuleId);
.WriteProperty("action", "runRule")
.WriteProperty("status", "failedPartially"));
} }
finally finally
{ {

4
backend/src/Squidex.Domain.Apps.Entities/Schemas/DomainObject/SchemaDomainObject.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Core.EventSynchronization; using Squidex.Domain.Apps.Core.EventSynchronization;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Entities.Schemas.Commands; using Squidex.Domain.Apps.Entities.Schemas.Commands;
@ -17,13 +18,12 @@ using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Orleans; using Squidex.Infrastructure.Orleans;
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.States; using Squidex.Infrastructure.States;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject
{ {
public sealed partial class SchemaDomainObject : DomainObject<SchemaDomainObject.State> public sealed partial class SchemaDomainObject : DomainObject<SchemaDomainObject.State>
{ {
public SchemaDomainObject(IPersistenceFactory<State> persistence, ISemanticLog log) public SchemaDomainObject(IPersistenceFactory<State> persistence, ILogger<SchemaDomainObject> log)
: base(persistence, log) : base(persistence, log)
{ {
} }

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

@ -185,7 +185,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes
if (existingId != default) if (existingId != default)
{ {
throw new ValidationException(T.Get("apps.nameAlreadyExists")); throw new ValidationException(T.Get("schemas.nameAlreadyExists"));
} }
} }
catch catch

12
backend/src/Squidex.Domain.Apps.Entities/Search/SearchManager.cs

@ -5,7 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using Squidex.Log; using Microsoft.Extensions.Logging;
namespace Squidex.Domain.Apps.Entities.Search namespace Squidex.Domain.Apps.Entities.Search
{ {
@ -13,9 +13,9 @@ namespace Squidex.Domain.Apps.Entities.Search
{ {
private static readonly SearchResults Empty = new SearchResults(); private static readonly SearchResults Empty = new SearchResults();
private readonly IEnumerable<ISearchSource> searchSources; private readonly IEnumerable<ISearchSource> searchSources;
private readonly ISemanticLog log; private readonly ILogger<SearchManager> log;
public SearchManager(IEnumerable<ISearchSource> searchSources, ISemanticLog log) public SearchManager(IEnumerable<ISearchSource> searchSources, ILogger<SearchManager> log)
{ {
this.searchSources = searchSources; this.searchSources = searchSources;
@ -46,11 +46,7 @@ namespace Squidex.Domain.Apps.Entities.Search
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, query, (c, w) => w log.LogError(ex, "Failed to execute search from source {source} with query '{query}'.", source, query);
.WriteProperty("operation", "search")
.WriteProperty("status", "Failed")
.WriteProperty("query", query));
return Empty; return Empty;
} }
} }

10
backend/src/Squidex.Domain.Users/DefaultUserService.cs

@ -7,9 +7,9 @@
using System.Security.Claims; using System.Security.Claims;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Security; using Squidex.Infrastructure.Security;
using Squidex.Log;
using Squidex.Shared; using Squidex.Shared;
using Squidex.Shared.Identity; using Squidex.Shared.Identity;
using Squidex.Shared.Users; using Squidex.Shared.Users;
@ -21,10 +21,10 @@ namespace Squidex.Domain.Users
private readonly UserManager<IdentityUser> userManager; private readonly UserManager<IdentityUser> userManager;
private readonly IUserFactory userFactory; private readonly IUserFactory userFactory;
private readonly IEnumerable<IUserEvents> userEvents; private readonly IEnumerable<IUserEvents> userEvents;
private readonly ISemanticLog log; private readonly ILogger<DefaultUserService> log;
public DefaultUserService(UserManager<IdentityUser> userManager, IUserFactory userFactory, public DefaultUserService(UserManager<IdentityUser> userManager, IUserFactory userFactory,
IEnumerable<IUserEvents> userEvents, ISemanticLog log) IEnumerable<IUserEvents> userEvents, ILogger<DefaultUserService> log)
{ {
this.userManager = userManager; this.userManager = userManager;
this.userFactory = userFactory; this.userFactory = userFactory;
@ -207,9 +207,7 @@ namespace Squidex.Domain.Users
} }
catch (Exception ex2) catch (Exception ex2)
{ {
log.LogError(ex2, w => w log.LogError(ex2, "Failed to cleanup user after creation failed.");
.WriteProperty("action", "CleanupUser")
.WriteProperty("status", "Failed"));
} }
throw; throw;

11
backend/src/Squidex.Domain.Users/UserManagerExtensions.cs

@ -1,4 +1,4 @@
// ========================================================================== // ==========================================================================
// Squidex Headless CMS // Squidex Headless CMS
// ========================================================================== // ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt) // Copyright (c) Squidex UG (haftungsbeschraenkt)
@ -8,16 +8,16 @@
using System.Security.Claims; using System.Security.Claims;
using System.Text; using System.Text;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
using Squidex.Log;
using Squidex.Shared.Identity; using Squidex.Shared.Identity;
namespace Squidex.Domain.Users namespace Squidex.Domain.Users
{ {
internal static class UserManagerExtensions internal static class UserManagerExtensions
{ {
public static async Task Throw(this Task<IdentityResult> task, ISemanticLog log) public static async Task Throw(this Task<IdentityResult> task, ILogger log)
{ {
var result = await task; var result = await task;
@ -46,10 +46,7 @@ namespace Squidex.Domain.Users
var errorMessage = errorMessageBuilder.ToString(); var errorMessage = errorMessageBuilder.ToString();
log.LogError(errorMessage, (ctx, w) => w log.LogError("Identity operation failed: {errorMessage}.", errorMessage);
.WriteProperty("action", "IdentityOperation")
.WriteProperty("status", "Failed")
.WriteProperty("message", ctx));
throw new ValidationException(result.Errors.Select(x => new ValidationError(Localize(x))).ToList()); throw new ValidationException(result.Errors.Select(x => new ValidationError(Localize(x))).ToList());
} }

3
backend/src/Squidex.Infrastructure.GetEventStore/EventSourcing/GetEventStoreSubscription.cs

@ -30,7 +30,8 @@ namespace Squidex.Infrastructure.EventSourcing
var streamName = await projectionClient.CreateProjectionAsync(streamFilter); var streamName = await projectionClient.CreateProjectionAsync(streamFilter);
async Task OnEvent(StreamSubscription subscription, ResolvedEvent @event, CancellationToken ct) async Task OnEvent(StreamSubscription subscription, ResolvedEvent @event,
CancellationToken ct)
{ {
var storedEvent = Formatter.Read(@event, prefix, serializer); var storedEvent = Formatter.Read(@event, prefix, serializer);

2
backend/src/Squidex.Infrastructure.MongoDb/MongoDb/Queries/FilterBuilder.cs

@ -20,7 +20,7 @@ namespace Squidex.Infrastructure.MongoDb.Queries
{ {
if (!supportsSearch) if (!supportsSearch)
{ {
throw new ValidationException(T.Get("queries.fullTextNotSupported")); throw new ValidationException(T.Get("common.fullTextNotSupported"));
} }
return (Builders<TDocument>.Filter.Text(query.FullText), false); return (Builders<TDocument>.Filter.Text(query.FullText), false);

23
backend/src/Squidex.Infrastructure/Commands/DomainObject.cs

@ -5,9 +5,9 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using Microsoft.Extensions.Logging;
using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.States; using Squidex.Infrastructure.States;
using Squidex.Log;
namespace Squidex.Infrastructure.Commands namespace Squidex.Infrastructure.Commands
{ {
@ -16,7 +16,7 @@ namespace Squidex.Infrastructure.Commands
private readonly List<Envelope<IEvent>> uncomittedEvents = new List<Envelope<IEvent>>(); private readonly List<Envelope<IEvent>> uncomittedEvents = new List<Envelope<IEvent>>();
private readonly SnapshotList<T> snapshots = new SnapshotList<T>(); private readonly SnapshotList<T> snapshots = new SnapshotList<T>();
private readonly IPersistenceFactory<T> factory; private readonly IPersistenceFactory<T> factory;
private readonly ISemanticLog log; private readonly ILogger log;
private IPersistence<T>? persistence; private IPersistence<T>? persistence;
private bool isLoaded; private bool isLoaded;
private DomainId uniqueId; private DomainId uniqueId;
@ -42,7 +42,8 @@ namespace Squidex.Infrastructure.Commands
set => snapshots.Capacity = value; set => snapshots.Capacity = value;
} }
protected DomainObject(IPersistenceFactory<T> factory, ISemanticLog log) protected DomainObject(IPersistenceFactory<T> factory,
ILogger log)
{ {
Guard.NotNull(factory); Guard.NotNull(factory);
Guard.NotNull(log); Guard.NotNull(log);
@ -120,15 +121,15 @@ namespace Squidex.Infrastructure.Commands
} }
else else
{ {
var logContext = (id: uniqueId.ToString(), name: GetType().Name); var watch = ValueStopwatch.StartNew();
try
using (log.MeasureInformation(logContext, (ctx, w) => w
.WriteProperty("action", "ActivateDomainObject")
.WriteProperty("domainObjectType", ctx.name)
.WriteProperty("domainObjectKey", ctx.id)))
{ {
await ReadAsync(); await ReadAsync();
} }
finally
{
log.LogInformation("Activated domain object of type {type} with ID {id} in {time}.", GetType(), UniqueId, watch.Stop());
}
} }
isLoaded = true; isLoaded = true;
@ -347,9 +348,7 @@ namespace Squidex.Infrastructure.Commands
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, w => w log.LogError(ex, "Failed to repair snapshot for domain object of type {type} with ID {id}.", GetType(), UniqueId);
.WriteProperty("action", "RepairSnapshot")
.WriteProperty("status", "Failed"));
} }
} }
} }

49
backend/src/Squidex.Infrastructure/Commands/LogCommandMiddleware.cs

@ -5,64 +5,51 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using Squidex.Log; using Microsoft.Extensions.Logging;
namespace Squidex.Infrastructure.Commands namespace Squidex.Infrastructure.Commands
{ {
public sealed class LogCommandMiddleware : ICommandMiddleware public sealed class LogCommandMiddleware : ICommandMiddleware
{ {
private readonly ISemanticLog log; private readonly ILogger<LogCommandMiddleware> log;
public LogCommandMiddleware(ISemanticLog log) public LogCommandMiddleware(ILogger<LogCommandMiddleware> log)
{ {
this.log = log; this.log = log;
} }
public async Task HandleAsync(CommandContext context, NextDelegate next) public async Task HandleAsync(CommandContext context, NextDelegate next)
{ {
var logContext = (id: context.ContextId.ToString(), command: context.Command.GetType().Name); var type = context.Command.GetType();
try try
{ {
log.LogDebug(logContext, (ctx, w) => w if (log.IsEnabled(LogLevel.Debug))
.WriteProperty("action", "HandleCommand.") {
.WriteProperty("actionId", ctx.id) log.LogDebug("Command {command} with ID {id} started.", type, context.ContextId);
.WriteProperty("status", "Started") }
.WriteProperty("commandType", ctx.command));
using (log.MeasureInformation(logContext, (ctx, w) => w var watch = ValueStopwatch.StartNew();
.WriteProperty("action", "HandleCommand.") try
.WriteProperty("actionId", ctx.id)
.WriteProperty("status", "Completed")
.WriteProperty("commandType", ctx.command)))
{ {
await next(context); await next(context);
}
log.LogInformation(logContext, (ctx, w) => w log.LogInformation("Command {command} with ID {id} succeeded.", type, context.ContextId);
.WriteProperty("action", "HandleCommand.") }
.WriteProperty("actionId", ctx.id) finally
.WriteProperty("status", "Succeeded") {
.WriteProperty("commandType", ctx.command)); log.LogInformation("Command {command} with ID {id} completed after {time}ms.", type, context.ContextId, watch.Stop());
}
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, logContext, (ctx, w) => w log.LogError(ex, "Command {command} with ID {id} failed.", type, context.ContextId);
.WriteProperty("action", "HandleCommand.")
.WriteProperty("actionId", ctx.id)
.WriteProperty("status", "Failed")
.WriteProperty("commandType", ctx.command));
throw; throw;
} }
if (!context.IsCompleted) if (!context.IsCompleted)
{ {
log.LogFatal(logContext, (ctx, w) => w log.LogCritical("Command {command} with ID {id} not handled.", type, context.ContextId);
.WriteProperty("action", "HandleCommand.")
.WriteProperty("actionId", ctx.id)
.WriteProperty("status", "Unhandled")
.WriteProperty("commandType", ctx.command));
} }
} }
} }

14
backend/src/Squidex.Infrastructure/Commands/Rebuilder.cs

@ -7,11 +7,11 @@
using System.Threading.Tasks.Dataflow; using System.Threading.Tasks.Dataflow;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Squidex.Caching; using Squidex.Caching;
using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.States; using Squidex.Infrastructure.States;
using Squidex.Infrastructure.Tasks; using Squidex.Infrastructure.Tasks;
using Squidex.Log;
#pragma warning disable RECS0108 // Warns about static fields in generic types #pragma warning disable RECS0108 // Warns about static fields in generic types
@ -22,7 +22,7 @@ namespace Squidex.Infrastructure.Commands
private readonly ILocalCache localCache; private readonly ILocalCache localCache;
private readonly IEventStore eventStore; private readonly IEventStore eventStore;
private readonly IServiceProvider serviceProvider; private readonly IServiceProvider serviceProvider;
private readonly ISemanticLog log; private readonly ILogger<Rebuilder> log;
private static class Factory<T, TState> where T : DomainObject<TState> where TState : class, IDomainState<TState>, new() private static class Factory<T, TState> where T : DomainObject<TState> where TState : class, IDomainState<TState>, new()
{ {
@ -38,12 +38,12 @@ namespace Squidex.Infrastructure.Commands
ILocalCache localCache, ILocalCache localCache,
IEventStore eventStore, IEventStore eventStore,
IServiceProvider serviceProvider, IServiceProvider serviceProvider,
ISemanticLog log) ILogger<Rebuilder> log)
{ {
this.eventStore = eventStore; this.eventStore = eventStore;
this.serviceProvider = serviceProvider; this.serviceProvider = serviceProvider;
this.log = log;
this.localCache = localCache; this.localCache = localCache;
this.log = log;
} }
public virtual Task RebuildAsync<T, TState>(string filter, int batchSize, public virtual Task RebuildAsync<T, TState>(string filter, int batchSize,
@ -119,11 +119,7 @@ namespace Squidex.Infrastructure.Commands
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogWarning(ex, w => w log.LogWarning(ex, "Found corrupt domain object of type {type} with ID {id}.", typeof(T), id);
.WriteProperty("reason", "CorruptData")
.WriteProperty("domainObjectId", id.ToString())
.WriteProperty("domainObjectType", typeof(T).Name));
Interlocked.Increment(ref handlerErrors); Interlocked.Increment(ref handlerErrors);
} }
} }

41
backend/src/Squidex.Infrastructure/EventSourcing/Grains/EventConsumerGrain.cs

@ -6,9 +6,9 @@
// ========================================================================== // ==========================================================================
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Microsoft.Extensions.Logging;
using Squidex.Infrastructure.Orleans; using Squidex.Infrastructure.Orleans;
using Squidex.Infrastructure.Tasks; using Squidex.Infrastructure.Tasks;
using Squidex.Log;
namespace Squidex.Infrastructure.EventSourcing.Grains namespace Squidex.Infrastructure.EventSourcing.Grains
{ {
@ -18,7 +18,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
private readonly IGrainState<EventConsumerState> state; private readonly IGrainState<EventConsumerState> state;
private readonly IEventDataFormatter eventDataFormatter; private readonly IEventDataFormatter eventDataFormatter;
private readonly IEventStore eventStore; private readonly IEventStore eventStore;
private readonly ISemanticLog log; private readonly ILogger<EventConsumerGrain> log;
private readonly SemaphoreSlim semaphore = new SemaphoreSlim(1); private readonly SemaphoreSlim semaphore = new SemaphoreSlim(1);
private IEventSubscription? currentSubscription; private IEventSubscription? currentSubscription;
private IEventConsumer? eventConsumer; private IEventConsumer? eventConsumer;
@ -34,7 +34,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
IGrainState<EventConsumerState> state, IGrainState<EventConsumerState> state,
IEventStore eventStore, IEventStore eventStore,
IEventDataFormatter eventDataFormatter, IEventDataFormatter eventDataFormatter,
ISemanticLog log) ILogger<EventConsumerGrain> log)
{ {
this.eventStore = eventStore; this.eventStore = eventStore;
this.eventDataFormatter = eventDataFormatter; this.eventDataFormatter = eventDataFormatter;
@ -68,9 +68,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogFatal(ex, w => w log.LogCritical(ex, "Failed to complete consumer.");
.WriteProperty("action", "CompleteConsumer")
.WriteProperty("status", "Failed"));
} }
} }
} }
@ -222,11 +220,8 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
ex = new AggregateException(ex, unsubscribeException); ex = new AggregateException(ex, unsubscribeException);
} }
log.LogFatal(ex, w => w log.LogCritical(ex, "Failed to update consumer {consumer} at position {position} from {caller}.",
.WriteProperty("action", caller) eventConsumer!.Name, position, caller);
.WriteProperty("status", "Failed")
.WriteProperty("eventPosition", position)
.WriteProperty("eventConsumer", eventConsumer!.Name));
State = previousState.Stopped(ex); State = previousState.Stopped(ex);
} }
@ -244,21 +239,19 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
private async Task ClearAsync() private async Task ClearAsync()
{ {
var logContext = (actionId: Guid.NewGuid().ToString(), consumer: eventConsumer!.Name); if (log.IsEnabled(LogLevel.Debug))
{
log.LogDebug(logContext, (ctx, w) => w log.LogDebug("Event consumer {consumer} reset started", eventConsumer!.Name);
.WriteProperty("action", "EventConsumerReset") }
.WriteProperty("actionId", ctx.actionId)
.WriteProperty("status", "Started")
.WriteProperty("eventConsumer", ctx.consumer));
using (log.MeasureInformation(logContext, (ctx, w) => w var watch = ValueStopwatch.StartNew();
.WriteProperty("action", "EventConsumerReset") try
.WriteProperty("actionId", ctx.actionId) {
.WriteProperty("status", "Completed") await eventConsumer!.ClearAsync();
.WriteProperty("eventConsumer", ctx.consumer))) }
finally
{ {
await eventConsumer.ClearAsync(); log.LogDebug("Event consumer {consumer} reset completed after {time}ms.", eventConsumer!.Name, watch.Stop());
} }
} }

10
backend/src/Squidex.Infrastructure/Log/BackgroundRequestLogStore.cs

@ -6,16 +6,16 @@
// ========================================================================== // ==========================================================================
using System.Collections.Concurrent; using System.Collections.Concurrent;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Squidex.Infrastructure.Timers; using Squidex.Infrastructure.Timers;
using Squidex.Log;
namespace Squidex.Infrastructure.Log namespace Squidex.Infrastructure.Log
{ {
public sealed class BackgroundRequestLogStore : DisposableObjectBase, IRequestLogStore public sealed class BackgroundRequestLogStore : DisposableObjectBase, IRequestLogStore
{ {
private readonly IRequestLogRepository logRepository; private readonly IRequestLogRepository logRepository;
private readonly ISemanticLog log; private readonly ILogger<BackgroundRequestLogStore> log;
private readonly CompletionTimer timer; private readonly CompletionTimer timer;
private readonly RequestLogStoreOptions options; private readonly RequestLogStoreOptions options;
private ConcurrentQueue<Request> jobs = new ConcurrentQueue<Request>(); private ConcurrentQueue<Request> jobs = new ConcurrentQueue<Request>();
@ -25,7 +25,7 @@ namespace Squidex.Infrastructure.Log
public bool IsEnabled => options.StoreEnabled; public bool IsEnabled => options.StoreEnabled;
public BackgroundRequestLogStore(IOptions<RequestLogStoreOptions> options, public BackgroundRequestLogStore(IOptions<RequestLogStoreOptions> options,
IRequestLogRepository logRepository, ISemanticLog log) IRequestLogRepository logRepository, ILogger<BackgroundRequestLogStore> log)
{ {
this.options = options.Value; this.options = options.Value;
@ -84,9 +84,7 @@ namespace Squidex.Infrastructure.Log
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, w => w log.LogError(ex, "Failed to track usage in background.");
.WriteProperty("action", "TrackUsage")
.WriteProperty("status", "Failed"));
} }
} }

33
backend/src/Squidex.Infrastructure/Migrations/Migrator.cs

@ -5,19 +5,20 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using Squidex.Log; using Microsoft.Extensions.Logging;
namespace Squidex.Infrastructure.Migrations namespace Squidex.Infrastructure.Migrations
{ {
public sealed class Migrator public sealed class Migrator
{ {
private readonly ISemanticLog log;
private readonly IMigrationStatus migrationStatus; private readonly IMigrationStatus migrationStatus;
private readonly IMigrationPath migrationPath; private readonly IMigrationPath migrationPath;
private readonly ILogger<Migrator> log;
public int LockWaitMs { get; set; } = 500; public int LockWaitMs { get; set; } = 500;
public Migrator(IMigrationStatus migrationStatus, IMigrationPath migrationPath, ISemanticLog log) public Migrator(IMigrationStatus migrationStatus, IMigrationPath migrationPath,
ILogger<Migrator> log)
{ {
this.migrationStatus = migrationStatus; this.migrationStatus = migrationStatus;
this.migrationPath = migrationPath; this.migrationPath = migrationPath;
@ -50,28 +51,19 @@ namespace Squidex.Infrastructure.Migrations
{ {
var name = migration.ToString()!; var name = migration.ToString()!;
log.LogInformation(w => w log.LogInformation("Migration {migration} started.", name);
.WriteProperty("action", "Migration")
.WriteProperty("status", "Started")
.WriteProperty("migrator", name));
try try
{ {
using (log.MeasureInformation(w => w var watch = ValueStopwatch.StartNew();
.WriteProperty("action", "Migration")
.WriteProperty("status", "Completed")
.WriteProperty("migrator", name)))
{
await migration.UpdateAsync(ct); await migration.UpdateAsync(ct);
}
log.LogInformation("Migration {migration} completed after {time}ms.", name, watch.Stop());
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogFatal(ex, w => w log.LogCritical(ex, "Migration {migration} failed.", name);
.WriteProperty("action", "Migration")
.WriteProperty("status", "Failed")
.WriteProperty("migrator", name));
throw new MigrationFailedException(name, ex); throw new MigrationFailedException(name, ex);
} }
} }
@ -94,10 +86,7 @@ namespace Squidex.Infrastructure.Migrations
{ {
while (!await migrationStatus.TryLockAsync(ct)) while (!await migrationStatus.TryLockAsync(ct))
{ {
log.LogInformation(w => w log.LogInformation("Could not acquire lock to start migrating. Tryping again in {time}ms.", LockWaitMs);
.WriteProperty("action", "Migrate")
.WriteProperty("mesage", $"Waiting {LockWaitMs}ms to acquire lock."));
await Task.Delay(LockWaitMs, ct); await Task.Delay(LockWaitMs, ct);
} }
} }

16
backend/src/Squidex.Infrastructure/Orleans/LoggingFilter.cs

@ -5,18 +5,18 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using Microsoft.Extensions.Logging;
using Orleans; using Orleans;
using Squidex.Log;
namespace Squidex.Infrastructure.Orleans namespace Squidex.Infrastructure.Orleans
{ {
public sealed class LoggingFilter : IIncomingGrainCallFilter public sealed class LoggingFilter : IIncomingGrainCallFilter
{ {
private readonly ISemanticLog log; private readonly ILoggerFactory logFactory;
public LoggingFilter(ISemanticLog log) public LoggingFilter(ILoggerFactory logFactory)
{ {
this.log = log; this.logFactory = logFactory;
} }
public async Task Invoke(IIncomingGrainCallContext context) public async Task Invoke(IIncomingGrainCallContext context)
@ -48,11 +48,9 @@ namespace Squidex.Infrastructure.Orleans
private void Log(IIncomingGrainCallContext context, Exception ex) private void Log(IIncomingGrainCallContext context, Exception ex)
{ {
log.LogError(ex, w => w var log = logFactory.CreateLogger(context.Grain.GetType());
.WriteProperty("action", "GrainInvoked")
.WriteProperty("status", "Failed") log.LogError(ex, "Failed to execute method of grain.", context.ImplementationMethod);
.WriteProperty("grain", context.Grain.ToString())
.WriteProperty("grainMethod", context.ImplementationMethod.ToString()));
} }
} }
} }

1
backend/src/Squidex.Infrastructure/Plugins/PluginManager.cs

@ -111,6 +111,7 @@ namespace Squidex.Infrastructure.Plugins
var status = exceptions.Count > 0 ? "CompletedWithErrors" : "Completed"; var status = exceptions.Count > 0 ? "CompletedWithErrors" : "Completed";
log.LogInformation(w => w log.LogInformation(w => w
.WriteProperty("message", "Plugins loaded.")
.WriteProperty("action", "pluginsLoaded") .WriteProperty("action", "pluginsLoaded")
.WriteProperty("status", status) .WriteProperty("status", status)
.WriteArray("errors", e => .WriteArray("errors", e =>

11
backend/src/Squidex.Infrastructure/UsageTracking/BackgroundUsageTracker.cs

@ -6,8 +6,8 @@
// ========================================================================== // ==========================================================================
using System.Collections.Concurrent; using System.Collections.Concurrent;
using Microsoft.Extensions.Logging;
using Squidex.Infrastructure.Timers; using Squidex.Infrastructure.Timers;
using Squidex.Log;
namespace Squidex.Infrastructure.UsageTracking namespace Squidex.Infrastructure.UsageTracking
{ {
@ -16,13 +16,14 @@ namespace Squidex.Infrastructure.UsageTracking
private const int Intervall = 60 * 1000; private const int Intervall = 60 * 1000;
private const string FallbackCategory = "*"; private const string FallbackCategory = "*";
private readonly IUsageRepository usageRepository; private readonly IUsageRepository usageRepository;
private readonly ISemanticLog log; private readonly ILogger<BackgroundUsageTracker> log;
private readonly CompletionTimer timer; private readonly CompletionTimer timer;
private ConcurrentDictionary<(string Key, string Category, DateTime Date), Counters> jobs = new ConcurrentDictionary<(string Key, string Category, DateTime Date), Counters>(); private ConcurrentDictionary<(string Key, string Category, DateTime Date), Counters> jobs = new ConcurrentDictionary<(string Key, string Category, DateTime Date), Counters>();
public bool ForceWrite { get; set; } public bool ForceWrite { get; set; }
public BackgroundUsageTracker(IUsageRepository usageRepository, ISemanticLog log) public BackgroundUsageTracker(IUsageRepository usageRepository,
ILogger<BackgroundUsageTracker> log)
{ {
this.usageRepository = usageRepository; this.usageRepository = usageRepository;
@ -78,9 +79,7 @@ namespace Squidex.Infrastructure.UsageTracking
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, w => w log.LogError(ex, "Failed to track usage in background.");
.WriteProperty("action", "TrackUsage")
.WriteProperty("status", "Failed"));
} }
} }

6
backend/src/Squidex.Shared/Texts.it.resx

@ -835,9 +835,6 @@
<data name="login.githubPrivateEmail" xml:space="preserve"> <data name="login.githubPrivateEmail" xml:space="preserve">
<value>Il tuo indirizzo email è impostato su privato in Github. Impostalo come pubblico per poter utilizzare il login Github.</value> <value>Il tuo indirizzo email è impostato su privato in Github. Impostalo come pubblico per poter utilizzare il login Github.</value>
</data> </data>
<data name="login.noEmailAddress" xml:space="preserve">
<value>We cannot get the email address from authentication provider.</value>
</data>
<data name="rules.ruleAlreadyRunning" xml:space="preserve"> <data name="rules.ruleAlreadyRunning" xml:space="preserve">
<value>È in esecuzione un'altra regola.</value> <value>È in esecuzione un'altra regola.</value>
</data> </data>
@ -1090,6 +1087,9 @@
<data name="users.logout.title" xml:space="preserve"> <data name="users.logout.title" xml:space="preserve">
<value>Esci</value> <value>Esci</value>
</data> </data>
<data name="users.noEmailAddress" xml:space="preserve">
<value>We cannot get the email address from authentication provider.</value>
</data>
<data name="users.profile.addLoginDone" xml:space="preserve"> <data name="users.profile.addLoginDone" xml:space="preserve">
<value>La login è stata aggiunta con successo.</value> <value>La login è stata aggiunta con successo.</value>
</data> </data>

6
backend/src/Squidex.Shared/Texts.nl.resx

@ -835,9 +835,6 @@
<data name="login.githubPrivateEmail" xml:space="preserve"> <data name="login.githubPrivateEmail" xml:space="preserve">
<value>Jouw e-mailadres is ingesteld op privé in Github. Stel het in op openbaar om Github-login te gebruiken.</value> <value>Jouw e-mailadres is ingesteld op privé in Github. Stel het in op openbaar om Github-login te gebruiken.</value>
</data> </data>
<data name="login.noEmailAddress" xml:space="preserve">
<value>We cannot get the email address from authentication provider.</value>
</data>
<data name="rules.ruleAlreadyRunning" xml:space="preserve"> <data name="rules.ruleAlreadyRunning" xml:space="preserve">
<value>Er wordt al een andere regel uitgevoerd.</value> <value>Er wordt al een andere regel uitgevoerd.</value>
</data> </data>
@ -1090,6 +1087,9 @@
<data name="users.logout.title" xml:space="preserve"> <data name="users.logout.title" xml:space="preserve">
<value>Uitloggen</value> <value>Uitloggen</value>
</data> </data>
<data name="users.noEmailAddress" xml:space="preserve">
<value>We cannot get the email address from authentication provider.</value>
</data>
<data name="users.profile.addLoginDone" xml:space="preserve"> <data name="users.profile.addLoginDone" xml:space="preserve">
<value>Login succesvol toegevoegd.</value> <value>Login succesvol toegevoegd.</value>
</data> </data>

6
backend/src/Squidex.Shared/Texts.resx

@ -835,9 +835,6 @@
<data name="login.githubPrivateEmail" xml:space="preserve"> <data name="login.githubPrivateEmail" xml:space="preserve">
<value>Your email address is set to private in Github. Please set it to public to use Github login.</value> <value>Your email address is set to private in Github. Please set it to public to use Github login.</value>
</data> </data>
<data name="login.noEmailAddress" xml:space="preserve">
<value>We cannot get the email address from authentication provider.</value>
</data>
<data name="rules.ruleAlreadyRunning" xml:space="preserve"> <data name="rules.ruleAlreadyRunning" xml:space="preserve">
<value>Another rule is already running.</value> <value>Another rule is already running.</value>
</data> </data>
@ -1090,6 +1087,9 @@
<data name="users.logout.title" xml:space="preserve"> <data name="users.logout.title" xml:space="preserve">
<value>Logout</value> <value>Logout</value>
</data> </data>
<data name="users.noEmailAddress" xml:space="preserve">
<value>We cannot get the email address from authentication provider.</value>
</data>
<data name="users.profile.addLoginDone" xml:space="preserve"> <data name="users.profile.addLoginDone" xml:space="preserve">
<value>Login added successfully.</value> <value>Login added successfully.</value>
</data> </data>

6
backend/src/Squidex.Shared/Texts.zh.resx

@ -835,9 +835,6 @@
<data name="login.githubPrivateEmail" xml:space="preserve"> <data name="login.githubPrivateEmail" xml:space="preserve">
<value>您的邮箱在 Github 中设置为私有。请设置为公开以使用 Github 登录。</value> <value>您的邮箱在 Github 中设置为私有。请设置为公开以使用 Github 登录。</value>
</data> </data>
<data name="login.noEmailAddress" xml:space="preserve">
<value>We cannot get the email address from authentication provider.</value>
</data>
<data name="rules.ruleAlreadyRunning" xml:space="preserve"> <data name="rules.ruleAlreadyRunning" xml:space="preserve">
<value>另一个规则已经在运行。</value> <value>另一个规则已经在运行。</value>
</data> </data>
@ -1090,6 +1087,9 @@
<data name="users.logout.title" xml:space="preserve"> <data name="users.logout.title" xml:space="preserve">
<value>注销</value> <value>注销</value>
</data> </data>
<data name="users.noEmailAddress" xml:space="preserve">
<value>We cannot get the email address from authentication provider.</value>
</data>
<data name="users.profile.addLoginDone" xml:space="preserve"> <data name="users.profile.addLoginDone" xml:space="preserve">
<value>登录添加成功。</value> <value>登录添加成功。</value>
</data> </data>

7
backend/src/Squidex.Web/ApiExceptionFilterAttribute.cs

@ -8,7 +8,7 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Squidex.Log; using Microsoft.Extensions.Logging;
namespace Squidex.Web namespace Squidex.Web
{ {
@ -32,10 +32,9 @@ namespace Squidex.Web
if (unhandled != null) if (unhandled != null)
{ {
var log = context.HttpContext.RequestServices.GetRequiredService<ISemanticLog>(); var log = context.HttpContext.RequestServices.GetRequiredService<ILogger<ApiExceptionFilterAttribute>>();
log.LogError(unhandled, w => w log.LogError(unhandled, "An unexpected exception has occurred.");
.WriteProperty("message", "An unexpected exception has occurred."));
} }
context.Result = GetResult(error); context.Result = GetResult(error);

18
backend/src/Squidex.Web/Pipeline/AppResolver.cs

@ -11,10 +11,10 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities;
using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Infrastructure.Security; using Squidex.Infrastructure.Security;
using Squidex.Log;
using Squidex.Shared; using Squidex.Shared;
using Squidex.Shared.Identity; using Squidex.Shared.Identity;
@ -43,12 +43,9 @@ namespace Squidex.Web.Pipeline
if (app == null) if (app == null)
{ {
var log = context.HttpContext.RequestServices?.GetService<ISemanticLog>(); var log = context.HttpContext.RequestServices?.GetService<ILogger<AppResolver>>();
log?.LogWarning(w => w log?.LogWarning("Cannot find app with the given name {name}.", appName);
.WriteProperty("message", "Cannot find app with the given name.")
.WriteProperty("appId", "404")
.WriteProperty("appName", appName));
context.Result = new NotFoundResult(); context.Result = new NotFoundResult();
return; return;
@ -98,12 +95,11 @@ namespace Squidex.Web.Pipeline
} }
else else
{ {
var log = context.HttpContext.RequestServices?.GetService<ISemanticLog>(); var log = context.HttpContext.RequestServices?.GetService<ILogger<AppResolver>>();
log?.LogWarning(w => w log?.LogWarning("Authenticated user has no permission to access the app {name} with ID {id}.",
.WriteProperty("message", "Authenticated user has no permission to access the app.") app.Id,
.WriteProperty("appId", app.Id.ToString()) app.Name);
.WriteProperty("appName", appName));
context.Result = new NotFoundResult(); context.Result = new NotFoundResult();
} }

9
backend/src/Squidex.Web/Pipeline/RequestExceptionMiddleware.cs

@ -1,4 +1,4 @@
// ========================================================================== // ==========================================================================
// Squidex Headless CMS // Squidex Headless CMS
// ========================================================================== // ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt) // Copyright (c) Squidex UG (haftungsbeschraenkt)
@ -11,7 +11,7 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Squidex.Log; using Microsoft.Extensions.Logging;
namespace Squidex.Web.Pipeline namespace Squidex.Web.Pipeline
{ {
@ -26,7 +26,8 @@ namespace Squidex.Web.Pipeline
this.next = next; this.next = next;
} }
public async Task InvokeAsync(HttpContext context, IActionResultExecutor<ObjectResult> writer, ISemanticLog log) public async Task InvokeAsync(HttpContext context, IActionResultExecutor<ObjectResult> writer,
ILogger<RequestExceptionMiddleware> log)
{ {
if (TryGetErrorCode(context, out var statusCode) && IsErrorStatusCode(statusCode)) if (TryGetErrorCode(context, out var statusCode) && IsErrorStatusCode(statusCode))
{ {
@ -42,7 +43,7 @@ namespace Squidex.Web.Pipeline
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, w => w.WriteProperty("message", "An unexpected exception has occurred.")); log.LogError(ex, "An unexpected exception has occurred.");
if (!context.Response.HasStarted) if (!context.Response.HasStarted)
{ {

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

@ -41,8 +41,9 @@ namespace Squidex.Web.Pipeline
log.LogInformation((elapsedMs, context), (ctx, w) => log.LogInformation((elapsedMs, context), (ctx, w) =>
{ {
w.WriteObject("filters", ctx.context, LogFilters); w.WriteProperty("message", "HTTP request executed.");
w.WriteProperty("elapsedRequestMs", ctx.elapsedMs); w.WriteProperty("elapsedRequestMs", ctx.elapsedMs);
w.WriteObject("filters", ctx.context, LogFilters);
}); });
} }
} }

9
backend/src/Squidex.Web/Pipeline/UsageMiddleware.cs

@ -34,7 +34,6 @@ namespace Squidex.Web.Pipeline
var usageBody = SetUsageBody(context); var usageBody = SetUsageBody(context);
var watch = ValueStopwatch.StartNew(); var watch = ValueStopwatch.StartNew();
try try
{ {
await next(context); await next(context);
@ -70,8 +69,8 @@ namespace Squidex.Web.Pipeline
request.UserId = context.User.OpenIdSubject(); request.UserId = context.User.OpenIdSubject();
request.UserClientId = clientId; request.UserClientId = clientId;
#pragma warning disable MA0040 // Flow the cancellation token // Do not flow cancellation token because it is too important.
await usageLog.LogAsync(appId.Value, request); await usageLog.LogAsync(appId.Value, request, default);
if (request.Costs > 0) if (request.Costs > 0)
{ {
@ -81,9 +80,9 @@ namespace Squidex.Web.Pipeline
request.UserClientId, request.UserClientId,
request.Costs, request.Costs,
request.ElapsedMs, request.ElapsedMs,
request.Bytes); request.Bytes,
default);
} }
#pragma warning restore MA0040 // Flow the cancellation token
} }
} }
} }

17
backend/src/Squidex/Areas/Api/Controllers/Users/UsersController.cs

@ -10,7 +10,6 @@ using Microsoft.Net.Http.Headers;
using Squidex.Areas.Api.Controllers.Users.Models; using Squidex.Areas.Api.Controllers.Users.Models;
using Squidex.Domain.Users; using Squidex.Domain.Users;
using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Commands;
using Squidex.Log;
using Squidex.Shared.Identity; using Squidex.Shared.Identity;
using Squidex.Shared.Users; using Squidex.Shared.Users;
using Squidex.Web; using Squidex.Web;
@ -27,7 +26,7 @@ namespace Squidex.Areas.Api.Controllers.Users
private readonly IHttpClientFactory httpClientFactory; private readonly IHttpClientFactory httpClientFactory;
private readonly IUserPictureStore userPictureStore; private readonly IUserPictureStore userPictureStore;
private readonly IUserResolver userResolver; private readonly IUserResolver userResolver;
private readonly ISemanticLog log; private readonly ILogger<UsersController> log;
static UsersController() static UsersController()
{ {
@ -46,7 +45,7 @@ namespace Squidex.Areas.Api.Controllers.Users
IHttpClientFactory httpClientFactory, IHttpClientFactory httpClientFactory,
IUserPictureStore userPictureStore, IUserPictureStore userPictureStore,
IUserResolver userResolver, IUserResolver userResolver,
ISemanticLog log) ILogger<UsersController> log)
: base(commandBus) : base(commandBus)
{ {
this.httpClientFactory = httpClientFactory; this.httpClientFactory = httpClientFactory;
@ -99,9 +98,7 @@ namespace Squidex.Areas.Api.Controllers.Users
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, w => w log.LogError(ex, "Failed to return users, returning empty results.");
.WriteProperty("action", nameof(GetUsers))
.WriteProperty("status", "Failed"));
} }
return Ok(Array.Empty<UserDto>()); return Ok(Array.Empty<UserDto>());
@ -134,9 +131,7 @@ namespace Squidex.Areas.Api.Controllers.Users
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, w => w log.LogError(ex, "Failed to return user, returning empty results.");
.WriteProperty("action", nameof(GetUser))
.WriteProperty("status", "Failed"));
} }
return NotFound(); return NotFound();
@ -209,9 +204,7 @@ namespace Squidex.Areas.Api.Controllers.Users
} }
catch (Exception ex) catch (Exception ex)
{ {
log.LogError(ex, w => w log.LogError(ex, "Failed to return user picture, returning fallback image.");
.WriteProperty("action", nameof(GetUser))
.WriteProperty("status", "Failed"));
} }
return new FileStreamResult(new MemoryStream(AvatarBytes), "image/png"); return new FileStreamResult(new MemoryStream(AvatarBytes), "image/png");

7
backend/src/Squidex/Areas/IdentityServer/Config/CreateAdminInitializer.cs

@ -12,7 +12,6 @@ using Squidex.Domain.Users;
using Squidex.Hosting; using Squidex.Hosting;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Security; using Squidex.Infrastructure.Security;
using Squidex.Log;
using Squidex.Shared; using Squidex.Shared;
using Squidex.Shared.Identity; using Squidex.Shared.Identity;
@ -85,11 +84,9 @@ namespace Squidex.Areas.IdentityServer.Config
} }
catch (Exception ex) catch (Exception ex)
{ {
var log = serviceProvider.GetRequiredService<ISemanticLog>(); var log = serviceProvider.GetRequiredService<ILogger<CreateAdminInitializer>>();
log.LogError(ex, w => w log.LogError(ex, "Failed to create administrator.");
.WriteProperty("action", "createAdmin")
.WriteProperty("status", "failed"));
} }
} }
} }

2
backend/src/Squidex/Areas/IdentityServer/Controllers/Account/AccountController.cs

@ -241,7 +241,7 @@ namespace Squidex.Areas.IdentityServer.Controllers.Account
if (string.IsNullOrWhiteSpace(email)) if (string.IsNullOrWhiteSpace(email))
{ {
throw new DomainException(T.Get("login.noEmailAddress")); throw new DomainException(T.Get("users.noEmailAddress"));
} }
var values = new UserValues var values = new UserValues

1
backend/src/Squidex/Config/Domain/InfrastructureServices.cs

@ -8,7 +8,6 @@
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using NodaTime; using NodaTime;
using Orleans;
using Squidex.Areas.Api.Controllers.Contents.Generator; using Squidex.Areas.Api.Controllers.Contents.Generator;
using Squidex.Areas.Api.Controllers.News; using Squidex.Areas.Api.Controllers.News;
using Squidex.Areas.Api.Controllers.News.Service; using Squidex.Areas.Api.Controllers.News.Service;

4
backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleServiceTests.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using NodaTime; using NodaTime;
using Squidex.Domain.Apps.Core.HandleRules; using Squidex.Domain.Apps.Core.HandleRules;
@ -18,7 +19,6 @@ using Squidex.Domain.Apps.Events.Contents;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
using Squidex.Log;
using Xunit; using Xunit;
namespace Squidex.Domain.Apps.Core.Operations.HandleRules namespace Squidex.Domain.Apps.Core.Operations.HandleRules
@ -80,7 +80,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules
A.CallTo(() => ruleTriggerHandler.TriggerType) A.CallTo(() => ruleTriggerHandler.TriggerType)
.Returns(typeof(ContentChangedTriggerV2)); .Returns(typeof(ContentChangedTriggerV2));
var log = A.Fake<ISemanticLog>(); var log = A.Fake<ILogger<RuleService>>();
sut = new RuleService(Options.Create(new RuleOptions()), sut = new RuleService(Options.Create(new RuleOptions()),
new[] { ruleTriggerHandler }, new[] { ruleTriggerHandler },

17
backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ValidationTestExtensions.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Core.TestHelpers;
@ -13,7 +14,6 @@ using Squidex.Domain.Apps.Core.ValidateContent;
using Squidex.Domain.Apps.Core.ValidateContent.Validators; using Squidex.Domain.Apps.Core.ValidateContent.Validators;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
using Squidex.Log;
#pragma warning disable MA0048 // File name must match type name #pragma warning disable MA0048 // File name must match type name
@ -140,7 +140,6 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
private sealed class ValidatorBuilder private sealed class ValidatorBuilder
{ {
private static readonly ISemanticLog Log = A.Fake<ISemanticLog>();
private static readonly IValidatorsFactory Default = new DefaultValidatorsFactory(); private static readonly IValidatorsFactory Default = new DefaultValidatorsFactory();
private readonly IValidatorsFactory? validatorFactory; private readonly IValidatorsFactory? validatorFactory;
private readonly ValidationContext validationContext; private readonly ValidationContext validationContext;
@ -153,17 +152,21 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
public ContentValidator ContentValidator(PartitionResolver partitionResolver) public ContentValidator ContentValidator(PartitionResolver partitionResolver)
{ {
return new ContentValidator(partitionResolver, validationContext, CreateFactories(), Log); var log = A.Fake<ILogger<ContentValidator>>();
return new ContentValidator(partitionResolver, validationContext, CreateFactories(), log);
} }
public IValidator ValueValidator(IField field) private IValidator CreateValueValidator(IField field)
{ {
return CreateValueValidator(field); var log = A.Fake<ILogger<ContentValidator>>();
return new FieldValidator(new AggregateValidator(CreateValueValidators(field), log), field);
} }
private IValidator CreateValueValidator(IField field) public IValidator ValueValidator(IField field)
{ {
return new FieldValidator(new AggregateValidator(CreateValueValidators(field), Log), field); return CreateValueValidator(field);
} }
private IEnumerable<IValidator> CreateValueValidators(IField field) private IEnumerable<IValidator> CreateValueValidators(IField field)

4
backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DefaultAppImageStoreTests.cs

@ -44,7 +44,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
await sut.UploadAsync(appId, stream); await sut.UploadAsync(appId, stream);
A.CallTo(() => assetStore.UploadAsync(fileName, stream, true, CancellationToken.None)) A.CallTo(() => assetStore.UploadAsync(fileName, stream, true, default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -61,7 +61,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
await sut.DownloadAsync(appId, stream); await sut.DownloadAsync(appId, stream);
A.CallTo(() => assetStore.DownloadAsync(fileName, stream, default, CancellationToken.None)) A.CallTo(() => assetStore.DownloadAsync(fileName, stream, default, default))
.MustHaveHappened(); .MustHaveHappened();
} }

10
backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppDomainObjectTests.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Core.Apps; using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Core.TestHelpers;
@ -15,7 +16,6 @@ using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Domain.Apps.Events.Apps; using Squidex.Domain.Apps.Events.Apps;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Json.Objects;
using Squidex.Log;
using Squidex.Shared.Users; using Squidex.Shared.Users;
using Xunit; using Xunit;
@ -67,7 +67,13 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
} }
}; };
sut = new AppDomainObject(PersistenceFactory, A.Dummy<ISemanticLog>(), initialSettings, appPlansProvider, appPlansBillingManager, userResolver); var log = A.Fake<ILogger<AppDomainObject>>();
sut = new AppDomainObject(PersistenceFactory, log,
initialSettings,
appPlansProvider,
appPlansBillingManager,
userResolver);
#pragma warning disable MA0056 // Do not call overridable members in constructor #pragma warning disable MA0056 // Do not call overridable members in constructor
sut.Setup(Id); sut.Setup(Id);
#pragma warning restore MA0056 // Do not call overridable members in constructor #pragma warning restore MA0056 // Do not call overridable members in constructor

6
backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InvitationEventConsumerTests.cs

@ -6,13 +6,13 @@
// ========================================================================== // ==========================================================================
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.Logging;
using NodaTime; using NodaTime;
using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Core.TestHelpers;
using Squidex.Domain.Apps.Entities.Notifications; using Squidex.Domain.Apps.Entities.Notifications;
using Squidex.Domain.Apps.Events.Apps; using Squidex.Domain.Apps.Events.Apps;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.EventSourcing;
using Squidex.Log;
using Squidex.Shared.Users; using Squidex.Shared.Users;
using Xunit; using Xunit;
@ -24,7 +24,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation
private readonly IUserResolver userResolver = A.Fake<IUserResolver>(); private readonly IUserResolver userResolver = A.Fake<IUserResolver>();
private readonly IUser assigner = UserMocks.User("1"); private readonly IUser assigner = UserMocks.User("1");
private readonly IUser assignee = UserMocks.User("2"); private readonly IUser assignee = UserMocks.User("2");
private readonly ISemanticLog log = A.Fake<ISemanticLog>(); private readonly ILogger<InvitationEventConsumer> log = A.Fake<ILogger<InvitationEventConsumer>>();
private readonly string assignerId = DomainId.NewGuid().ToString(); private readonly string assignerId = DomainId.NewGuid().ToString();
private readonly string assigneeId = DomainId.NewGuid().ToString(); private readonly string assigneeId = DomainId.NewGuid().ToString();
private readonly string appName = "my-app"; private readonly string appName = "my-app";
@ -155,7 +155,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation
private void MustLogWarning() private void MustLogWarning()
{ {
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!)) A.CallTo(log).Where(x => x.Method.Name == "Log" && x.GetArgument<LogLevel>(0) == LogLevel.Warning)
.MustHaveHappened(); .MustHaveHappened();
} }

4
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetDomainObjectTests.cs

@ -7,6 +7,7 @@
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Squidex.Assets; using Squidex.Assets;
using Squidex.Domain.Apps.Core.Assets; using Squidex.Domain.Apps.Core.Assets;
using Squidex.Domain.Apps.Core.Scripting; using Squidex.Domain.Apps.Core.Scripting;
@ -18,7 +19,6 @@ using Squidex.Domain.Apps.Entities.Contents.Repositories;
using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Domain.Apps.Events.Assets; using Squidex.Domain.Apps.Events.Assets;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Log;
using Xunit; using Xunit;
namespace Squidex.Domain.Apps.Entities.Assets.DomainObject namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
@ -66,7 +66,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
A.CallTo(() => tagService.NormalizeTagsAsync(AppId, TagGroups.Assets, A<HashSet<string>>._, A<HashSet<string>>._)) A.CallTo(() => tagService.NormalizeTagsAsync(AppId, TagGroups.Assets, A<HashSet<string>>._, A<HashSet<string>>._))
.ReturnsLazily(x => Task.FromResult(x.GetArgument<HashSet<string>>(2)?.ToDictionary(x => x) ?? new Dictionary<string, string>())); .ReturnsLazily(x => Task.FromResult(x.GetArgument<HashSet<string>>(2)?.ToDictionary(x => x) ?? new Dictionary<string, string>()));
var log = A.Fake<ISemanticLog>(); var log = A.Fake<ILogger<AssetDomainObject>>();
var serviceProvider = var serviceProvider =
new ServiceCollection() new ServiceCollection()

4
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetFolderDomainObjectTests.cs

@ -7,13 +7,13 @@
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Domain.Apps.Entities.Contents.Repositories; using Squidex.Domain.Apps.Entities.Contents.Repositories;
using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Domain.Apps.Events.Assets; using Squidex.Domain.Apps.Events.Assets;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Log;
using Xunit; using Xunit;
namespace Squidex.Domain.Apps.Entities.Assets.DomainObject namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
@ -43,7 +43,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
A.CallTo(() => assetQuery.FindAssetFolderAsync(AppId, parentId, A<CancellationToken>._)) A.CallTo(() => assetQuery.FindAssetFolderAsync(AppId, parentId, A<CancellationToken>._))
.Returns(new List<IAssetFolderEntity> { A.Fake<IAssetFolderEntity>() }); .Returns(new List<IAssetFolderEntity> { A.Fake<IAssetFolderEntity>() });
var log = A.Fake<ISemanticLog>(); var log = A.Fake<ILogger<AssetFolderDomainObject>>();
var serviceProvider = var serviceProvider =
new ServiceCollection() new ServiceCollection()

6
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetsBulkUpdateCommandMiddlewareTests.cs

@ -7,11 +7,11 @@
using System.Security.Claims; using System.Security.Claims;
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Commands;
using Squidex.Log;
using Squidex.Shared; using Squidex.Shared;
using Squidex.Shared.Identity; using Squidex.Shared.Identity;
using Xunit; using Xunit;
@ -27,7 +27,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
public AssetsBulkUpdateCommandMiddlewareTests() public AssetsBulkUpdateCommandMiddlewareTests()
{ {
sut = new AssetsBulkUpdateCommandMiddleware(contextProvider, A.Fake<ISemanticLog>()); var log = A.Fake<ILogger<AssetsBulkUpdateCommandMiddleware>>();
sut = new AssetsBulkUpdateCommandMiddleware(contextProvider, log);
} }
[Fact] [Fact]

6
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/RecursiveDeleterTests.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Domain.Apps.Entities.Assets.Repositories; using Squidex.Domain.Apps.Entities.Assets.Repositories;
using Squidex.Domain.Apps.Events.Assets; using Squidex.Domain.Apps.Events.Assets;
@ -13,14 +14,13 @@ using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
using Squidex.Log;
using Xunit; using Xunit;
namespace Squidex.Domain.Apps.Entities.Assets namespace Squidex.Domain.Apps.Entities.Assets
{ {
public class RecursiveDeleterTests public class RecursiveDeleterTests
{ {
private readonly ISemanticLog log = A.Fake<ISemanticLog>(); private readonly ILogger<RecursiveDeleter> log = A.Fake<ILogger<RecursiveDeleter>>();
private readonly IAssetRepository assetRepository = A.Fake<IAssetRepository>(); private readonly IAssetRepository assetRepository = A.Fake<IAssetRepository>();
private readonly IAssetFolderRepository assetFolderRepository = A.Fake<IAssetFolderRepository>(); private readonly IAssetFolderRepository assetFolderRepository = A.Fake<IAssetFolderRepository>();
private readonly ICommandBus commandBus = A.Fake<ICommandBus>(); private readonly ICommandBus commandBus = A.Fake<ICommandBus>();
@ -128,7 +128,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
A.CallTo(() => commandBus.PublishAsync(A<DeleteAsset>.That.Matches(x => x.AssetId == childId2))) A.CallTo(() => commandBus.PublishAsync(A<DeleteAsset>.That.Matches(x => x.AssetId == childId2)))
.MustHaveHappened(); .MustHaveHappened();
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!)) A.CallTo(log).Where(x => x.Method.Name == "Log")
.MustHaveHappened(); .MustHaveHappened();
} }
} }

6
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentSchedulerGrainTests.cs

@ -6,13 +6,13 @@
// ========================================================================== // ==========================================================================
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.Logging;
using NodaTime; using NodaTime;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Domain.Apps.Entities.Contents.Commands;
using Squidex.Domain.Apps.Entities.Contents.Repositories; using Squidex.Domain.Apps.Entities.Contents.Repositories;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Commands;
using Squidex.Log;
using Xunit; using Xunit;
namespace Squidex.Domain.Apps.Entities.Contents namespace Squidex.Domain.Apps.Entities.Contents
@ -27,7 +27,9 @@ namespace Squidex.Domain.Apps.Entities.Contents
public ContentSchedulerGrainTests() public ContentSchedulerGrainTests()
{ {
sut = new ContentSchedulerGrain(contentRepository, commandBus, clock, A.Fake<ISemanticLog>()); var log = A.Fake<ILogger<ContentSchedulerGrain>>();
sut = new ContentSchedulerGrain(contentRepository, commandBus, clock, log);
} }
[Fact] [Fact]

5
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentDomainObjectTests.cs

@ -7,6 +7,7 @@
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NodaTime; using NodaTime;
using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
@ -22,7 +23,6 @@ using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Domain.Apps.Events.Contents; using Squidex.Domain.Apps.Events.Contents;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
using Squidex.Log;
using Xunit; using Xunit;
namespace Squidex.Domain.Apps.Entities.Contents.DomainObject namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
@ -104,11 +104,12 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
patched = patch.MergeInto(data); patched = patch.MergeInto(data);
var log = A.Fake<ISemanticLog>(); var log = A.Fake<ILogger<ContentDomainObject>>();
var serviceProvider = var serviceProvider =
new ServiceCollection() new ServiceCollection()
.AddSingleton(appProvider) .AddSingleton(appProvider)
.AddSingleton(A.Fake<ILogger<ContentValidator>>())
.AddSingleton(log) .AddSingleton(log)
.AddSingleton(contentWorkflow) .AddSingleton(contentWorkflow)
.AddSingleton(contentRepository) .AddSingleton(contentRepository)

6
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentsBulkUpdateCommandMiddlewareTests.cs

@ -7,6 +7,7 @@
using System.Security.Claims; using System.Security.Claims;
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.Logging;
using NodaTime; using NodaTime;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Domain.Apps.Entities.Contents.Commands;
@ -15,7 +16,6 @@ using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Json.Objects;
using Squidex.Infrastructure.Queries; using Squidex.Infrastructure.Queries;
using Squidex.Log;
using Squidex.Shared; using Squidex.Shared;
using Squidex.Shared.Identity; using Squidex.Shared.Identity;
using Xunit; using Xunit;
@ -34,7 +34,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
public ContentsBulkUpdateCommandMiddlewareTests() public ContentsBulkUpdateCommandMiddlewareTests()
{ {
sut = new ContentsBulkUpdateCommandMiddleware(contentQuery, contextProvider, A.Fake<ISemanticLog>()); var log = A.Fake<ILogger<ContentsBulkUpdateCommandMiddleware>>();
sut = new ContentsBulkUpdateCommandMiddleware(contentQuery, contextProvider, log);
} }
[Fact] [Fact]

5
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs

@ -12,6 +12,7 @@ using GraphQL.Execution;
using GraphQL.NewtonsoftJson; using GraphQL.NewtonsoftJson;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Newtonsoft.Json; using Newtonsoft.Json;
using Squidex.Caching; using Squidex.Caching;
@ -23,10 +24,8 @@ using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives;
using Squidex.Domain.Apps.Entities.Contents.TestData; using Squidex.Domain.Apps.Entities.Contents.TestData;
using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.Json; using Squidex.Infrastructure.Json;
using Squidex.Log;
using Squidex.Shared; using Squidex.Shared;
using Squidex.Shared.Users; using Squidex.Shared.Users;
using Xunit; using Xunit;
@ -116,7 +115,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
DataLoaderDocumentListener>() DataLoaderDocumentListener>()
.AddSingleton<IDataLoaderContextAccessor, .AddSingleton<IDataLoaderContextAccessor,
DataLoaderContextAccessor>() DataLoaderContextAccessor>()
.AddSingleton(A.Fake<ISemanticLog>()) .AddSingleton(A.Fake<ILoggerFactory>())
.AddSingleton(appProvider) .AddSingleton(appProvider)
.AddSingleton(assetQuery) .AddSingleton(assetQuery)
.AddSingleton(commandBus) .AddSingleton(commandBus)

1
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/MongoTextIndexTests.cs

@ -5,7 +5,6 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using MongoDB.Driver;
using Xunit; using Xunit;
#pragma warning disable SA1300 // Element should begin with upper-case letter #pragma warning disable SA1300 // Element should begin with upper-case letter

6
backend/tests/Squidex.Domain.Apps.Entities.Tests/Notifications/NotificationEmailSenderTests.cs

@ -6,11 +6,11 @@
// ========================================================================== // ==========================================================================
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Core.TestHelpers;
using Squidex.Infrastructure.Email; using Squidex.Infrastructure.Email;
using Squidex.Log;
using Squidex.Shared.Users; using Squidex.Shared.Users;
using Xunit; using Xunit;
@ -22,7 +22,7 @@ namespace Squidex.Domain.Apps.Entities.Notifications
private readonly IUrlGenerator urlGenerator = A.Fake<IUrlGenerator>(); private readonly IUrlGenerator urlGenerator = A.Fake<IUrlGenerator>();
private readonly IUser assigner = UserMocks.User("1", "1@email.com", "user1"); private readonly IUser assigner = UserMocks.User("1", "1@email.com", "user1");
private readonly IUser assigned = UserMocks.User("2", "2@email.com", "user2"); private readonly IUser assigned = UserMocks.User("2", "2@email.com", "user2");
private readonly ISemanticLog log = A.Fake<ISemanticLog>(); private readonly ILogger<NotificationEmailSender> log = A.Fake<ILogger<NotificationEmailSender>>();
private readonly string appName = "my-app"; private readonly string appName = "my-app";
private readonly string appUI = "my-ui"; private readonly string appUI = "my-ui";
private readonly NotificationEmailTextOptions texts = new NotificationEmailTextOptions(); private readonly NotificationEmailTextOptions texts = new NotificationEmailTextOptions();
@ -169,7 +169,7 @@ namespace Squidex.Domain.Apps.Entities.Notifications
private void MustLogWarning() private void MustLogWarning()
{ {
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!)) A.CallTo(log).Where(x => x.Method.Name == "Log" && x.GetArgument<LogLevel>(0) == LogLevel.Warning)
.MustHaveHappened(); .MustHaveHappened();
} }
} }

6
backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/RuleDomainObjectTests.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Core.Rules; using Squidex.Domain.Apps.Core.Rules;
using Squidex.Domain.Apps.Core.Rules.Triggers; using Squidex.Domain.Apps.Core.Rules.Triggers;
using Squidex.Domain.Apps.Entities.Rules.Commands; using Squidex.Domain.Apps.Entities.Rules.Commands;
@ -13,7 +14,6 @@ using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Domain.Apps.Events.Rules; using Squidex.Domain.Apps.Events.Rules;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.EventSourcing;
using Squidex.Log;
using Xunit; using Xunit;
namespace Squidex.Domain.Apps.Entities.Rules.DomainObject namespace Squidex.Domain.Apps.Entities.Rules.DomainObject
@ -37,7 +37,9 @@ namespace Squidex.Domain.Apps.Entities.Rules.DomainObject
public RuleDomainObjectTests() public RuleDomainObjectTests()
{ {
sut = new RuleDomainObject(PersistenceFactory, A.Dummy<ISemanticLog>(), appProvider, ruleEnqueuer); var log = A.Fake<ILogger<RuleDomainObject>>();
sut = new RuleDomainObject(PersistenceFactory, log, appProvider, ruleEnqueuer);
#pragma warning disable MA0056 // Do not call overridable members in constructor #pragma warning disable MA0056 // Do not call overridable members in constructor
sut.Setup(Id); sut.Setup(Id);
#pragma warning restore MA0056 // Do not call overridable members in constructor #pragma warning restore MA0056 // Do not call overridable members in constructor

12
backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleDequeuerGrainTests.cs

@ -6,12 +6,12 @@
// ========================================================================== // ==========================================================================
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.Logging;
using NodaTime; using NodaTime;
using Squidex.Domain.Apps.Core.HandleRules; using Squidex.Domain.Apps.Core.HandleRules;
using Squidex.Domain.Apps.Core.Rules; using Squidex.Domain.Apps.Core.Rules;
using Squidex.Domain.Apps.Entities.Rules.Repositories; using Squidex.Domain.Apps.Entities.Rules.Repositories;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Log;
using Xunit; using Xunit;
namespace Squidex.Domain.Apps.Entities.Rules namespace Squidex.Domain.Apps.Entities.Rules
@ -19,7 +19,7 @@ namespace Squidex.Domain.Apps.Entities.Rules
public class RuleDequeuerGrainTests public class RuleDequeuerGrainTests
{ {
private readonly IClock clock = A.Fake<IClock>(); private readonly IClock clock = A.Fake<IClock>();
private readonly ISemanticLog log = A.Dummy<ISemanticLog>(); private readonly ILogger<RuleDequeuerGrain> log = A.Dummy<ILogger<RuleDequeuerGrain>>();
private readonly IRuleEventRepository ruleEventRepository = A.Fake<IRuleEventRepository>(); private readonly IRuleEventRepository ruleEventRepository = A.Fake<IRuleEventRepository>();
private readonly IRuleService ruleService = A.Fake<IRuleService>(); private readonly IRuleService ruleService = A.Fake<IRuleService>();
private readonly RuleDequeuerGrain sut; private readonly RuleDequeuerGrain sut;
@ -49,7 +49,7 @@ namespace Squidex.Domain.Apps.Entities.Rules
await sut.QueryAsync(); await sut.QueryAsync();
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!)) A.CallTo(log).Where(x => x.Method.Name == "Log")
.MustHaveHappened(); .MustHaveHappened();
} }
@ -63,7 +63,7 @@ namespace Squidex.Domain.Apps.Entities.Rules
await sut.HandleAsync(@event); await sut.HandleAsync(@event);
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!)) A.CallTo(log).Where(x => x.Method.Name == "Log")
.MustHaveHappened(); .MustHaveHappened();
} }
@ -124,12 +124,12 @@ namespace Squidex.Domain.Apps.Entities.Rules
if (result == RuleResult.Failed) if (result == RuleResult.Failed)
{ {
A.CallTo(() => log.Log(SemanticLogLevel.Warning, A<Exception?>._, A<LogFormatter>._)) A.CallTo(log).Where(x => x.Method.Name == "Log" && x.GetArgument<LogLevel>(0) == LogLevel.Warning)
.MustHaveHappened(); .MustHaveHappened();
} }
else else
{ {
A.CallTo(() => log.Log(SemanticLogLevel.Warning, A<Exception?>._, A<LogFormatter>._)) A.CallTo(log).Where(x => x.Method.Name == "Log" && x.GetArgument<LogLevel>(0) == LogLevel.Warning)
.MustNotHaveHappened(); .MustNotHaveHappened();
} }

6
backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/DomainObject/SchemaDomainObjectTests.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Entities.Schemas.Commands; using Squidex.Domain.Apps.Entities.Schemas.Commands;
@ -14,7 +15,6 @@ using Squidex.Domain.Apps.Events.Schemas;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Collections; using Squidex.Infrastructure.Collections;
using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Commands;
using Squidex.Log;
using Xunit; using Xunit;
namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject
@ -35,7 +35,9 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject
public SchemaDomainObjectTests() public SchemaDomainObjectTests()
{ {
sut = new SchemaDomainObject(PersistenceFactory, A.Dummy<ISemanticLog>()); var log = A.Fake<ILogger<SchemaDomainObject>>();
sut = new SchemaDomainObject(PersistenceFactory, log);
#pragma warning disable MA0056 // Do not call overridable members in constructor #pragma warning disable MA0056 // Do not call overridable members in constructor
sut.Setup(Id); sut.Setup(Id);
#pragma warning restore MA0056 // Do not call overridable members in constructor #pragma warning restore MA0056 // Do not call overridable members in constructor

6
backend/tests/Squidex.Domain.Apps.Entities.Tests/Search/SearchManagerTests.cs

@ -7,9 +7,9 @@
using FakeItEasy; using FakeItEasy;
using FluentAssertions; using FluentAssertions;
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Log;
using Xunit; using Xunit;
namespace Squidex.Domain.Apps.Entities.Search namespace Squidex.Domain.Apps.Entities.Search
@ -18,7 +18,7 @@ namespace Squidex.Domain.Apps.Entities.Search
{ {
private readonly ISearchSource source1 = A.Fake<ISearchSource>(); private readonly ISearchSource source1 = A.Fake<ISearchSource>();
private readonly ISearchSource source2 = A.Fake<ISearchSource>(); private readonly ISearchSource source2 = A.Fake<ISearchSource>();
private readonly ISemanticLog log = A.Fake<ISemanticLog>(); private readonly ILogger<SearchManager> log = A.Fake<ILogger<SearchManager>>();
private readonly Context requestContext = Context.Anonymous(Mocks.App(NamedId.Of(DomainId.NewGuid(), "my-app"))); private readonly Context requestContext = Context.Anonymous(Mocks.App(NamedId.Of(DomainId.NewGuid(), "my-app")));
private readonly SearchManager sut; private readonly SearchManager sut;
@ -94,7 +94,7 @@ namespace Squidex.Domain.Apps.Entities.Search
result.Should().BeEquivalentTo(result2); result.Should().BeEquivalentTo(result2);
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<string>._, A<Exception?>._, A<LogFormatter<string>>._!)) A.CallTo(log).Where(x => x.Method.Name == "Log")
.MustHaveHappened(); .MustHaveHappened();
} }
} }

4
backend/tests/Squidex.Domain.Users.Tests/DefaultUserPictureStoreTests.cs

@ -32,7 +32,7 @@ namespace Squidex.Domain.Users
await sut.UploadAsync(userId, stream); await sut.UploadAsync(userId, stream);
A.CallTo(() => assetStore.UploadAsync(file, stream, true, CancellationToken.None)) A.CallTo(() => assetStore.UploadAsync(file, stream, true, default))
.MustHaveHappened(); .MustHaveHappened();
} }
@ -43,7 +43,7 @@ namespace Squidex.Domain.Users
await sut.DownloadAsync(userId, stream); await sut.DownloadAsync(userId, stream);
A.CallTo(() => assetStore.DownloadAsync(file, stream, default, CancellationToken.None)) A.CallTo(() => assetStore.DownloadAsync(file, stream, default, default))
.MustHaveHappened(); .MustHaveHappened();
} }
} }

6
backend/tests/Squidex.Domain.Users.Tests/DefaultUserServiceTests.cs

@ -9,8 +9,8 @@ using System.Globalization;
using System.Security.Claims; using System.Security.Claims;
using FakeItEasy; using FakeItEasy;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Log;
using Squidex.Shared; using Squidex.Shared;
using Squidex.Shared.Identity; using Squidex.Shared.Identity;
using Squidex.Shared.Users; using Squidex.Shared.Users;
@ -33,7 +33,9 @@ namespace Squidex.Domain.Users
A.CallTo(userManager).WithReturnType<Task<IdentityResult>>() A.CallTo(userManager).WithReturnType<Task<IdentityResult>>()
.Returns(IdentityResult.Success); .Returns(IdentityResult.Success);
sut = new DefaultUserService(userManager, userFactory, Enumerable.Repeat(userEvents, 1), A.Fake<ISemanticLog>()); var log = A.Fake<ILogger<DefaultUserService>>();
sut = new DefaultUserService(userManager, userFactory, Enumerable.Repeat(userEvents, 1), log);
} }
[Fact] [Fact]

70
backend/tests/Squidex.Infrastructure.Tests/Commands/LogCommandMiddlewareTests.cs

@ -6,45 +6,23 @@
// ========================================================================== // ==========================================================================
using FakeItEasy; using FakeItEasy;
using Squidex.Log; using Microsoft.Extensions.Logging;
using Xunit; using Xunit;
namespace Squidex.Infrastructure.Commands namespace Squidex.Infrastructure.Commands
{ {
public class LogCommandMiddlewareTests public class LogCommandMiddlewareTests
{ {
private readonly MyLog log = new MyLog(); private readonly ILogger<LogCommandMiddleware> log = A.Fake<ILogger<LogCommandMiddleware>>();
private readonly LogCommandMiddleware sut; private readonly LogCommandMiddleware sut;
private readonly ICommand command = A.Dummy<ICommand>(); private readonly ICommand command = A.Dummy<ICommand>();
private readonly ICommandBus commandBus = A.Dummy<ICommandBus>(); private readonly ICommandBus commandBus = A.Dummy<ICommandBus>();
private sealed class MyLog : ISemanticLog
{
public Dictionary<SemanticLogLevel, int> LogLevels { get; } = new Dictionary<SemanticLogLevel, int>();
public void Log<T>(SemanticLogLevel logLevel, T context, Exception? exception, LogFormatter<T> action)
{
LogLevels[logLevel] = LogLevels.GetOrDefault(logLevel) + 1;
}
public void Log(SemanticLogLevel logLevel, Exception? exception, LogFormatter action)
{
LogLevels[logLevel] = LogLevels.GetOrDefault(logLevel) + 1;
}
public ISemanticLog CreateScope(Action<IObjectWriter> objectWriter)
{
throw new NotSupportedException();
}
public ISemanticLog CreateScope(ILogAppender appender)
{
throw new NotSupportedException();
}
}
public LogCommandMiddlewareTests() public LogCommandMiddlewareTests()
{ {
A.CallTo(() => log.IsEnabled(A<LogLevel>._))
.Returns(true);
sut = new LogCommandMiddleware(log); sut = new LogCommandMiddleware(log);
} }
@ -60,11 +38,11 @@ namespace Squidex.Infrastructure.Commands
return Task.CompletedTask; return Task.CompletedTask;
}); });
Assert.Equal(log.LogLevels, new Dictionary<SemanticLogLevel, int> A.CallTo(log).Where(x => x.Method.Name == "Log" && x.GetArgument<LogLevel>(0) == LogLevel.Debug)
{ .MustHaveHappened();
[SemanticLogLevel.Debug] = 1,
[SemanticLogLevel.Information] = 2 A.CallTo(log).Where(x => x.Method.Name == "Log" && x.GetArgument<LogLevel>(0) == LogLevel.Information)
}); .MustHaveHappenedTwiceExactly();
} }
[Fact] [Fact]
@ -77,12 +55,14 @@ namespace Squidex.Infrastructure.Commands
await sut.HandleAsync(context, c => throw new InvalidOperationException()); await sut.HandleAsync(context, c => throw new InvalidOperationException());
}); });
Assert.Equal(log.LogLevels, new Dictionary<SemanticLogLevel, int> A.CallTo(log).Where(x => x.Method.Name == "Log" && x.GetArgument<LogLevel>(0) == LogLevel.Debug)
{ .MustHaveHappened();
[SemanticLogLevel.Debug] = 1,
[SemanticLogLevel.Information] = 1, A.CallTo(log).Where(x => x.Method.Name == "Log" && x.GetArgument<LogLevel>(0) == LogLevel.Information)
[SemanticLogLevel.Error] = 1 .MustHaveHappened();
});
A.CallTo(log).Where(x => x.Method.Name == "Log" && x.GetArgument<LogLevel>(0) == LogLevel.Error)
.MustHaveHappened();
} }
[Fact] [Fact]
@ -92,12 +72,14 @@ namespace Squidex.Infrastructure.Commands
await sut.HandleAsync(context, c => Task.CompletedTask); await sut.HandleAsync(context, c => Task.CompletedTask);
Assert.Equal(log.LogLevels, new Dictionary<SemanticLogLevel, int> A.CallTo(log).Where(x => x.Method.Name == "Log" && x.GetArgument<LogLevel>(0) == LogLevel.Debug)
{ .MustHaveHappened();
[SemanticLogLevel.Debug] = 1,
[SemanticLogLevel.Information] = 2, A.CallTo(log).Where(x => x.Method.Name == "Log" && x.GetArgument<LogLevel>(0) == LogLevel.Information)
[SemanticLogLevel.Fatal] = 1 .MustHaveHappenedTwiceExactly();
});
A.CallTo(log).Where(x => x.Method.Name == "Log" && x.GetArgument<LogLevel>(0) == LogLevel.Critical)
.MustHaveHappened();
} }
} }
} }

7
backend/tests/Squidex.Infrastructure.Tests/EventSourcing/Grains/EventConsumerGrainTests.cs

@ -7,10 +7,10 @@
using FakeItEasy; using FakeItEasy;
using FluentAssertions; using FluentAssertions;
using Microsoft.Extensions.Logging;
using Orleans.Storage; using Orleans.Storage;
using Squidex.Infrastructure.Orleans; using Squidex.Infrastructure.Orleans;
using Squidex.Infrastructure.TestHelpers; using Squidex.Infrastructure.TestHelpers;
using Squidex.Log;
using Xunit; using Xunit;
namespace Squidex.Infrastructure.EventSourcing.Grains namespace Squidex.Infrastructure.EventSourcing.Grains
@ -26,7 +26,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
IGrainState<EventConsumerState> state, IGrainState<EventConsumerState> state,
IEventStore eventStore, IEventStore eventStore,
IEventDataFormatter eventDataFormatter, IEventDataFormatter eventDataFormatter,
ISemanticLog log) ILogger<EventConsumerGrain> log)
: base(eventConsumerFactory, state, eventStore, eventDataFormatter, log) : base(eventConsumerFactory, state, eventStore, eventDataFormatter, log)
{ {
} }
@ -59,7 +59,6 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
private readonly IEventDataFormatter formatter = A.Fake<IEventDataFormatter>(); private readonly IEventDataFormatter formatter = A.Fake<IEventDataFormatter>();
private readonly IEventStore eventStore = A.Fake<IEventStore>(); private readonly IEventStore eventStore = A.Fake<IEventStore>();
private readonly IEventSubscription eventSubscription = A.Fake<IEventSubscription>(); private readonly IEventSubscription eventSubscription = A.Fake<IEventSubscription>();
private readonly ISemanticLog log = A.Fake<ISemanticLog>();
private readonly StoredEvent storedEvent; private readonly StoredEvent storedEvent;
private readonly EventData eventData = new EventData("Type", new EnvelopeHeaders(), "Payload"); private readonly EventData eventData = new EventData("Type", new EnvelopeHeaders(), "Payload");
private readonly Envelope<IEvent> envelope = new Envelope<IEvent>(new MyEvent()); private readonly Envelope<IEvent> envelope = new Envelope<IEvent>(new MyEvent());
@ -102,6 +101,8 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
A.CallTo(() => formatter.ParseIfKnown(storedEvent)) A.CallTo(() => formatter.ParseIfKnown(storedEvent))
.Returns(envelope); .Returns(envelope);
var log = A.Fake<ILogger<EventConsumerGrain>>();
sut = new MyEventConsumerGrain( sut = new MyEventConsumerGrain(
x => eventConsumer, x => eventConsumer,
grainState, grainState,

6
backend/tests/Squidex.Infrastructure.Tests/EventSourcing/MongoParallelInsertTests.cs

@ -6,13 +6,13 @@
// ========================================================================== // ==========================================================================
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.Logging;
using Orleans.Internal; using Orleans.Internal;
using Squidex.Infrastructure.EventSourcing.Grains; using Squidex.Infrastructure.EventSourcing.Grains;
using Squidex.Infrastructure.Orleans; using Squidex.Infrastructure.Orleans;
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Tasks; using Squidex.Infrastructure.Tasks;
using Squidex.Infrastructure.TestHelpers; using Squidex.Infrastructure.TestHelpers;
using Squidex.Log;
using Xunit; using Xunit;
#pragma warning disable SA1300 // Element should begin with upper-case letter #pragma warning disable SA1300 // Element should begin with upper-case letter
@ -23,7 +23,7 @@ namespace Squidex.Infrastructure.EventSourcing
public sealed class MongoParallelInsertTests : IClassFixture<MongoEventStoreReplicaSetFixture> public sealed class MongoParallelInsertTests : IClassFixture<MongoEventStoreReplicaSetFixture>
{ {
private readonly IGrainState<EventConsumerState> grainState = A.Fake<IGrainState<EventConsumerState>>(); private readonly IGrainState<EventConsumerState> grainState = A.Fake<IGrainState<EventConsumerState>>();
private readonly ISemanticLog log = A.Fake<ISemanticLog>(); private readonly ILogger<EventConsumerGrain> log = A.Fake<ILogger<EventConsumerGrain>>();
private readonly IEventDataFormatter eventDataFormatter; private readonly IEventDataFormatter eventDataFormatter;
public MongoEventStoreFixture _ { get; } public MongoEventStoreFixture _ { get; }
@ -155,7 +155,7 @@ namespace Squidex.Infrastructure.EventSourcing
IGrainState<EventConsumerState> state, IGrainState<EventConsumerState> state,
IEventStore eventStore, IEventStore eventStore,
IEventDataFormatter eventDataFormatter, IEventDataFormatter eventDataFormatter,
ISemanticLog log) ILogger<EventConsumerGrain> log)
: base(eventConsumerFactory, state, eventStore, eventDataFormatter, log) : base(eventConsumerFactory, state, eventStore, eventDataFormatter, log)
{ {
} }

6
backend/tests/Squidex.Infrastructure.Tests/Log/BackgroundRequestLogStoreTests.cs

@ -7,8 +7,8 @@
using System.Globalization; using System.Globalization;
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Squidex.Log;
using Xunit; using Xunit;
namespace Squidex.Infrastructure.Log namespace Squidex.Infrastructure.Log
@ -27,7 +27,9 @@ namespace Squidex.Infrastructure.Log
options.StoreEnabled = true; options.StoreEnabled = true;
sut = new BackgroundRequestLogStore(Options.Create(options), requestLogRepository, A.Fake<ISemanticLog>()) var log = A.Fake<ILogger<BackgroundRequestLogStore>>();
sut = new BackgroundRequestLogStore(Options.Create(options), requestLogRepository, log)
{ {
ForceWrite = true ForceWrite = true
}; };

6
backend/tests/Squidex.Infrastructure.Tests/Migrations/MigratorTests.cs

@ -6,7 +6,7 @@
// ========================================================================== // ==========================================================================
using FakeItEasy; using FakeItEasy;
using Squidex.Log; using Microsoft.Extensions.Logging;
using Xunit; using Xunit;
namespace Squidex.Infrastructure.Migrations namespace Squidex.Infrastructure.Migrations
@ -17,7 +17,7 @@ namespace Squidex.Infrastructure.Migrations
private readonly CancellationToken ct; private readonly CancellationToken ct;
private readonly IMigrationStatus status = A.Fake<IMigrationStatus>(); private readonly IMigrationStatus status = A.Fake<IMigrationStatus>();
private readonly IMigrationPath path = A.Fake<IMigrationPath>(); private readonly IMigrationPath path = A.Fake<IMigrationPath>();
private readonly ISemanticLog log = A.Fake<ISemanticLog>(); private readonly ILogger<Migrator> log = A.Fake<ILogger<Migrator>>();
private readonly List<(int From, int To, IMigration Migration)> migrations = new List<(int From, int To, IMigration Migration)>(); private readonly List<(int From, int To, IMigration Migration)> migrations = new List<(int From, int To, IMigration Migration)>();
public sealed class InMemoryStatus : IMigrationStatus public sealed class InMemoryStatus : IMigrationStatus
@ -216,7 +216,7 @@ namespace Squidex.Infrastructure.Migrations
await Assert.ThrowsAsync<MigrationFailedException>(() => sut.MigrateAsync(ct)); await Assert.ThrowsAsync<MigrationFailedException>(() => sut.MigrateAsync(ct));
A.CallTo(() => log.Log(SemanticLogLevel.Fatal, ex, A<LogFormatter>._!)) A.CallTo(log).Where(x => x.Method.Name == "Log" && x.GetArgument<LogLevel>(0) == LogLevel.Critical && x.GetArgument<Exception>(3) == ex)
.MustHaveHappened(); .MustHaveHappened();
A.CallTo(() => migrator_1_2.UpdateAsync(ct)) A.CallTo(() => migrator_1_2.UpdateAsync(ct))

23
backend/tests/Squidex.Infrastructure.Tests/Orleans/LoggingFilterTests.cs

@ -6,22 +6,23 @@
// ========================================================================== // ==========================================================================
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.Logging;
using Orleans; using Orleans;
using Orleans.Runtime;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
using Squidex.Log;
using Xunit; using Xunit;
namespace Squidex.Infrastructure.Orleans namespace Squidex.Infrastructure.Orleans
{ {
public class LoggingFilterTests public class LoggingFilterTests
{ {
private readonly ISemanticLog log = A.Fake<ISemanticLog>(); private readonly ILoggerFactory logFactory = A.Fake<ILoggerFactory>();
private readonly IIncomingGrainCallContext context = A.Fake<IIncomingGrainCallContext>(); private readonly IIncomingGrainCallContext context = A.Fake<IIncomingGrainCallContext>();
private readonly LoggingFilter sut; private readonly LoggingFilter sut;
public LoggingFilterTests() public LoggingFilterTests()
{ {
sut = new LoggingFilter(log); sut = new LoggingFilter(logFactory);
} }
[Fact] [Fact]
@ -29,7 +30,7 @@ namespace Squidex.Infrastructure.Orleans
{ {
await sut.Invoke(context); await sut.Invoke(context);
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!)) A.CallTo(() => logFactory.CreateLogger(A<string>._))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -41,19 +42,29 @@ namespace Squidex.Infrastructure.Orleans
await Assert.ThrowsAsync<ValidationException>(() => sut.Invoke(context)); await Assert.ThrowsAsync<ValidationException>(() => sut.Invoke(context));
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!)) A.CallTo(() => logFactory.CreateLogger(A<string>._))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
[Fact] [Fact]
public async Task Should_log_exception_and_forward_it() public async Task Should_log_exception_and_forward_it()
{ {
var log = A.Fake<ILogger>();
var grain = A.Fake<IAddressable>();
A.CallTo(() => context.Invoke()) A.CallTo(() => context.Invoke())
.Throws(new InvalidOperationException()); .Throws(new InvalidOperationException());
A.CallTo(() => context.Grain)
.Returns(grain);
A.CallTo(() => logFactory.CreateLogger(A<string>._))
.Returns(log);
await Assert.ThrowsAsync<InvalidOperationException>(() => sut.Invoke(context)); await Assert.ThrowsAsync<InvalidOperationException>(() => sut.Invoke(context));
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!)) A.CallTo(log).Where(x => x.Method.Name == "Log")
.MustHaveHappened(); .MustHaveHappened();
} }
} }

4
backend/tests/Squidex.Infrastructure.Tests/TestHelpers/MyDomainObject.cs

@ -6,10 +6,10 @@
// ========================================================================== // ==========================================================================
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.Logging;
using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.States; using Squidex.Infrastructure.States;
using Squidex.Log;
#pragma warning disable MA0048 // File name must match type name #pragma warning disable MA0048 // File name must match type name
@ -28,7 +28,7 @@ namespace Squidex.Infrastructure.TestHelpers
} }
public MyDomainObject(IPersistenceFactory<MyDomainState> factory) public MyDomainObject(IPersistenceFactory<MyDomainState> factory)
: base(factory, A.Dummy<ISemanticLog>()) : base(factory, A.Dummy<ILogger>())
{ {
} }

5
backend/tests/Squidex.Infrastructure.Tests/UsageTracking/BackgroundUsageTrackerTests.cs

@ -7,7 +7,7 @@
using FakeItEasy; using FakeItEasy;
using FluentAssertions; using FluentAssertions;
using Squidex.Log; using Microsoft.Extensions.Logging;
using Xunit; using Xunit;
namespace Squidex.Infrastructure.UsageTracking namespace Squidex.Infrastructure.UsageTracking
@ -17,7 +17,6 @@ namespace Squidex.Infrastructure.UsageTracking
private readonly CancellationTokenSource cts = new CancellationTokenSource(); private readonly CancellationTokenSource cts = new CancellationTokenSource();
private readonly CancellationToken ct; private readonly CancellationToken ct;
private readonly IUsageRepository usageStore = A.Fake<IUsageRepository>(); private readonly IUsageRepository usageStore = A.Fake<IUsageRepository>();
private readonly ISemanticLog log = A.Fake<ISemanticLog>();
private readonly string key = Guid.NewGuid().ToString(); private readonly string key = Guid.NewGuid().ToString();
private readonly DateTime date = DateTime.Today; private readonly DateTime date = DateTime.Today;
private readonly BackgroundUsageTracker sut; private readonly BackgroundUsageTracker sut;
@ -26,6 +25,8 @@ namespace Squidex.Infrastructure.UsageTracking
{ {
ct = cts.Token; ct = cts.Token;
var log = A.Fake<ILogger<BackgroundUsageTracker>>();
sut = new BackgroundUsageTracker(usageStore, log) sut = new BackgroundUsageTracker(usageStore, log)
{ {
ForceWrite = true ForceWrite = true

30
backend/tests/Squidex.Web.Tests/ApiExceptionFilterAttributeTests.cs

@ -13,9 +13,9 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Logging;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
using Squidex.Log;
using Xunit; using Xunit;
#pragma warning disable MA0015 // Specify the parameter name in ArgumentException #pragma warning disable MA0015 // Specify the parameter name in ArgumentException
@ -24,7 +24,7 @@ namespace Squidex.Web
{ {
public class ApiExceptionFilterAttributeTests public class ApiExceptionFilterAttributeTests
{ {
private readonly ISemanticLog log = A.Fake<ISemanticLog>(); private readonly ILogger<ApiExceptionFilterAttribute> log = A.Fake<ILogger<ApiExceptionFilterAttribute>>();
private readonly ApiExceptionFilterAttribute sut = new ApiExceptionFilterAttribute(); private readonly ApiExceptionFilterAttribute sut = new ApiExceptionFilterAttribute();
[Fact] [Fact]
@ -59,7 +59,7 @@ namespace Squidex.Web
"property5[0].property6: Error5" "property5[0].property6: Error5"
}, ((ErrorDto)result.Value!).Details); }, ((ErrorDto)result.Value!).Details);
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!)) A.CallTo(log)
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -72,7 +72,7 @@ namespace Squidex.Web
Assert.IsType<NotFoundResult>(context.Result); Assert.IsType<NotFoundResult>(context.Result);
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!)) A.CallTo(log)
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -85,7 +85,7 @@ namespace Squidex.Web
Validate(500, context.Result, null); Validate(500, context.Result, null);
A.CallTo(() => log.Log(A<SemanticLogLevel>._, context.Exception, A<LogFormatter>._!)) A.CallTo(log).Where(x => x.Method.Name == "Log" && x.GetArgument<Exception>(3) == context.Exception)
.MustHaveHappened(); .MustHaveHappened();
} }
@ -98,7 +98,7 @@ namespace Squidex.Web
Validate(400, context.Result, context.Exception); Validate(400, context.Result, context.Exception);
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!)) A.CallTo(log)
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -111,7 +111,7 @@ namespace Squidex.Web
Validate(400, context.Result, context.Exception, "ERROR_CODE_XYZ"); Validate(400, context.Result, context.Exception, "ERROR_CODE_XYZ");
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!)) A.CallTo(log)
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -124,7 +124,7 @@ namespace Squidex.Web
Validate(400, context.Result, context.Exception); Validate(400, context.Result, context.Exception);
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!)) A.CallTo(log)
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -137,7 +137,7 @@ namespace Squidex.Web
Validate(409, context.Result, context.Exception, "OBJECT_CONFLICT"); Validate(409, context.Result, context.Exception, "OBJECT_CONFLICT");
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!)) A.CallTo(log)
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -150,7 +150,7 @@ namespace Squidex.Web
Validate(410, context.Result, context.Exception, "OBJECT_DELETED"); Validate(410, context.Result, context.Exception, "OBJECT_DELETED");
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!)) A.CallTo(log)
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -163,7 +163,7 @@ namespace Squidex.Web
Validate(412, context.Result, context.Exception, "OBJECT_VERSION_CONFLICT"); Validate(412, context.Result, context.Exception, "OBJECT_VERSION_CONFLICT");
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!)) A.CallTo(log)
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -176,7 +176,7 @@ namespace Squidex.Web
Validate(403, context.Result, context.Exception, "FORBIDDEN"); Validate(403, context.Result, context.Exception, "FORBIDDEN");
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!)) A.CallTo(log)
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -189,7 +189,7 @@ namespace Squidex.Web
Validate(403, context.Result, null); Validate(403, context.Result, null);
A.CallTo(() => log.Log(A<SemanticLogLevel>._, context.Exception, A<LogFormatter>._!)) A.CallTo(log).Where(x => x.Method.Name == "Log" && x.GetArgument<Exception>(3) == context.Exception)
.MustHaveHappened(); .MustHaveHappened();
} }
@ -202,7 +202,7 @@ namespace Squidex.Web
Validate(403, context.Result, null); Validate(403, context.Result, null);
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!)) A.CallTo(log)
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -238,7 +238,7 @@ namespace Squidex.Web
{ {
var services = A.Fake<IServiceProvider>(); var services = A.Fake<IServiceProvider>();
A.CallTo(() => services.GetService(typeof(ISemanticLog))) A.CallTo(() => services.GetService(typeof(ILogger<ApiExceptionFilterAttribute>)))
.Returns(log); .Returns(log);
var httpContext = new DefaultHttpContext var httpContext = new DefaultHttpContext

6
backend/tests/Squidex.Web.Tests/Pipeline/RequestExceptionMiddlewareTests.cs

@ -10,14 +10,14 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.Infrastructure;
using Squidex.Log; using Microsoft.Extensions.Logging;
using Xunit; using Xunit;
namespace Squidex.Web.Pipeline namespace Squidex.Web.Pipeline
{ {
public class RequestExceptionMiddlewareTests public class RequestExceptionMiddlewareTests
{ {
private readonly ISemanticLog log = A.Fake<ISemanticLog>(); private readonly ILogger<RequestExceptionMiddleware> log = A.Fake<ILogger<RequestExceptionMiddleware>>();
private readonly IActionResultExecutor<ObjectResult> resultWriter = A.Fake<IActionResultExecutor<ObjectResult>>(); private readonly IActionResultExecutor<ObjectResult> resultWriter = A.Fake<IActionResultExecutor<ObjectResult>>();
private readonly IHttpResponseFeature responseFeature = A.Fake<IHttpResponseFeature>(); private readonly IHttpResponseFeature responseFeature = A.Fake<IHttpResponseFeature>();
private readonly HttpContext httpContext = new DefaultHttpContext(); private readonly HttpContext httpContext = new DefaultHttpContext();
@ -113,7 +113,7 @@ namespace Squidex.Web.Pipeline
await sut.InvokeAsync(httpContext, resultWriter, log); await sut.InvokeAsync(httpContext, resultWriter, log);
A.CallTo(() => log.Log(SemanticLogLevel.Error, ex, A<LogFormatter>._)) A.CallTo(log).Where(x => x.Method.Name == "Log" && x.GetArgument<LogLevel>(0) == LogLevel.Error)
.MustHaveHappened(); .MustHaveHappened();
} }

2
frontend/src/app/features/schemas/pages/schema/fields/types/assets-validation.component.html

@ -50,7 +50,7 @@
<div class="col"> <div class="col">
<select class="form-select" formControlName="expectedType"> <select class="form-select" formControlName="expectedType">
<option></option> <option></option>
<option ngValue="Image">{{ 'apps.image' | sqxTranslate }}</option> <option ngValue="Image">Image</option>
<option ngValue="Audio">Audio</option> <option ngValue="Audio">Audio</option>
<option ngValue="Video">Video</option> <option ngValue="Video">Video</option>
<option ngValue="Unknown">Unknown</option> <option ngValue="Unknown">Unknown</option>

Loading…
Cancel
Save