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.SchemaRegistry;
using Confluent.SchemaRegistry.Serdes;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Squidex.Infrastructure.Json;
using Squidex.Infrastructure.Json.Objects;
using Squidex.Log;
using Schema = Avro.Schema;
namespace Squidex.Extensions.Actions.Kafka
@ -26,7 +26,8 @@ namespace Squidex.Extensions.Actions.Kafka
private readonly ISchemaRegistryClient schemaRegistry;
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;
@ -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)
{
case SyslogLevel.Emergency:
level = SemanticLogLevel.Error;
level = LogLevel.Error;
break;
case SyslogLevel.Alert:
level = SemanticLogLevel.Error;
level = LogLevel.Error;
break;
case SyslogLevel.Critical:
level = SemanticLogLevel.Error;
level = LogLevel.Error;
break;
case SyslogLevel.Error:
level = SemanticLogLevel.Error;
level = LogLevel.Error;
break;
case SyslogLevel.Warning:
level = SemanticLogLevel.Warning;
level = LogLevel.Warning;
break;
case SyslogLevel.Notice:
level = SemanticLogLevel.Information;
level = LogLevel.Information;
break;
case SyslogLevel.Info:
level = SemanticLogLevel.Information;
level = LogLevel.Information;
break;
case SyslogLevel.Debug:
level = SemanticLogLevel.Debug;
level = LogLevel.Debug;
break;
}
log.Log(level, null, w => w
.WriteProperty("action", "KafkaAction")
.WriteProperty("name", message.Name)
.WriteProperty("message", message.Message));
log.Log(level, "Kafka log {name}: {message}.", message.Name, message.Message);
}
private static void LogError(ISemanticLog log, Error error)
private static void LogError(ILogger<KafkaProducer> log, Error error)
{
log.LogWarning(w => w
.WriteProperty("action", "KafkaError")
.WriteProperty("reason", error.Reason));
log.LogWarning("Kafka error with {code} and {reason}.", error.Code, error.Reason);
}
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.Models;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Squidex.Domain.Apps.Core.Assets;
using Squidex.Domain.Apps.Entities.Assets;
using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Infrastructure.Json.Objects;
using Squidex.Log;
namespace Squidex.Extensions.Assets.Azure
{
public sealed class AzureMetadataSource : IAssetMetadataSource
{
private const long MaxSize = 5 * 1025 * 1024;
private readonly ISemanticLog log;
private readonly ILogger<AzureMetadataSource> log;
private readonly ComputerVisionClient client;
private readonly char[] trimChars =
{
@ -36,7 +36,8 @@ namespace Squidex.Extensions.Assets.Azure
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))
{
@ -82,9 +83,7 @@ namespace Squidex.Extensions.Assets.Azure
}
catch (Exception ex)
{
log.LogError(ex, w => w
.WriteProperty("action", "EnrichWithAzure")
.WriteProperty("status", "Failed"));
log.LogError(ex, "Failed to enrich asset.");
}
}

7
backend/i18n/frontend_en.json

@ -12,6 +12,7 @@
"apps.appNameWarning": "The app name cannot be changed later.",
"apps.appsButtonCreate": "Apps Overview",
"apps.appsButtonFallbackTitle": "Apps Overview",
"apps.archiveFailed": "Failed to archive app.",
"apps.create": "Create App",
"apps.createBlankApp": "New App",
"apps.createBlankAppDescription": "Create a new blank app without content and schemas.",
@ -36,12 +37,14 @@
"apps.leaveConfirmTitle": "Leave app.",
"apps.leaveFailed": "Failed to leave app. Please reload.",
"apps.listPageTitle": "Apps",
"apps.loadAssetScriptsFailed": "Failed to load asset scripts. Please reload.",
"apps.loadFailed": "Failed to load apps. Please reload.",
"apps.loadSettingsFailed": "Failed to update UI settings. Please reload.",
"apps.removeImage": "Remove image",
"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.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.uploadImageButton": "Upload File",
"apps.uploadImageFailed": "Failed to upload image. Please reload.",
@ -125,6 +128,7 @@
"assets.uploaderUploadHere": "No upload in progress, drop files here.",
"assets.uploadFailed": "Failed to upload asset. Please reload.",
"assets.uploadHint": "Drop file on existing item to replace the asset with a newer version.",
"assetScripts.reloaded": "Asset Scripts reloaded.",
"backups.backupCountAssetsLabel": "Assets",
"backups.backupCountAssetsTooltip": "Archived assets",
"backups.backupCountEventsLabel": "Events",
@ -314,6 +318,7 @@
"common.name": "Name",
"common.no": "No",
"common.nothingChanged": "Nothing has been changed.",
"common.notSupported": "Not Supported",
"common.noValue": "- No value -",
"common.openAPI": "Open API",
"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.appsButtonCreate": "Nuova App",
"apps.appsButtonFallbackTitle": "Lista App",
"apps.archiveFailed": "Failed to archive app.",
"apps.create": "Crea un'App",
"apps.createBlankApp": "Nuova App.",
"apps.createBlankAppDescription": "Crea una app vuota senza contenuti o schema.",
@ -36,12 +37,14 @@
"apps.leaveConfirmTitle": "Esci dall'app.",
"apps.leaveFailed": "Non è stato possibile uscire dall'app. Per favore ricarica.",
"apps.listPageTitle": "App",
"apps.loadAssetScriptsFailed": "Failed to load asset scripts. Please reload.",
"apps.loadFailed": "Non è stato possibile caricare le App. Per favore ricarica.",
"apps.loadSettingsFailed": "Failed to update UI settings. Please reload.",
"apps.removeImage": "Rimuovi l'immagine",
"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.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.uploadImageButton": "Carica il File",
"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.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.",
"assetScripts.reloaded": "Asset Scripts reloaded.",
"backups.backupCountAssetsLabel": "Risorse",
"backups.backupCountAssetsTooltip": "Risorse archiviate",
"backups.backupCountEventsLabel": "Eventi",
@ -314,6 +318,7 @@
"common.name": "Nome",
"common.no": "No",
"common.nothingChanged": "Non è stato cambiato niente.",
"common.notSupported": "Not Supported",
"common.noValue": "- Nessun valore -",
"common.openAPI": "Open API",
"common.or": "o",

7
backend/i18n/frontend_nl.json

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

5
backend/i18n/frontend_zh.json

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

2
backend/i18n/source/backend_en.json

@ -250,7 +250,6 @@
"history.schemas.updated": "updated schema {[Name]}.",
"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.noEmailAddress": "We cannot get the email address from authentication provider.",
"rules.ruleAlreadyRunning": "Another rule is already running.",
"schemas.dateTimeCalculatedDefaultAndDefaultError": "Calculated default value and default value cannot be used together.",
"schemas.duplicateFieldName": "Field '{field}' has been added twice.",
@ -335,6 +334,7 @@
"users.logout.headline": "Logged out!",
"users.logout.text": "!Please close this popup.",
"users.logout.title": "Logout",
"users.noEmailAddress": "We cannot get the email address from authentication provider.",
"users.profile.addLoginDone": "Login added successfully.",
"users.profile.changePassword": "Change Password",
"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.appsButtonCreate": "Apps Overview",
"apps.appsButtonFallbackTitle": "Apps Overview",
"apps.archiveFailed": "Failed to archive app.",
"apps.create": "Create App",
"apps.createBlankApp": "New App",
"apps.createBlankAppDescription": "Create a new blank app without content and schemas.",
@ -36,12 +37,14 @@
"apps.leaveConfirmTitle": "Leave app.",
"apps.leaveFailed": "Failed to leave app. Please reload.",
"apps.listPageTitle": "Apps",
"apps.loadAssetScriptsFailed": "Failed to load asset scripts. Please reload.",
"apps.loadFailed": "Failed to load apps. Please reload.",
"apps.loadSettingsFailed": "Failed to update UI settings. Please reload.",
"apps.removeImage": "Remove image",
"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.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.uploadImageButton": "Upload File",
"apps.uploadImageFailed": "Failed to upload image. Please reload.",
@ -125,6 +128,7 @@
"assets.uploaderUploadHere": "No upload in progress, drop files here.",
"assets.uploadFailed": "Failed to upload asset. Please reload.",
"assets.uploadHint": "Drop file on existing item to replace the asset with a newer version.",
"assetScripts.reloaded": "Asset Scripts reloaded.",
"backups.backupCountAssetsLabel": "Assets",
"backups.backupCountAssetsTooltip": "Archived assets",
"backups.backupCountEventsLabel": "Events",
@ -314,6 +318,7 @@
"common.name": "Name",
"common.no": "No",
"common.nothingChanged": "Nothing has been changed.",
"common.notSupported": "Not Supported",
"common.noValue": "- No value -",
"common.openAPI": "Open API",
"common.or": "or",

2
backend/i18n/source/frontend_nl.json

@ -41,7 +41,7 @@
"apps.removeImage": "Afbeelding verwijderen",
"apps.removeImageFailed": "Verwijderen van app-afbeelding is 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.uploadImageButton": "Upload bestand",
"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))
{
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)));

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

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

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

@ -8,7 +8,6 @@
using Esprima;
using Esprima.Ast;
using Microsoft.Extensions.Caching.Memory;
using Squidex.Infrastructure;
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 Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.ValidateContent.Validators;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Json.Objects;
using Squidex.Infrastructure.Validation;
using Squidex.Log;
namespace Squidex.Domain.Apps.Core.ValidateContent
{
@ -21,7 +21,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
private readonly PartitionResolver partitionResolver;
private readonly ValidationContext context;
private readonly IEnumerable<IValidatorsFactory> factories;
private readonly ISemanticLog log;
private readonly ILogger<ContentValidator> log;
private readonly ConcurrentBag<ValidationError> errors = new ConcurrentBag<ValidationError>();
public IReadOnlyCollection<ValidationError> Errors
@ -29,7 +29,8 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
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(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.
// ==========================================================================
using Microsoft.Extensions.Logging;
using Squidex.Infrastructure.Tasks;
using Squidex.Infrastructure.Translations;
using Squidex.Log;
namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
{
public sealed class AggregateValidator : IValidator
{
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();
@ -34,9 +35,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
}
catch (Exception ex)
{
log.LogError(ex, w => w
.WriteProperty("action", "validateField")
.WriteProperty("status", "Failed"));
log.LogError(ex, "Failed to validate fields.");
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.
// ==========================================================================
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Domain.Apps.Entities.Apps.DomainObject.Guards;
@ -16,7 +17,6 @@ using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.States;
using Squidex.Log;
using Squidex.Shared.Users;
namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
@ -28,8 +28,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
private readonly IAppPlanBillingManager appPlansBillingManager;
private readonly IUserResolver userResolver;
public AppDomainObject(IPersistenceFactory<State> persistence, ISemanticLog log,
InitialSettings initialPatterns,
public AppDomainObject(IPersistenceFactory<State> persistence, ILogger<AppDomainObject> log,
InitialSettings initialSettings,
IAppPlansProvider appPlansProvider,
IAppPlanBillingManager appPlansBillingManager,
IUserResolver userResolver)
@ -38,7 +38,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
this.userResolver = userResolver;
this.appPlansProvider = appPlansProvider;
this.appPlansBillingManager = appPlansBillingManager;
this.initialSettings = initialPatterns;
this.initialSettings = initialSettings;
}
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.
// ==========================================================================
using Microsoft.Extensions.Logging;
using NodaTime;
using Squidex.Domain.Apps.Entities.Notifications;
using Squidex.Domain.Apps.Events.Apps;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Log;
using Squidex.Shared.Users;
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 readonly INotificationSender emailSender;
private readonly IUserResolver userResolver;
private readonly ISemanticLog log;
private readonly ILogger<InvitationEventConsumer> log;
public string Name
{
@ -31,7 +31,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation
get { return "^app-"; }
}
public InvitationEventConsumer(INotificationSender emailSender, IUserResolver userResolver, ISemanticLog log)
public InvitationEventConsumer(INotificationSender emailSender, IUserResolver userResolver,
ILogger<InvitationEventConsumer> log)
{
this.emailSender = emailSender;
this.userResolver = userResolver;
@ -74,7 +75,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation
if (assigner == null)
{
LogWarning($"Assigner {assignerId} not found");
log.LogWarning("Failed to invite user: Assigner {assignerId} not found.", assignerId);
return;
}
@ -82,7 +83,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation
if (assignee == null)
{
LogWarning($"Assignee {assigneeId} not found");
log.LogWarning("Failed to invite user: Assignee {assigneeId} not found.", assigneeId);
return;
}
@ -91,13 +92,5 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation
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.Ast;
using Fluid.Values;
using GraphQL.Utilities;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Domain.Apps.Core.Rules.EnrichedEvents;
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.
// ==========================================================================
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Domain.Apps.Entities.Assets.DomainObject.Guards;
using Squidex.Domain.Apps.Events;
@ -14,7 +15,6 @@ using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.States;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
{
@ -22,7 +22,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
{
private readonly IServiceProvider serviceProvider;
public AssetDomainObject(IPersistenceFactory<State> factory, ISemanticLog log,
public AssetDomainObject(IPersistenceFactory<State> factory, ILogger<AssetDomainObject> log,
IServiceProvider serviceProvider)
: 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.
// ==========================================================================
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Domain.Apps.Entities.Assets.DomainObject.Guards;
using Squidex.Domain.Apps.Events;
@ -13,7 +14,6 @@ using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.States;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
{
@ -21,7 +21,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
{
private readonly IServiceProvider serviceProvider;
public AssetFolderDomainObject(IPersistenceFactory<State> factory, ISemanticLog log,
public AssetFolderDomainObject(IPersistenceFactory<State> factory, ILogger<AssetFolderDomainObject> log,
IServiceProvider serviceProvider)
: base(factory, log)
{

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

@ -7,13 +7,13 @@
using System.Collections.Concurrent;
using System.Threading.Tasks.Dataflow;
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Domain.Apps.Entities.Contents;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Tasks;
using Squidex.Log;
using Squidex.Shared;
#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
{
private readonly IContextProvider contextProvider;
private readonly ISemanticLog log;
private readonly ILogger<AssetsBulkUpdateCommandMiddleware> log;
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.log = log;
@ -139,11 +139,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
}
catch (Exception ex)
{
log.LogError(ex, w => w
.WriteProperty("action", "BulkContent")
.WriteProperty("status", "Failed")
.WriteProperty("jobIndex", task.JobIndex)
.WriteProperty("jobType", task.CommandJob.Type.ToString()));
log.LogError(ex, "Faield to execute asset bulk job with index {index} of type {type}.",
task.JobIndex,
task.CommandJob.Type);
task.Results.Add(new BulkUpdateResultItem(id, task.JobIndex, ex));
}
@ -163,11 +161,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
}
catch (Exception ex)
{
log.LogError(ex, w => w
.WriteProperty("action", "BulkContent")
.WriteProperty("status", "Failed")
.WriteProperty("jobIndex", task.JobIndex)
.WriteProperty("jobType", task.CommandJob.Type.ToString()));
log.LogError(ex, "Faield to execute asset bulk job with index {index} of type {type}.",
task.JobIndex,
task.CommandJob.Type);
task.Results.Add(new BulkUpdateResultItem(id, task.JobIndex, ex));
return null;

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

@ -8,7 +8,6 @@
using Microsoft.Extensions.Options;
using Microsoft.OData;
using Microsoft.OData.Edm;
using NJsonSchema;
using Squidex.Domain.Apps.Core.GenerateFilters;
using Squidex.Domain.Apps.Core.Tags;
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.
// ==========================================================================
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Domain.Apps.Entities.Assets.Repositories;
using Squidex.Domain.Apps.Events.Assets;
using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Reflection;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Assets
{
@ -20,7 +20,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
private readonly ICommandBus commandBus;
private readonly IAssetRepository assetRepository;
private readonly IAssetFolderRepository assetFolderRepository;
private readonly ISemanticLog log;
private readonly ILogger<RecursiveDeleter> log;
private readonly HashSet<string> consumingTypes;
public string Name
@ -38,11 +38,12 @@ namespace Squidex.Domain.Apps.Entities.Assets
IAssetRepository assetRepository,
IAssetFolderRepository assetFolderRepository,
TypeNameRegistry typeNameRegistry,
ISemanticLog log)
ILogger<RecursiveDeleter> log)
{
this.commandBus = commandBus;
this.assetRepository = assetRepository;
this.assetFolderRepository = assetFolderRepository;
this.log = log;
// 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)
{
log.LogError(ex, w => w
.WriteProperty("action", "DeleteAssetsRecursive")
.WriteProperty("status", "Failed"));
log.LogError(ex, "Failed to delete asset recursively.");
}
}

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

@ -7,6 +7,7 @@
using System.Text.RegularExpressions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NodaTime;
using Orleans.Concurrency;
using Squidex.Domain.Apps.Entities.Backup.State;
@ -16,7 +17,6 @@ using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Orleans;
using Squidex.Infrastructure.Tasks;
using Squidex.Infrastructure.Translations;
using Squidex.Log;
using Squidex.Shared.Users;
namespace Squidex.Domain.Apps.Entities.Backup
@ -26,14 +26,14 @@ namespace Squidex.Domain.Apps.Entities.Backup
{
private const int MaxBackups = 10;
private static readonly Duration UpdateDuration = Duration.FromSeconds(1);
private readonly IGrainState<BackupState> state;
private readonly IBackupArchiveLocation backupArchiveLocation;
private readonly IBackupArchiveStore backupArchiveStore;
private readonly IClock clock;
private readonly IServiceProvider serviceProvider;
private readonly IEventDataFormatter eventDataFormatter;
private readonly IEventStore eventStore;
private readonly ISemanticLog log;
private readonly IGrainState<BackupState> state;
private readonly ILogger<BackupGrain> log;
private readonly IUserResolver userResolver;
private CancellationTokenSource? currentJobToken;
private BackupJob? currentJob;
@ -46,8 +46,8 @@ namespace Squidex.Domain.Apps.Entities.Backup
IEventStore eventStore,
IGrainState<BackupState> state,
IServiceProvider serviceProvider,
ISemanticLog log,
IUserResolver userResolver)
IUserResolver userResolver,
ILogger<BackupGrain> log)
{
this.backupArchiveLocation = backupArchiveLocation;
this.backupArchiveStore = backupArchiveStore;
@ -79,9 +79,7 @@ namespace Squidex.Domain.Apps.Entities.Backup
{
foreach (var backup in state.Value.Jobs)
{
#pragma warning disable MA0040 // Flow the cancellation token
await backupArchiveStore.DeleteAsync(backup.Id);
#pragma warning restore MA0040 // Flow the cancellation token
await backupArchiveStore.DeleteAsync(backup.Id, default);
}
TryDeactivateOnIdle();
@ -201,10 +199,7 @@ namespace Squidex.Domain.Apps.Entities.Backup
}
catch (Exception ex)
{
log.LogError(ex, job.Id.ToString(), (ctx, w) => w
.WriteProperty("action", "makeBackup")
.WriteProperty("status", "failed")
.WriteProperty("backupId", ctx));
log.LogError(ex, "Faield to make backup with backup id '{backupId}'.", job.Id);
job.Status = JobStatus.Failed;
}
@ -275,10 +270,7 @@ namespace Squidex.Domain.Apps.Entities.Backup
}
catch (Exception ex)
{
log.LogError(ex, job.Id.ToString(), (logOperationId, w) => w
.WriteProperty("action", "deleteBackup")
.WriteProperty("status", "failed")
.WriteProperty("operationId", logOperationId));
log.LogError(ex, "Failed to make remove with backup id '{backupId}'.", job.Id);
}
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 Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NodaTime;
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Entities.Apps.Commands;
@ -20,7 +21,6 @@ using Squidex.Infrastructure.Orleans;
using Squidex.Infrastructure.States;
using Squidex.Infrastructure.Tasks;
using Squidex.Infrastructure.Translations;
using Squidex.Log;
using Squidex.Shared.Users;
namespace Squidex.Domain.Apps.Entities.Backup
@ -32,7 +32,7 @@ namespace Squidex.Domain.Apps.Entities.Backup
private readonly ICommandBus commandBus;
private readonly IEventStore eventStore;
private readonly IEventDataFormatter eventDataFormatter;
private readonly ISemanticLog log;
private readonly ILogger<RestoreGrain> log;
private readonly IServiceProvider serviceProvider;
private readonly IStreamNameResolver streamNameResolver;
private readonly IUserResolver userResolver;
@ -55,7 +55,7 @@ namespace Squidex.Domain.Apps.Entities.Backup
IServiceProvider serviceProvider,
IStreamNameResolver streamNameResolver,
IUserResolver userResolver,
ISemanticLog log)
ILogger<RestoreGrain> log)
{
this.backupArchiveLocation = backupArchiveLocation;
this.clock = clock;
@ -129,11 +129,6 @@ namespace Squidex.Domain.Apps.Entities.Backup
{
var handlers = CreateHandlers();
var logContext = (
jobId: CurrentJob.Id.ToString(),
jobUrl: CurrentJob.Url.ToString()
);
var ct = default(CancellationToken);
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(" * Complete the restore operation for all objects");
log.LogInformation(logContext, (ctx, w) => w
.WriteProperty("action", "restore")
.WriteProperty("status", "started")
.WriteProperty("operationId", ctx.jobId)
.WriteProperty("url", ctx.jobUrl));
log.LogInformation("Backup with job id {backupId} with from URL '{url}' started.",
CurrentJob.Id,
CurrentJob.Url);
using (var reader = await DownloadAsync())
{
@ -188,13 +181,9 @@ namespace Squidex.Domain.Apps.Entities.Backup
Log("Completed, Yeah!");
log.LogInformation(logContext, (ctx, w) =>
{
w.WriteProperty("action", "restore");
w.WriteProperty("status", "completed");
w.WriteProperty("operationId", ctx.jobId);
w.WriteProperty("url", ctx.jobUrl);
});
log.LogInformation("Backup with job id {backupId} from URL '{url}' completed.",
CurrentJob.Id,
CurrentJob.Url);
}
catch (Exception ex)
{
@ -215,13 +204,9 @@ namespace Squidex.Domain.Apps.Entities.Backup
CurrentJob.Status = JobStatus.Failed;
log.LogError(ex, logContext, (ctx, w) =>
{
w.WriteProperty("action", "restore");
w.WriteProperty("status", "failed");
w.WriteProperty("operationId", ctx.jobId);
w.WriteProperty("url", ctx.jobUrl);
});
log.LogError(ex, "Backup with job id {backupId} from URL '{url}' failed.",
CurrentJob.Id,
CurrentJob.Url);
}
finally
{
@ -279,10 +264,7 @@ namespace Squidex.Domain.Apps.Entities.Backup
}
catch (Exception ex)
{
log.LogError(ex, appId.ToString(), (logOperationId, w) => w
.WriteProperty("action", "cleanupRestore")
.WriteProperty("status", "failed")
.WriteProperty("operationId", logOperationId));
log.LogError(ex, "Failed to clean up restore.");
}
}
}

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

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

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

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

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

@ -7,6 +7,7 @@
using System.Collections.Concurrent;
using System.Threading.Tasks.Dataflow;
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Entities.Contents.Commands;
using Squidex.Domain.Apps.Entities.Schemas;
@ -15,7 +16,6 @@ using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Tasks;
using Squidex.Infrastructure.Translations;
using Squidex.Log;
using Squidex.Shared;
#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 IContextProvider contextProvider;
private readonly ISemanticLog log;
private readonly ILogger<ContentsBulkUpdateCommandMiddleware> log;
private sealed record BulkTaskCommand(BulkTask Task, DomainId Id, ICommand Command)
{
@ -47,10 +47,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
public ContentsBulkUpdateCommandMiddleware(
IContentQueryService contentQuery,
IContextProvider contextProvider,
ISemanticLog log)
ILogger<ContentsBulkUpdateCommandMiddleware> log)
{
this.contentQuery = contentQuery;
this.contextProvider = contextProvider;
this.log = log;
}
@ -148,11 +149,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
}
catch (Exception ex)
{
log.LogError(ex, w => w
.WriteProperty("action", "BulkContent")
.WriteProperty("status", "Failed")
.WriteProperty("jobIndex", task.JobIndex)
.WriteProperty("jobType", task.CommandJob.Type.ToString()));
log.LogError(ex, "Failed to execute content bulk job with index {index} of type {type}.",
task.JobIndex,
task.CommandJob.Type);
task.Results.Add(new BulkUpdateResultItem(id, task.JobIndex, ex));
}
@ -183,11 +182,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
}
catch (Exception ex)
{
log.LogError(ex, w => w
.WriteProperty("action", "BulkContent")
.WriteProperty("status", "Failed")
.WriteProperty("jobIndex", task.JobIndex)
.WriteProperty("jobType", task.CommandJob.Type.ToString()));
log.LogError(ex, "Failed to execute content bulk job with index {index} of type {type}.",
task.JobIndex,
task.CommandJob.Type);
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.
// ==========================================================================
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.DefaultValues;
@ -16,7 +17,6 @@ using Squidex.Infrastructure;
using Squidex.Infrastructure.Json;
using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
{
@ -117,7 +117,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
new ContentValidator(operation.Partition(),
validationContext,
operation.Resolve<IEnumerable<IValidatorsFactory>>(),
operation.Resolve<ISemanticLog>());
operation.Resolve<ILogger<ContentValidator>>());
return validator;
}

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

@ -7,9 +7,9 @@
using GraphQL;
using GraphQL.Resolvers;
using Microsoft.Extensions.Logging;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Validation;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
{
@ -62,11 +62,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
}
catch (Exception ex)
{
executionContext.Resolve<ISemanticLog>().LogWarning(ex, w => w
.WriteProperty("action", "resolveField")
.WriteProperty("status", "failed")
.WriteProperty("field", context.FieldDefinition.Name));
var logFactory = executionContext.Resolve<ILoggerFactory>();
logFactory.CreateLogger("GraphQL").LogError(ex, "Failed to resolve field {field}.", context.FieldDefinition.Name);
throw;
}
}
@ -104,11 +102,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
}
catch (Exception ex)
{
executionContext.Resolve<ISemanticLog>().LogWarning(ex, w => w
.WriteProperty("action", "resolveField")
.WriteProperty("status", "failed")
.WriteProperty("field", context.FieldDefinition.Name));
var logFactory = executionContext.Resolve<ILoggerFactory>();
logFactory.CreateLogger("GraphQL").LogError(ex, "Failed to resolve field {field}.", context.FieldDefinition.Name);
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.OData;
using Microsoft.OData.Edm;
using NJsonSchema;
using Squidex.Domain.Apps.Core.GenerateFilters;
using Squidex.Domain.Apps.Core.Schemas;
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.
// ==========================================================================
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NodaTime;
using Notifo.SDK;
@ -16,7 +17,6 @@ using Squidex.Domain.Apps.Events.Contents;
using Squidex.Domain.Users;
using Squidex.Infrastructure;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Log;
using Squidex.Shared.Identity;
using Squidex.Shared.Users;
@ -30,14 +30,14 @@ namespace Squidex.Domain.Apps.Entities.History
private readonly NotifoOptions options;
private readonly IUrlGenerator urlGenerator;
private readonly IUserResolver userResolver;
private readonly ISemanticLog log;
private readonly ILogger<NotifoService> log;
private readonly IClock clock;
private readonly INotifoClient? client;
public NotifoService(IOptions<NotifoOptions> options,
IUrlGenerator urlGenerator,
IUserResolver userResolver,
ISemanticLog log,
ILogger<NotifoService> log,
IClock clock)
{
this.options = options.Value;
@ -136,16 +136,11 @@ namespace Squidex.Domain.Apps.Entities.History
}
catch (NotifoException ex)
{
log.LogError(ex, w => w
.WriteProperty("action", "RegisterToNotifo")
.WriteProperty("status", "Failed")
.WriteProperty("details", ex.ToString()));
log.LogError(ex, "Failed to register user in notifo: {details}.", ex.ToString());
}
catch (Exception ex)
{
log.LogError(ex, w => w
.WriteProperty("action", "RegisterToNotifo")
.WriteProperty("status", "Failed"));
log.LogError(ex, "Failed to register user in notifo.");
}
}
@ -196,16 +191,11 @@ namespace Squidex.Domain.Apps.Entities.History
}
catch (NotifoException ex)
{
log.LogError(ex, w => w
.WriteProperty("action", "RegisterToNotifo")
.WriteProperty("status", "Failed")
.WriteProperty("details", ex.ToString()));
log.LogError(ex, "Failed to push user to notifo: {details}.", ex.ToString());
}
catch (Exception ex)
{
log.LogError(ex, w => w
.WriteProperty("action", "RegisterToNotifo")
.WriteProperty("status", "Failed"));
log.LogError(ex, "Failed to push user to notifo.");
}
}

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

@ -5,11 +5,11 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Squidex.Domain.Apps.Core;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Email;
using Squidex.Log;
using Squidex.Shared.Identity;
using Squidex.Shared.Users;
@ -19,7 +19,7 @@ namespace Squidex.Domain.Apps.Entities.Notifications
{
private readonly IEmailSender emailSender;
private readonly IUrlGenerator urlGenerator;
private readonly ISemanticLog log;
private readonly ILogger<NotificationEmailSender> log;
private readonly NotificationEmailTextOptions texts;
private sealed class TemplatesVars
@ -46,7 +46,7 @@ namespace Squidex.Domain.Apps.Entities.Notifications
IOptions<NotificationEmailTextOptions> texts,
IEmailSender emailSender,
IUrlGenerator urlGenerator,
ISemanticLog log)
ILogger<NotificationEmailSender> log)
{
this.texts = texts.Value;
this.emailSender = emailSender;
@ -101,13 +101,13 @@ namespace Squidex.Domain.Apps.Entities.Notifications
{
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;
}
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;
}
@ -124,22 +124,11 @@ namespace Squidex.Domain.Apps.Entities.Notifications
}
catch (Exception ex)
{
log.LogError(ex, w => w
.WriteProperty("action", "SendNotification")
.WriteProperty("status", "Failed"));
log.LogError(ex, "Failed to send notification to {email}.", user.Email);
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)
{
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.
// ==========================================================================
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Entities.Rules.Commands;
using Squidex.Domain.Apps.Entities.Rules.DomainObject.Guards;
using Squidex.Domain.Apps.Events;
@ -13,7 +14,6 @@ using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.States;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Rules.DomainObject
{
@ -22,7 +22,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.DomainObject
private readonly IAppProvider appProvider;
private readonly IRuleEnqueuer ruleEnqueuer;
public RuleDomainObject(IPersistenceFactory<State> factory, ISemanticLog log,
public RuleDomainObject(IPersistenceFactory<State> factory, ILogger<RuleDomainObject> log,
IAppProvider appProvider, IRuleEnqueuer ruleEnqueuer)
: base(factory, log)
{

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

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

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

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

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

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Core.EventSynchronization;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Entities.Schemas.Commands;
@ -17,13 +18,12 @@ using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Orleans;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.States;
using Squidex.Log;
namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject
{
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)
{
}

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)
{
throw new ValidationException(T.Get("apps.nameAlreadyExists"));
throw new ValidationException(T.Get("schemas.nameAlreadyExists"));
}
}
catch

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

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

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

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

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

@ -1,4 +1,4 @@
// ==========================================================================
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
@ -8,16 +8,16 @@
using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation;
using Squidex.Log;
using Squidex.Shared.Identity;
namespace Squidex.Domain.Users
{
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;
@ -46,10 +46,7 @@ namespace Squidex.Domain.Users
var errorMessage = errorMessageBuilder.ToString();
log.LogError(errorMessage, (ctx, w) => w
.WriteProperty("action", "IdentityOperation")
.WriteProperty("status", "Failed")
.WriteProperty("message", ctx));
log.LogError("Identity operation failed: {errorMessage}.", errorMessage);
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);
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);

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

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

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

@ -5,64 +5,51 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Squidex.Log;
using Microsoft.Extensions.Logging;
namespace Squidex.Infrastructure.Commands
{
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;
}
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
{
log.LogDebug(logContext, (ctx, w) => w
.WriteProperty("action", "HandleCommand.")
.WriteProperty("actionId", ctx.id)
.WriteProperty("status", "Started")
.WriteProperty("commandType", ctx.command));
if (log.IsEnabled(LogLevel.Debug))
{
log.LogDebug("Command {command} with ID {id} started.", type, context.ContextId);
}
using (log.MeasureInformation(logContext, (ctx, w) => w
.WriteProperty("action", "HandleCommand.")
.WriteProperty("actionId", ctx.id)
.WriteProperty("status", "Completed")
.WriteProperty("commandType", ctx.command)))
var watch = ValueStopwatch.StartNew();
try
{
await next(context);
}
log.LogInformation(logContext, (ctx, w) => w
.WriteProperty("action", "HandleCommand.")
.WriteProperty("actionId", ctx.id)
.WriteProperty("status", "Succeeded")
.WriteProperty("commandType", ctx.command));
log.LogInformation("Command {command} with ID {id} succeeded.", type, context.ContextId);
}
finally
{
log.LogInformation("Command {command} with ID {id} completed after {time}ms.", type, context.ContextId, watch.Stop());
}
}
catch (Exception ex)
{
log.LogError(ex, logContext, (ctx, w) => w
.WriteProperty("action", "HandleCommand.")
.WriteProperty("actionId", ctx.id)
.WriteProperty("status", "Failed")
.WriteProperty("commandType", ctx.command));
log.LogError(ex, "Command {command} with ID {id} failed.", type, context.ContextId);
throw;
}
if (!context.IsCompleted)
{
log.LogFatal(logContext, (ctx, w) => w
.WriteProperty("action", "HandleCommand.")
.WriteProperty("actionId", ctx.id)
.WriteProperty("status", "Unhandled")
.WriteProperty("commandType", ctx.command));
log.LogCritical("Command {command} with ID {id} not handled.", type, context.ContextId);
}
}
}

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

@ -7,11 +7,11 @@
using System.Threading.Tasks.Dataflow;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Squidex.Caching;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.States;
using Squidex.Infrastructure.Tasks;
using Squidex.Log;
#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 IEventStore eventStore;
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()
{
@ -38,12 +38,12 @@ namespace Squidex.Infrastructure.Commands
ILocalCache localCache,
IEventStore eventStore,
IServiceProvider serviceProvider,
ISemanticLog log)
ILogger<Rebuilder> log)
{
this.eventStore = eventStore;
this.serviceProvider = serviceProvider;
this.log = log;
this.localCache = localCache;
this.log = log;
}
public virtual Task RebuildAsync<T, TState>(string filter, int batchSize,
@ -119,11 +119,7 @@ namespace Squidex.Infrastructure.Commands
}
catch (Exception ex)
{
log.LogWarning(ex, w => w
.WriteProperty("reason", "CorruptData")
.WriteProperty("domainObjectId", id.ToString())
.WriteProperty("domainObjectType", typeof(T).Name));
log.LogWarning(ex, "Found corrupt domain object of type {type} with ID {id}.", typeof(T), id);
Interlocked.Increment(ref handlerErrors);
}
}

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

@ -6,9 +6,9 @@
// ==========================================================================
using System.Runtime.CompilerServices;
using Microsoft.Extensions.Logging;
using Squidex.Infrastructure.Orleans;
using Squidex.Infrastructure.Tasks;
using Squidex.Log;
namespace Squidex.Infrastructure.EventSourcing.Grains
{
@ -18,7 +18,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
private readonly IGrainState<EventConsumerState> state;
private readonly IEventDataFormatter eventDataFormatter;
private readonly IEventStore eventStore;
private readonly ISemanticLog log;
private readonly ILogger<EventConsumerGrain> log;
private readonly SemaphoreSlim semaphore = new SemaphoreSlim(1);
private IEventSubscription? currentSubscription;
private IEventConsumer? eventConsumer;
@ -34,7 +34,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
IGrainState<EventConsumerState> state,
IEventStore eventStore,
IEventDataFormatter eventDataFormatter,
ISemanticLog log)
ILogger<EventConsumerGrain> log)
{
this.eventStore = eventStore;
this.eventDataFormatter = eventDataFormatter;
@ -68,9 +68,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
}
catch (Exception ex)
{
log.LogFatal(ex, w => w
.WriteProperty("action", "CompleteConsumer")
.WriteProperty("status", "Failed"));
log.LogCritical(ex, "Failed to complete consumer.");
}
}
}
@ -222,11 +220,8 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
ex = new AggregateException(ex, unsubscribeException);
}
log.LogFatal(ex, w => w
.WriteProperty("action", caller)
.WriteProperty("status", "Failed")
.WriteProperty("eventPosition", position)
.WriteProperty("eventConsumer", eventConsumer!.Name));
log.LogCritical(ex, "Failed to update consumer {consumer} at position {position} from {caller}.",
eventConsumer!.Name, position, caller);
State = previousState.Stopped(ex);
}
@ -244,21 +239,19 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
private async Task ClearAsync()
{
var logContext = (actionId: Guid.NewGuid().ToString(), consumer: eventConsumer!.Name);
log.LogDebug(logContext, (ctx, w) => w
.WriteProperty("action", "EventConsumerReset")
.WriteProperty("actionId", ctx.actionId)
.WriteProperty("status", "Started")
.WriteProperty("eventConsumer", ctx.consumer));
if (log.IsEnabled(LogLevel.Debug))
{
log.LogDebug("Event consumer {consumer} reset started", eventConsumer!.Name);
}
using (log.MeasureInformation(logContext, (ctx, w) => w
.WriteProperty("action", "EventConsumerReset")
.WriteProperty("actionId", ctx.actionId)
.WriteProperty("status", "Completed")
.WriteProperty("eventConsumer", ctx.consumer)))
var watch = ValueStopwatch.StartNew();
try
{
await eventConsumer!.ClearAsync();
}
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 Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Squidex.Infrastructure.Timers;
using Squidex.Log;
namespace Squidex.Infrastructure.Log
{
public sealed class BackgroundRequestLogStore : DisposableObjectBase, IRequestLogStore
{
private readonly IRequestLogRepository logRepository;
private readonly ISemanticLog log;
private readonly ILogger<BackgroundRequestLogStore> log;
private readonly CompletionTimer timer;
private readonly RequestLogStoreOptions options;
private ConcurrentQueue<Request> jobs = new ConcurrentQueue<Request>();
@ -25,7 +25,7 @@ namespace Squidex.Infrastructure.Log
public bool IsEnabled => options.StoreEnabled;
public BackgroundRequestLogStore(IOptions<RequestLogStoreOptions> options,
IRequestLogRepository logRepository, ISemanticLog log)
IRequestLogRepository logRepository, ILogger<BackgroundRequestLogStore> log)
{
this.options = options.Value;
@ -84,9 +84,7 @@ namespace Squidex.Infrastructure.Log
}
catch (Exception ex)
{
log.LogError(ex, w => w
.WriteProperty("action", "TrackUsage")
.WriteProperty("status", "Failed"));
log.LogError(ex, "Failed to track usage in background.");
}
}

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

@ -5,19 +5,20 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Squidex.Log;
using Microsoft.Extensions.Logging;
namespace Squidex.Infrastructure.Migrations
{
public sealed class Migrator
{
private readonly ISemanticLog log;
private readonly IMigrationStatus migrationStatus;
private readonly IMigrationPath migrationPath;
private readonly ILogger<Migrator> log;
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.migrationPath = migrationPath;
@ -50,28 +51,19 @@ namespace Squidex.Infrastructure.Migrations
{
var name = migration.ToString()!;
log.LogInformation(w => w
.WriteProperty("action", "Migration")
.WriteProperty("status", "Started")
.WriteProperty("migrator", name));
log.LogInformation("Migration {migration} started.", name);
try
{
using (log.MeasureInformation(w => w
.WriteProperty("action", "Migration")
.WriteProperty("status", "Completed")
.WriteProperty("migrator", name)))
{
var watch = ValueStopwatch.StartNew();
await migration.UpdateAsync(ct);
}
log.LogInformation("Migration {migration} completed after {time}ms.", name, watch.Stop());
}
catch (Exception ex)
{
log.LogFatal(ex, w => w
.WriteProperty("action", "Migration")
.WriteProperty("status", "Failed")
.WriteProperty("migrator", name));
log.LogCritical(ex, "Migration {migration} failed.", name);
throw new MigrationFailedException(name, ex);
}
}
@ -94,10 +86,7 @@ namespace Squidex.Infrastructure.Migrations
{
while (!await migrationStatus.TryLockAsync(ct))
{
log.LogInformation(w => w
.WriteProperty("action", "Migrate")
.WriteProperty("mesage", $"Waiting {LockWaitMs}ms to acquire lock."));
log.LogInformation("Could not acquire lock to start migrating. Tryping again in {time}ms.", LockWaitMs);
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.
// ==========================================================================
using Microsoft.Extensions.Logging;
using Orleans;
using Squidex.Log;
namespace Squidex.Infrastructure.Orleans
{
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)
@ -48,11 +48,9 @@ namespace Squidex.Infrastructure.Orleans
private void Log(IIncomingGrainCallContext context, Exception ex)
{
log.LogError(ex, w => w
.WriteProperty("action", "GrainInvoked")
.WriteProperty("status", "Failed")
.WriteProperty("grain", context.Grain.ToString())
.WriteProperty("grainMethod", context.ImplementationMethod.ToString()));
var log = logFactory.CreateLogger(context.Grain.GetType());
log.LogError(ex, "Failed to execute method of grain.", context.ImplementationMethod);
}
}
}

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

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

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

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

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

@ -835,9 +835,6 @@
<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>
</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">
<value>È in esecuzione un'altra regola.</value>
</data>
@ -1090,6 +1087,9 @@
<data name="users.logout.title" xml:space="preserve">
<value>Esci</value>
</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">
<value>La login è stata aggiunta con successo.</value>
</data>

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

@ -835,9 +835,6 @@
<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>
</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">
<value>Er wordt al een andere regel uitgevoerd.</value>
</data>
@ -1090,6 +1087,9 @@
<data name="users.logout.title" xml:space="preserve">
<value>Uitloggen</value>
</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">
<value>Login succesvol toegevoegd.</value>
</data>

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

@ -835,9 +835,6 @@
<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>
</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">
<value>Another rule is already running.</value>
</data>
@ -1090,6 +1087,9 @@
<data name="users.logout.title" xml:space="preserve">
<value>Logout</value>
</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">
<value>Login added successfully.</value>
</data>

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

@ -835,9 +835,6 @@
<data name="login.githubPrivateEmail" xml:space="preserve">
<value>您的邮箱在 Github 中设置为私有。请设置为公开以使用 Github 登录。</value>
</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">
<value>另一个规则已经在运行。</value>
</data>
@ -1090,6 +1087,9 @@
<data name="users.logout.title" xml:space="preserve">
<value>注销</value>
</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">
<value>登录添加成功。</value>
</data>

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

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

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

@ -1,4 +1,4 @@
// ==========================================================================
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
@ -11,7 +11,7 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Routing;
using Squidex.Log;
using Microsoft.Extensions.Logging;
namespace Squidex.Web.Pipeline
{
@ -26,7 +26,8 @@ namespace Squidex.Web.Pipeline
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))
{
@ -42,7 +43,7 @@ namespace Squidex.Web.Pipeline
}
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)
{

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

@ -41,8 +41,9 @@ namespace Squidex.Web.Pipeline
log.LogInformation((elapsedMs, context), (ctx, w) =>
{
w.WriteObject("filters", ctx.context, LogFilters);
w.WriteProperty("message", "HTTP request executed.");
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 watch = ValueStopwatch.StartNew();
try
{
await next(context);
@ -70,8 +69,8 @@ namespace Squidex.Web.Pipeline
request.UserId = context.User.OpenIdSubject();
request.UserClientId = clientId;
#pragma warning disable MA0040 // Flow the cancellation token
await usageLog.LogAsync(appId.Value, request);
// Do not flow cancellation token because it is too important.
await usageLog.LogAsync(appId.Value, request, default);
if (request.Costs > 0)
{
@ -81,9 +80,9 @@ namespace Squidex.Web.Pipeline
request.UserClientId,
request.Costs,
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.Domain.Users;
using Squidex.Infrastructure.Commands;
using Squidex.Log;
using Squidex.Shared.Identity;
using Squidex.Shared.Users;
using Squidex.Web;
@ -27,7 +26,7 @@ namespace Squidex.Areas.Api.Controllers.Users
private readonly IHttpClientFactory httpClientFactory;
private readonly IUserPictureStore userPictureStore;
private readonly IUserResolver userResolver;
private readonly ISemanticLog log;
private readonly ILogger<UsersController> log;
static UsersController()
{
@ -46,7 +45,7 @@ namespace Squidex.Areas.Api.Controllers.Users
IHttpClientFactory httpClientFactory,
IUserPictureStore userPictureStore,
IUserResolver userResolver,
ISemanticLog log)
ILogger<UsersController> log)
: base(commandBus)
{
this.httpClientFactory = httpClientFactory;
@ -99,9 +98,7 @@ namespace Squidex.Areas.Api.Controllers.Users
}
catch (Exception ex)
{
log.LogError(ex, w => w
.WriteProperty("action", nameof(GetUsers))
.WriteProperty("status", "Failed"));
log.LogError(ex, "Failed to return users, returning empty results.");
}
return Ok(Array.Empty<UserDto>());
@ -134,9 +131,7 @@ namespace Squidex.Areas.Api.Controllers.Users
}
catch (Exception ex)
{
log.LogError(ex, w => w
.WriteProperty("action", nameof(GetUser))
.WriteProperty("status", "Failed"));
log.LogError(ex, "Failed to return user, returning empty results.");
}
return NotFound();
@ -209,9 +204,7 @@ namespace Squidex.Areas.Api.Controllers.Users
}
catch (Exception ex)
{
log.LogError(ex, w => w
.WriteProperty("action", nameof(GetUser))
.WriteProperty("status", "Failed"));
log.LogError(ex, "Failed to return user picture, returning fallback image.");
}
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.Infrastructure;
using Squidex.Infrastructure.Security;
using Squidex.Log;
using Squidex.Shared;
using Squidex.Shared.Identity;
@ -85,11 +84,9 @@ namespace Squidex.Areas.IdentityServer.Config
}
catch (Exception ex)
{
var log = serviceProvider.GetRequiredService<ISemanticLog>();
var log = serviceProvider.GetRequiredService<ILogger<CreateAdminInitializer>>();
log.LogError(ex, w => w
.WriteProperty("action", "createAdmin")
.WriteProperty("status", "failed"));
log.LogError(ex, "Failed to create administrator.");
}
}
}

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

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

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

@ -8,7 +8,6 @@
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using NodaTime;
using Orleans;
using Squidex.Areas.Api.Controllers.Contents.Generator;
using Squidex.Areas.Api.Controllers.News;
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 Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NodaTime;
using Squidex.Domain.Apps.Core.HandleRules;
@ -18,7 +19,6 @@ using Squidex.Domain.Apps.Events.Contents;
using Squidex.Infrastructure;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Reflection;
using Squidex.Log;
using Xunit;
namespace Squidex.Domain.Apps.Core.Operations.HandleRules
@ -80,7 +80,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules
A.CallTo(() => ruleTriggerHandler.TriggerType)
.Returns(typeof(ContentChangedTriggerV2));
var log = A.Fake<ISemanticLog>();
var log = A.Fake<ILogger<RuleService>>();
sut = new RuleService(Options.Create(new RuleOptions()),
new[] { ruleTriggerHandler },

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

@ -6,6 +6,7 @@
// ==========================================================================
using FakeItEasy;
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas;
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.Infrastructure;
using Squidex.Infrastructure.Validation;
using Squidex.Log;
#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 static readonly ISemanticLog Log = A.Fake<ISemanticLog>();
private static readonly IValidatorsFactory Default = new DefaultValidatorsFactory();
private readonly IValidatorsFactory? validatorFactory;
private readonly ValidationContext validationContext;
@ -153,17 +152,21 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
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)

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

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

@ -6,6 +6,7 @@
// ==========================================================================
using FakeItEasy;
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.TestHelpers;
@ -15,7 +16,6 @@ using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Domain.Apps.Events.Apps;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Json.Objects;
using Squidex.Log;
using Squidex.Shared.Users;
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
sut.Setup(Id);
#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 Microsoft.Extensions.Logging;
using NodaTime;
using Squidex.Domain.Apps.Core.TestHelpers;
using Squidex.Domain.Apps.Entities.Notifications;
using Squidex.Domain.Apps.Events.Apps;
using Squidex.Infrastructure;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Log;
using Squidex.Shared.Users;
using Xunit;
@ -24,7 +24,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation
private readonly IUserResolver userResolver = A.Fake<IUserResolver>();
private readonly IUser assigner = UserMocks.User("1");
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 assigneeId = DomainId.NewGuid().ToString();
private readonly string appName = "my-app";
@ -155,7 +155,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation
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();
}

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

@ -7,6 +7,7 @@
using FakeItEasy;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Squidex.Assets;
using Squidex.Domain.Apps.Core.Assets;
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.Events.Assets;
using Squidex.Infrastructure;
using Squidex.Log;
using Xunit;
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>>._))
.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 =
new ServiceCollection()

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

@ -7,13 +7,13 @@
using FakeItEasy;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Domain.Apps.Entities.Contents.Repositories;
using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Domain.Apps.Events.Assets;
using Squidex.Infrastructure;
using Squidex.Log;
using Xunit;
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>._))
.Returns(new List<IAssetFolderEntity> { A.Fake<IAssetFolderEntity>() });
var log = A.Fake<ISemanticLog>();
var log = A.Fake<ILogger<AssetFolderDomainObject>>();
var serviceProvider =
new ServiceCollection()

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

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

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

@ -6,6 +6,7 @@
// ==========================================================================
using FakeItEasy;
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Domain.Apps.Entities.Assets.Repositories;
using Squidex.Domain.Apps.Events.Assets;
@ -13,14 +14,13 @@ using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Reflection;
using Squidex.Log;
using Xunit;
namespace Squidex.Domain.Apps.Entities.Assets
{
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 IAssetFolderRepository assetFolderRepository = A.Fake<IAssetFolderRepository>();
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)))
.MustHaveHappened();
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!))
A.CallTo(log).Where(x => x.Method.Name == "Log")
.MustHaveHappened();
}
}

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

@ -6,13 +6,13 @@
// ==========================================================================
using FakeItEasy;
using Microsoft.Extensions.Logging;
using NodaTime;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Entities.Contents.Commands;
using Squidex.Domain.Apps.Entities.Contents.Repositories;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands;
using Squidex.Log;
using Xunit;
namespace Squidex.Domain.Apps.Entities.Contents
@ -27,7 +27,9 @@ namespace Squidex.Domain.Apps.Entities.Contents
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]

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

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

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

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

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

@ -12,6 +12,7 @@ using GraphQL.Execution;
using GraphQL.NewtonsoftJson;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
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.Schemas;
using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.Json;
using Squidex.Log;
using Squidex.Shared;
using Squidex.Shared.Users;
using Xunit;
@ -116,7 +115,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
DataLoaderDocumentListener>()
.AddSingleton<IDataLoaderContextAccessor,
DataLoaderContextAccessor>()
.AddSingleton(A.Fake<ISemanticLog>())
.AddSingleton(A.Fake<ILoggerFactory>())
.AddSingleton(appProvider)
.AddSingleton(assetQuery)
.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.
// ==========================================================================
using MongoDB.Driver;
using Xunit;
#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 Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.TestHelpers;
using Squidex.Infrastructure.Email;
using Squidex.Log;
using Squidex.Shared.Users;
using Xunit;
@ -22,7 +22,7 @@ namespace Squidex.Domain.Apps.Entities.Notifications
private readonly IUrlGenerator urlGenerator = A.Fake<IUrlGenerator>();
private readonly IUser assigner = UserMocks.User("1", "1@email.com", "user1");
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 appUI = "my-ui";
private readonly NotificationEmailTextOptions texts = new NotificationEmailTextOptions();
@ -169,7 +169,7 @@ namespace Squidex.Domain.Apps.Entities.Notifications
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();
}
}

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

@ -6,6 +6,7 @@
// ==========================================================================
using FakeItEasy;
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Core.Rules;
using Squidex.Domain.Apps.Core.Rules.Triggers;
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.Infrastructure;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Log;
using Xunit;
namespace Squidex.Domain.Apps.Entities.Rules.DomainObject
@ -37,7 +37,9 @@ namespace Squidex.Domain.Apps.Entities.Rules.DomainObject
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
sut.Setup(Id);
#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 Microsoft.Extensions.Logging;
using NodaTime;
using Squidex.Domain.Apps.Core.HandleRules;
using Squidex.Domain.Apps.Core.Rules;
using Squidex.Domain.Apps.Entities.Rules.Repositories;
using Squidex.Infrastructure;
using Squidex.Log;
using Xunit;
namespace Squidex.Domain.Apps.Entities.Rules
@ -19,7 +19,7 @@ namespace Squidex.Domain.Apps.Entities.Rules
public class RuleDequeuerGrainTests
{
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 IRuleService ruleService = A.Fake<IRuleService>();
private readonly RuleDequeuerGrain sut;
@ -49,7 +49,7 @@ namespace Squidex.Domain.Apps.Entities.Rules
await sut.QueryAsync();
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!))
A.CallTo(log).Where(x => x.Method.Name == "Log")
.MustHaveHappened();
}
@ -63,7 +63,7 @@ namespace Squidex.Domain.Apps.Entities.Rules
await sut.HandleAsync(@event);
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!))
A.CallTo(log).Where(x => x.Method.Name == "Log")
.MustHaveHappened();
}
@ -124,12 +124,12 @@ namespace Squidex.Domain.Apps.Entities.Rules
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();
}
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();
}

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

@ -6,6 +6,7 @@
// ==========================================================================
using FakeItEasy;
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Entities.Schemas.Commands;
@ -14,7 +15,6 @@ using Squidex.Domain.Apps.Events.Schemas;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Collections;
using Squidex.Infrastructure.Commands;
using Squidex.Log;
using Xunit;
namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject
@ -35,7 +35,9 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject
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
sut.Setup(Id);
#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 FluentAssertions;
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Infrastructure;
using Squidex.Log;
using Xunit;
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 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 SearchManager sut;
@ -94,7 +94,7 @@ namespace Squidex.Domain.Apps.Entities.Search
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();
}
}

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

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

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

@ -9,8 +9,8 @@ using System.Globalization;
using System.Security.Claims;
using FakeItEasy;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Squidex.Infrastructure;
using Squidex.Log;
using Squidex.Shared;
using Squidex.Shared.Identity;
using Squidex.Shared.Users;
@ -33,7 +33,9 @@ namespace Squidex.Domain.Users
A.CallTo(userManager).WithReturnType<Task<IdentityResult>>()
.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]

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

@ -6,45 +6,23 @@
// ==========================================================================
using FakeItEasy;
using Squidex.Log;
using Microsoft.Extensions.Logging;
using Xunit;
namespace Squidex.Infrastructure.Commands
{
public class LogCommandMiddlewareTests
{
private readonly MyLog log = new MyLog();
private readonly ILogger<LogCommandMiddleware> log = A.Fake<ILogger<LogCommandMiddleware>>();
private readonly LogCommandMiddleware sut;
private readonly ICommand command = A.Dummy<ICommand>();
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()
{
A.CallTo(() => log.IsEnabled(A<LogLevel>._))
.Returns(true);
sut = new LogCommandMiddleware(log);
}
@ -60,11 +38,11 @@ namespace Squidex.Infrastructure.Commands
return Task.CompletedTask;
});
Assert.Equal(log.LogLevels, new Dictionary<SemanticLogLevel, int>
{
[SemanticLogLevel.Debug] = 1,
[SemanticLogLevel.Information] = 2
});
A.CallTo(log).Where(x => x.Method.Name == "Log" && x.GetArgument<LogLevel>(0) == LogLevel.Debug)
.MustHaveHappened();
A.CallTo(log).Where(x => x.Method.Name == "Log" && x.GetArgument<LogLevel>(0) == LogLevel.Information)
.MustHaveHappenedTwiceExactly();
}
[Fact]
@ -77,12 +55,14 @@ namespace Squidex.Infrastructure.Commands
await sut.HandleAsync(context, c => throw new InvalidOperationException());
});
Assert.Equal(log.LogLevels, new Dictionary<SemanticLogLevel, int>
{
[SemanticLogLevel.Debug] = 1,
[SemanticLogLevel.Information] = 1,
[SemanticLogLevel.Error] = 1
});
A.CallTo(log).Where(x => x.Method.Name == "Log" && x.GetArgument<LogLevel>(0) == LogLevel.Debug)
.MustHaveHappened();
A.CallTo(log).Where(x => x.Method.Name == "Log" && x.GetArgument<LogLevel>(0) == LogLevel.Information)
.MustHaveHappened();
A.CallTo(log).Where(x => x.Method.Name == "Log" && x.GetArgument<LogLevel>(0) == LogLevel.Error)
.MustHaveHappened();
}
[Fact]
@ -92,12 +72,14 @@ namespace Squidex.Infrastructure.Commands
await sut.HandleAsync(context, c => Task.CompletedTask);
Assert.Equal(log.LogLevels, new Dictionary<SemanticLogLevel, int>
{
[SemanticLogLevel.Debug] = 1,
[SemanticLogLevel.Information] = 2,
[SemanticLogLevel.Fatal] = 1
});
A.CallTo(log).Where(x => x.Method.Name == "Log" && x.GetArgument<LogLevel>(0) == LogLevel.Debug)
.MustHaveHappened();
A.CallTo(log).Where(x => x.Method.Name == "Log" && x.GetArgument<LogLevel>(0) == LogLevel.Information)
.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 FluentAssertions;
using Microsoft.Extensions.Logging;
using Orleans.Storage;
using Squidex.Infrastructure.Orleans;
using Squidex.Infrastructure.TestHelpers;
using Squidex.Log;
using Xunit;
namespace Squidex.Infrastructure.EventSourcing.Grains
@ -26,7 +26,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
IGrainState<EventConsumerState> state,
IEventStore eventStore,
IEventDataFormatter eventDataFormatter,
ISemanticLog log)
ILogger<EventConsumerGrain> 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 IEventStore eventStore = A.Fake<IEventStore>();
private readonly IEventSubscription eventSubscription = A.Fake<IEventSubscription>();
private readonly ISemanticLog log = A.Fake<ISemanticLog>();
private readonly StoredEvent storedEvent;
private readonly EventData eventData = new EventData("Type", new EnvelopeHeaders(), "Payload");
private readonly Envelope<IEvent> envelope = new Envelope<IEvent>(new MyEvent());
@ -102,6 +101,8 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
A.CallTo(() => formatter.ParseIfKnown(storedEvent))
.Returns(envelope);
var log = A.Fake<ILogger<EventConsumerGrain>>();
sut = new MyEventConsumerGrain(
x => eventConsumer,
grainState,

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

@ -6,13 +6,13 @@
// ==========================================================================
using FakeItEasy;
using Microsoft.Extensions.Logging;
using Orleans.Internal;
using Squidex.Infrastructure.EventSourcing.Grains;
using Squidex.Infrastructure.Orleans;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Tasks;
using Squidex.Infrastructure.TestHelpers;
using Squidex.Log;
using Xunit;
#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>
{
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;
public MongoEventStoreFixture _ { get; }
@ -155,7 +155,7 @@ namespace Squidex.Infrastructure.EventSourcing
IGrainState<EventConsumerState> state,
IEventStore eventStore,
IEventDataFormatter eventDataFormatter,
ISemanticLog log)
ILogger<EventConsumerGrain> log)
: base(eventConsumerFactory, state, eventStore, eventDataFormatter, log)
{
}

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

@ -7,8 +7,8 @@
using System.Globalization;
using FakeItEasy;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Squidex.Log;
using Xunit;
namespace Squidex.Infrastructure.Log
@ -27,7 +27,9 @@ namespace Squidex.Infrastructure.Log
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
};

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

@ -6,7 +6,7 @@
// ==========================================================================
using FakeItEasy;
using Squidex.Log;
using Microsoft.Extensions.Logging;
using Xunit;
namespace Squidex.Infrastructure.Migrations
@ -17,7 +17,7 @@ namespace Squidex.Infrastructure.Migrations
private readonly CancellationToken ct;
private readonly IMigrationStatus status = A.Fake<IMigrationStatus>();
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)>();
public sealed class InMemoryStatus : IMigrationStatus
@ -216,7 +216,7 @@ namespace Squidex.Infrastructure.Migrations
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();
A.CallTo(() => migrator_1_2.UpdateAsync(ct))

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

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

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

@ -6,10 +6,10 @@
// ==========================================================================
using FakeItEasy;
using Microsoft.Extensions.Logging;
using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.States;
using Squidex.Log;
#pragma warning disable MA0048 // File name must match type name
@ -28,7 +28,7 @@ namespace Squidex.Infrastructure.TestHelpers
}
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 FluentAssertions;
using Squidex.Log;
using Microsoft.Extensions.Logging;
using Xunit;
namespace Squidex.Infrastructure.UsageTracking
@ -17,7 +17,6 @@ namespace Squidex.Infrastructure.UsageTracking
private readonly CancellationTokenSource cts = new CancellationTokenSource();
private readonly CancellationToken ct;
private readonly IUsageRepository usageStore = A.Fake<IUsageRepository>();
private readonly ISemanticLog log = A.Fake<ISemanticLog>();
private readonly string key = Guid.NewGuid().ToString();
private readonly DateTime date = DateTime.Today;
private readonly BackgroundUsageTracker sut;
@ -26,6 +25,8 @@ namespace Squidex.Infrastructure.UsageTracking
{
ct = cts.Token;
var log = A.Fake<ILogger<BackgroundUsageTracker>>();
sut = new BackgroundUsageTracker(usageStore, log)
{
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.Filters;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Logging;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Validation;
using Squidex.Log;
using Xunit;
#pragma warning disable MA0015 // Specify the parameter name in ArgumentException
@ -24,7 +24,7 @@ namespace Squidex.Web
{
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();
[Fact]
@ -59,7 +59,7 @@ namespace Squidex.Web
"property5[0].property6: Error5"
}, ((ErrorDto)result.Value!).Details);
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!))
A.CallTo(log)
.MustNotHaveHappened();
}
@ -72,7 +72,7 @@ namespace Squidex.Web
Assert.IsType<NotFoundResult>(context.Result);
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!))
A.CallTo(log)
.MustNotHaveHappened();
}
@ -85,7 +85,7 @@ namespace Squidex.Web
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();
}
@ -98,7 +98,7 @@ namespace Squidex.Web
Validate(400, context.Result, context.Exception);
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!))
A.CallTo(log)
.MustNotHaveHappened();
}
@ -111,7 +111,7 @@ namespace Squidex.Web
Validate(400, context.Result, context.Exception, "ERROR_CODE_XYZ");
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!))
A.CallTo(log)
.MustNotHaveHappened();
}
@ -124,7 +124,7 @@ namespace Squidex.Web
Validate(400, context.Result, context.Exception);
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!))
A.CallTo(log)
.MustNotHaveHappened();
}
@ -137,7 +137,7 @@ namespace Squidex.Web
Validate(409, context.Result, context.Exception, "OBJECT_CONFLICT");
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!))
A.CallTo(log)
.MustNotHaveHappened();
}
@ -150,7 +150,7 @@ namespace Squidex.Web
Validate(410, context.Result, context.Exception, "OBJECT_DELETED");
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!))
A.CallTo(log)
.MustNotHaveHappened();
}
@ -163,7 +163,7 @@ namespace Squidex.Web
Validate(412, context.Result, context.Exception, "OBJECT_VERSION_CONFLICT");
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!))
A.CallTo(log)
.MustNotHaveHappened();
}
@ -176,7 +176,7 @@ namespace Squidex.Web
Validate(403, context.Result, context.Exception, "FORBIDDEN");
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!))
A.CallTo(log)
.MustNotHaveHappened();
}
@ -189,7 +189,7 @@ namespace Squidex.Web
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();
}
@ -202,7 +202,7 @@ namespace Squidex.Web
Validate(403, context.Result, null);
A.CallTo(() => log.Log(A<SemanticLogLevel>._, A<Exception?>._, A<LogFormatter>._!))
A.CallTo(log)
.MustNotHaveHappened();
}
@ -238,7 +238,7 @@ namespace Squidex.Web
{
var services = A.Fake<IServiceProvider>();
A.CallTo(() => services.GetService(typeof(ISemanticLog)))
A.CallTo(() => services.GetService(typeof(ILogger<ApiExceptionFilterAttribute>)))
.Returns(log);
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.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Squidex.Log;
using Microsoft.Extensions.Logging;
using Xunit;
namespace Squidex.Web.Pipeline
{
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 IHttpResponseFeature responseFeature = A.Fake<IHttpResponseFeature>();
private readonly HttpContext httpContext = new DefaultHttpContext();
@ -113,7 +113,7 @@ namespace Squidex.Web.Pipeline
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();
}

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

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

Loading…
Cancel
Save