Browse Source

add auditing-logging

master
guotianliang 3 years ago
parent
commit
1df5c7f6bd
  1. 2
      Directory.Build.props
  2. 73
      Sanhe.Abp.Framework.sln
  3. 3
      modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/FodyWeavers.xml
  4. 38
      modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/README.md
  5. 20
      modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe.Abp.AuditLogging.Elasticsearch.csproj
  6. 22
      modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/AbpAuditLoggingElasticsearchModule.cs
  7. 17
      modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/AbpAuditLoggingElasticsearchOptions.cs
  8. 104
      modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/AuditLogInfoToAuditLogConverter.cs
  9. 362
      modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/ElasticsearchAuditLogManager.cs
  10. 371
      modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/ElasticsearchEntityChangeStore.cs
  11. 268
      modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/ElasticsearchSecurityLogManager.cs
  12. 10
      modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/IAuditLogInfoToAuditLogConverter.cs
  13. 9
      modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/IIndexInitializer.cs
  14. 7
      modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/IIndexNameNormalizer.cs
  15. 107
      modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/IndexInitializer.cs
  16. 21
      modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/IndexInitializerService.cs
  17. 30
      modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/IndexNameNormalizer.cs
  18. 3
      modules/auditing/Sanhe.Abp.AuditLogging.EntityFrameworkCore/FodyWeavers.xml
  19. 32
      modules/auditing/Sanhe.Abp.AuditLogging.EntityFrameworkCore/README.md
  20. 21
      modules/auditing/Sanhe.Abp.AuditLogging.EntityFrameworkCore/Sanhe.Abp.AuditLogging.EntityFrameworkCore.csproj
  21. 25
      modules/auditing/Sanhe.Abp.AuditLogging.EntityFrameworkCore/Sanhe/Abp/AuditLogging/EntityFrameworkCore/AbpAuditLoggingEntityFrameworkCoreModule.cs
  22. 21
      modules/auditing/Sanhe.Abp.AuditLogging.EntityFrameworkCore/Sanhe/Abp/AuditLogging/EntityFrameworkCore/AbpAuditingMapperProfile.cs
  23. 179
      modules/auditing/Sanhe.Abp.AuditLogging.EntityFrameworkCore/Sanhe/Abp/AuditLogging/EntityFrameworkCore/AuditLogManager.cs
  24. 144
      modules/auditing/Sanhe.Abp.AuditLogging.EntityFrameworkCore/Sanhe/Abp/AuditLogging/EntityFrameworkCore/SecurityLogManager.cs
  25. 3
      modules/auditing/Sanhe.Abp.AuditLogging/FodyWeavers.xml
  26. 17
      modules/auditing/Sanhe.Abp.AuditLogging/Sanhe.Abp.AuditLogging.csproj
  27. 15
      modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/AbpAuditLoggingModule.cs
  28. 115
      modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/AuditLog.cs
  29. 47
      modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/AuditLogAction.cs
  30. 23
      modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/AuditingStore.cs
  31. 96
      modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/DefaultAuditLogManager.cs
  32. 40
      modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/DefaultEntityChangeStore.cs
  33. 87
      modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/DefaultSecurityLogManager.cs
  34. 69
      modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/EntityChange.cs
  35. 9
      modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/EntityChangeWithUsername.cs
  36. 43
      modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/EntityPropertyChange.cs
  37. 64
      modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/IAuditLogManager.cs
  38. 46
      modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/IEntityChangeStore.cs
  39. 56
      modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/ISecurityLogManager.cs
  40. 72
      modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/SecurityLog.cs
  41. 23
      modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/SecurityLogStore.cs
  42. 3
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/FodyWeavers.xml
  43. 28
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe.Abp.Auditing.Application.Contracts.csproj
  44. 34
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AbpAuditingApplicationContractsModule.cs
  45. 18
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AuditLogs/AuditLogActionDto.cs
  46. 55
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AuditLogs/AuditLogDto.cs
  47. 24
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AuditLogs/AuditLogGetByPagedDto.cs
  48. 27
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AuditLogs/EntityChangeDto.cs
  49. 15
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AuditLogs/EntityChangeGetByPagedDto.cs
  50. 7
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AuditLogs/EntityChangeGetWithUsernameDto.cs
  51. 8
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AuditLogs/EntityChangeWithUsernameDto.cs
  52. 16
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AuditLogs/EntityPropertyChangeDto.cs
  53. 16
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AuditLogs/IAuditLogAppService.cs
  54. 17
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AuditLogs/IEntityChangesAppService.cs
  55. 7
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AuditingRemoteServiceConsts.cs
  56. 43
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/Features/AuditingFeatureDefinitionProvider.cs
  57. 15
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/Features/AuditingFeatureNames.cs
  58. 88
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/Localization/Resources/en.json
  59. 88
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/Localization/Resources/zh-Hans.json
  60. 15
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/Logging/Dto/LogDto.cs
  61. 13
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/Logging/Dto/LogExceptionDto.cs
  62. 21
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/Logging/Dto/LogFieldDto.cs
  63. 23
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/Logging/Dto/LogGetByPagedDto.cs
  64. 14
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/Logging/ILogAppService.cs
  65. 35
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/Permissions/AuditingPermissionDefinitionProvider.cs
  66. 18
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/Permissions/AuditingPermissionNames.cs
  67. 16
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/SecurityLogs/ISecurityLogAppService.cs
  68. 30
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/SecurityLogs/SecurityLogDto.cs
  69. 18
      modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/SecurityLogs/SecurityLogGetByPagedDto.cs
  70. 3
      modules/auditing/Sanhe.Abp.Auditing.Application/FodyWeavers.xml
  71. 22
      modules/auditing/Sanhe.Abp.Auditing.Application/Sanhe.Abp.Auditing.Application.csproj
  72. 24
      modules/auditing/Sanhe.Abp.Auditing.Application/Sanhe/Abp/Auditing/AbpAuditingApplicationModule.cs
  73. 31
      modules/auditing/Sanhe.Abp.Auditing.Application/Sanhe/Abp/Auditing/AbpAuditingMapperProfile.cs
  74. 63
      modules/auditing/Sanhe.Abp.Auditing.Application/Sanhe/Abp/Auditing/AuditLogs/AuditLogAppService.cs
  75. 61
      modules/auditing/Sanhe.Abp.Auditing.Application/Sanhe/Abp/Auditing/AuditLogs/EntityChangesAppService.cs
  76. 14
      modules/auditing/Sanhe.Abp.Auditing.Application/Sanhe/Abp/Auditing/AuditingApplicationServiceBase.cs
  77. 49
      modules/auditing/Sanhe.Abp.Auditing.Application/Sanhe/Abp/Auditing/Logging/LogAppService.cs
  78. 57
      modules/auditing/Sanhe.Abp.Auditing.Application/Sanhe/Abp/Auditing/SecurityLogs/SecurityLogAppService.cs
  79. 3
      modules/auditing/Sanhe.Abp.Auditing.HttpApi/FodyWeavers.xml
  80. 19
      modules/auditing/Sanhe.Abp.Auditing.HttpApi/Sanhe.Abp.Auditing.HttpApi.csproj
  81. 41
      modules/auditing/Sanhe.Abp.Auditing.HttpApi/Sanhe/Abp/Auditing/AbpAuditingHttpApiModule.cs
  82. 61
      modules/auditing/Sanhe.Abp.Auditing.HttpApi/Sanhe/Abp/Auditing/AuditLogs/AuditLogController.cs
  83. 49
      modules/auditing/Sanhe.Abp.Auditing.HttpApi/Sanhe/Abp/Auditing/AuditLogs/EntityChangesController.cs
  84. 49
      modules/auditing/Sanhe.Abp.Auditing.HttpApi/Sanhe/Abp/Auditing/Logging/LogController.cs
  85. 62
      modules/auditing/Sanhe.Abp.Auditing.HttpApi/Sanhe/Abp/Auditing/SecurityLogs/SecurityLogController.cs
  86. 3
      modules/logging/Sanhe.Abp.Logging.Serilog.Elasticsearch/FodyWeavers.xml
  87. 32
      modules/logging/Sanhe.Abp.Logging.Serilog.Elasticsearch/README.md
  88. 24
      modules/logging/Sanhe.Abp.Logging.Serilog.Elasticsearch/Sanhe.Abp.Logging.Serilog.Elasticsearch.csproj
  89. 16
      modules/logging/Sanhe.Abp.Logging.Serilog.Elasticsearch/Sanhe/Abp/AuditLogging/Serilog/Elasticsearch/AbpLoggingSerilogElasticsearchMapperProfile.cs
  90. 31
      modules/logging/Sanhe.Abp.Logging.Serilog.Elasticsearch/Sanhe/Abp/AuditLogging/Serilog/Elasticsearch/AbpLoggingSerilogElasticsearchModule.cs
  91. 12
      modules/logging/Sanhe.Abp.Logging.Serilog.Elasticsearch/Sanhe/Abp/AuditLogging/Serilog/Elasticsearch/AbpLoggingSerilogElasticsearchOptions.cs
  92. 412
      modules/logging/Sanhe.Abp.Logging.Serilog.Elasticsearch/Sanhe/Abp/AuditLogging/Serilog/Elasticsearch/SerilogElasticsearchLoggingManager.cs
  93. 26
      modules/logging/Sanhe.Abp.Logging.Serilog.Elasticsearch/Sanhe/Abp/AuditLogging/Serilog/Elasticsearch/SerilogException.cs
  94. 58
      modules/logging/Sanhe.Abp.Logging.Serilog.Elasticsearch/Sanhe/Abp/AuditLogging/Serilog/Elasticsearch/SerilogField.cs
  95. 26
      modules/logging/Sanhe.Abp.Logging.Serilog.Elasticsearch/Sanhe/Abp/AuditLogging/Serilog/Elasticsearch/SerilogInfo.cs
  96. 3
      modules/logging/Sanhe.Abp.Logging/FodyWeavers.xml
  97. 15
      modules/logging/Sanhe.Abp.Logging/README.md
  98. 14
      modules/logging/Sanhe.Abp.Logging/Sanhe.Abp.Logging.csproj
  99. 8
      modules/logging/Sanhe.Abp.Logging/Sanhe/Abp/Logging/AbpLoggingEnricherPropertyNames.cs
  100. 15
      modules/logging/Sanhe.Abp.Logging/Sanhe/Abp/Logging/AbpLoggingModule.cs
  101. Some files were not shown because too many files have changed in this diff Show More

2
Directory.Build.props

@ -5,5 +5,7 @@
<MicrosoftPackageVersion>6.0.*</MicrosoftPackageVersion>
<HangfirePostgreSqlStorageVersion>1.9.7</HangfirePostgreSqlStorageVersion>
<NESTPackageVersion>7.15.1</NESTPackageVersion>
<SerilogPackageVersion>2.10.0</SerilogPackageVersion>
<SerilogSinksElasticsearchPackageVersion>8.4.1</SerilogSinksElasticsearchPackageVersion>
</PropertyGroup>
</Project>

73
Sanhe.Abp.Framework.sln

@ -109,6 +109,28 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sanhe.Abp.MenuManagement.Ht
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "logging", "logging", "{56577207-AF97-4354-9C7A-ABBEE80FA1CA}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "auditing", "auditing", "{5BD41DAA-FBB1-4F52-A5D5-3C1D6A123645}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.Logging", "modules\logging\Sanhe.Abp.Logging\Sanhe.Abp.Logging.csproj", "{1E0D237A-070E-44A5-A2E5-B1EA3FF397C3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sanhe.Abp.Serilog.Enrichers.UniqueId", "modules\logging\Sanhe.Abp.Serilog.Enrichers.UniqueId\Sanhe.Abp.Serilog.Enrichers.UniqueId.csproj", "{68056A12-29B7-41F5-9ABC-1E3BFFC5BF02}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sanhe.Abp.Serilog.Enrichers.Application", "modules\logging\Sanhe.Abp.Serilog.Enrichers.Application\Sanhe.Abp.Serilog.Enrichers.Application.csproj", "{3F2C7B9A-4145-42BF-9470-D7FCAF5D25A6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sanhe.Abp.Logging.Serilog.Elasticsearch", "modules\logging\Sanhe.Abp.Logging.Serilog.Elasticsearch\Sanhe.Abp.Logging.Serilog.Elasticsearch.csproj", "{0DE6DCC3-48CA-4F2F-B6B1-88AA37B0208E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sanhe.Abp.AuditLogging", "modules\auditing\Sanhe.Abp.AuditLogging\Sanhe.Abp.AuditLogging.csproj", "{11D7834B-EB00-4940-AB94-1835AACA0F13}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sanhe.Abp.AuditLogging.Elasticsearch", "modules\auditing\Sanhe.Abp.AuditLogging.Elasticsearch\Sanhe.Abp.AuditLogging.Elasticsearch.csproj", "{539069FD-3973-4DEB-A1EC-2BD25753698C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sanhe.Abp.AuditLogging.EntityFrameworkCore", "modules\auditing\Sanhe.Abp.AuditLogging.EntityFrameworkCore\Sanhe.Abp.AuditLogging.EntityFrameworkCore.csproj", "{8B73A116-D859-439A-B3F0-BB8DE902D2D2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sanhe.Abp.Auditing.Application.Contracts", "modules\auditing\Sanhe.Abp.Auditing.Application.Contracts\Sanhe.Abp.Auditing.Application.Contracts.csproj", "{D014ED3D-E73A-4AFB-873E-C50B81493C8B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sanhe.Abp.Auditing.Application", "modules\auditing\Sanhe.Abp.Auditing.Application\Sanhe.Abp.Auditing.Application.csproj", "{58BE1EAE-9C41-4ED4-B4B9-4F8052B3E9D7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sanhe.Abp.Auditing.HttpApi", "modules\auditing\Sanhe.Abp.Auditing.HttpApi\Sanhe.Abp.Auditing.HttpApi.csproj", "{A82C2175-AD0D-4AF5-B4F9-E264E47617C3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -267,6 +289,46 @@ Global
{4A545053-9CD6-4578-92AF-1637AAC79F80}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4A545053-9CD6-4578-92AF-1637AAC79F80}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4A545053-9CD6-4578-92AF-1637AAC79F80}.Release|Any CPU.Build.0 = Release|Any CPU
{1E0D237A-070E-44A5-A2E5-B1EA3FF397C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1E0D237A-070E-44A5-A2E5-B1EA3FF397C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1E0D237A-070E-44A5-A2E5-B1EA3FF397C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1E0D237A-070E-44A5-A2E5-B1EA3FF397C3}.Release|Any CPU.Build.0 = Release|Any CPU
{68056A12-29B7-41F5-9ABC-1E3BFFC5BF02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{68056A12-29B7-41F5-9ABC-1E3BFFC5BF02}.Debug|Any CPU.Build.0 = Debug|Any CPU
{68056A12-29B7-41F5-9ABC-1E3BFFC5BF02}.Release|Any CPU.ActiveCfg = Release|Any CPU
{68056A12-29B7-41F5-9ABC-1E3BFFC5BF02}.Release|Any CPU.Build.0 = Release|Any CPU
{3F2C7B9A-4145-42BF-9470-D7FCAF5D25A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3F2C7B9A-4145-42BF-9470-D7FCAF5D25A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3F2C7B9A-4145-42BF-9470-D7FCAF5D25A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3F2C7B9A-4145-42BF-9470-D7FCAF5D25A6}.Release|Any CPU.Build.0 = Release|Any CPU
{0DE6DCC3-48CA-4F2F-B6B1-88AA37B0208E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0DE6DCC3-48CA-4F2F-B6B1-88AA37B0208E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0DE6DCC3-48CA-4F2F-B6B1-88AA37B0208E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0DE6DCC3-48CA-4F2F-B6B1-88AA37B0208E}.Release|Any CPU.Build.0 = Release|Any CPU
{11D7834B-EB00-4940-AB94-1835AACA0F13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{11D7834B-EB00-4940-AB94-1835AACA0F13}.Debug|Any CPU.Build.0 = Debug|Any CPU
{11D7834B-EB00-4940-AB94-1835AACA0F13}.Release|Any CPU.ActiveCfg = Release|Any CPU
{11D7834B-EB00-4940-AB94-1835AACA0F13}.Release|Any CPU.Build.0 = Release|Any CPU
{539069FD-3973-4DEB-A1EC-2BD25753698C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{539069FD-3973-4DEB-A1EC-2BD25753698C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{539069FD-3973-4DEB-A1EC-2BD25753698C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{539069FD-3973-4DEB-A1EC-2BD25753698C}.Release|Any CPU.Build.0 = Release|Any CPU
{8B73A116-D859-439A-B3F0-BB8DE902D2D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8B73A116-D859-439A-B3F0-BB8DE902D2D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8B73A116-D859-439A-B3F0-BB8DE902D2D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8B73A116-D859-439A-B3F0-BB8DE902D2D2}.Release|Any CPU.Build.0 = Release|Any CPU
{D014ED3D-E73A-4AFB-873E-C50B81493C8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D014ED3D-E73A-4AFB-873E-C50B81493C8B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D014ED3D-E73A-4AFB-873E-C50B81493C8B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D014ED3D-E73A-4AFB-873E-C50B81493C8B}.Release|Any CPU.Build.0 = Release|Any CPU
{58BE1EAE-9C41-4ED4-B4B9-4F8052B3E9D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{58BE1EAE-9C41-4ED4-B4B9-4F8052B3E9D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{58BE1EAE-9C41-4ED4-B4B9-4F8052B3E9D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{58BE1EAE-9C41-4ED4-B4B9-4F8052B3E9D7}.Release|Any CPU.Build.0 = Release|Any CPU
{A82C2175-AD0D-4AF5-B4F9-E264E47617C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A82C2175-AD0D-4AF5-B4F9-E264E47617C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A82C2175-AD0D-4AF5-B4F9-E264E47617C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A82C2175-AD0D-4AF5-B4F9-E264E47617C3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -319,6 +381,17 @@ Global
{F60BA528-E8FE-465D-BAED-EAC48DE57847} = {1D9012F7-AAA3-49E0-9852-4A97FFB26E8C}
{4A545053-9CD6-4578-92AF-1637AAC79F80} = {1D9012F7-AAA3-49E0-9852-4A97FFB26E8C}
{56577207-AF97-4354-9C7A-ABBEE80FA1CA} = {F5F5D604-531B-4B57-A88E-C9C5CEEC55D7}
{5BD41DAA-FBB1-4F52-A5D5-3C1D6A123645} = {F5F5D604-531B-4B57-A88E-C9C5CEEC55D7}
{1E0D237A-070E-44A5-A2E5-B1EA3FF397C3} = {56577207-AF97-4354-9C7A-ABBEE80FA1CA}
{68056A12-29B7-41F5-9ABC-1E3BFFC5BF02} = {56577207-AF97-4354-9C7A-ABBEE80FA1CA}
{3F2C7B9A-4145-42BF-9470-D7FCAF5D25A6} = {56577207-AF97-4354-9C7A-ABBEE80FA1CA}
{0DE6DCC3-48CA-4F2F-B6B1-88AA37B0208E} = {56577207-AF97-4354-9C7A-ABBEE80FA1CA}
{11D7834B-EB00-4940-AB94-1835AACA0F13} = {5BD41DAA-FBB1-4F52-A5D5-3C1D6A123645}
{539069FD-3973-4DEB-A1EC-2BD25753698C} = {5BD41DAA-FBB1-4F52-A5D5-3C1D6A123645}
{8B73A116-D859-439A-B3F0-BB8DE902D2D2} = {5BD41DAA-FBB1-4F52-A5D5-3C1D6A123645}
{D014ED3D-E73A-4AFB-873E-C50B81493C8B} = {5BD41DAA-FBB1-4F52-A5D5-3C1D6A123645}
{58BE1EAE-9C41-4ED4-B4B9-4F8052B3E9D7} = {5BD41DAA-FBB1-4F52-A5D5-3C1D6A123645}
{A82C2175-AD0D-4AF5-B4F9-E264E47617C3} = {5BD41DAA-FBB1-4F52-A5D5-3C1D6A123645}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AB69BFDE-9DDB-4D16-8CB8-72472C0319CD}

3
modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

38
modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/README.md

@ -0,0 +1,38 @@
# LINGYUN.Abp.AuditLogging.Elasticsearch
审计模块 Elasticsearch 实现
ElasticsearchAuditLogManager 实现了 IAuditLogManager, 审计日志由ES管理
ElasticsearchSecurityLogManager 实现了 ISecurityLogManager, 安全日志由ES管理
## 模块引用
```csharp
[DependsOn(typeof(AbpAuditLoggingElasticsearchModule))]
public class YouProjectModule : AbpModule
{
// other
}
```
## 配置项
* AbpAuditLoggingElasticsearchOptions.IndexPrefix 索引前缀, 默认 auditlogging
## 注意事项
与租户模块集成, 跨租户时将会切换索引
## appsettings.json
```json
{
"AuditLogging": {
"Elasticsearch": {
"IndexPrefix": "auditlogging"
}
}
}
```

20
modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe.Abp.AuditLogging.Elasticsearch.csproj

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Json" Version="$(VoloAbpVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\elasticsearch\Sanhe.Abp.Elasticsearch\Sanhe.Abp.Elasticsearch.csproj" />
<ProjectReference Include="..\Sanhe.Abp.AuditLogging\Sanhe.Abp.AuditLogging.csproj" />
</ItemGroup>
</Project>

22
modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/AbpAuditLoggingElasticsearchModule.cs

@ -0,0 +1,22 @@
using Sanhe.Abp.Elasticsearch;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Json;
using Volo.Abp.Modularity;
namespace Sanhe.Abp.AuditLogging.Elasticsearch
{
[DependsOn(
typeof(AbpAuditLoggingModule),
typeof(AbpElasticsearchModule),
typeof(AbpJsonModule))]
public class AbpAuditLoggingElasticsearchModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
Configure<AbpAuditLoggingElasticsearchOptions>(configuration.GetSection("AuditLogging:Elasticsearch"));
context.Services.AddHostedService<IndexInitializerService>();
}
}
}

17
modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/AbpAuditLoggingElasticsearchOptions.cs

@ -0,0 +1,17 @@
using Nest;
namespace Sanhe.Abp.AuditLogging.Elasticsearch
{
public class AbpAuditLoggingElasticsearchOptions
{
public const string DefaultIndexPrefix = "auditlogging";
public string IndexPrefix { get; set; }
public IIndexSettings IndexSettings { get; set; }
public AbpAuditLoggingElasticsearchOptions()
{
IndexPrefix = DefaultIndexPrefix;
IndexSettings = new IndexSettings();
}
}
}

104
modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/AuditLogInfoToAuditLogConverter.cs

@ -0,0 +1,104 @@
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.ExceptionHandling;
using Volo.Abp.Auditing;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Guids;
using Volo.Abp.Http;
using Volo.Abp.Json;
namespace Sanhe.Abp.AuditLogging.Elasticsearch
{
public class AuditLogInfoToAuditLogConverter : IAuditLogInfoToAuditLogConverter, ITransientDependency
{
protected IGuidGenerator GuidGenerator { get; }
protected AbpExceptionHandlingOptions ExceptionHandlingOptions { get; }
protected IExceptionToErrorInfoConverter ExceptionToErrorInfoConverter { get; }
protected IJsonSerializer JsonSerializer { get; }
public AuditLogInfoToAuditLogConverter(
IGuidGenerator guidGenerator,
IOptions<AbpExceptionHandlingOptions> exceptionHandlingOptions,
IExceptionToErrorInfoConverter exceptionToErrorInfoConverter,
IJsonSerializer jsonSerializer)
{
GuidGenerator = guidGenerator;
ExceptionHandlingOptions = exceptionHandlingOptions.Value;
ExceptionToErrorInfoConverter = exceptionToErrorInfoConverter;
JsonSerializer = jsonSerializer;
}
public virtual Task<AuditLog> ConvertAsync(AuditLogInfo auditLogInfo)
{
var auditLogId = GuidGenerator.Create();
var extraProperties = new ExtraPropertyDictionary();
if (auditLogInfo.ExtraProperties != null)
{
foreach (var pair in auditLogInfo.ExtraProperties)
{
extraProperties.Add(pair.Key, pair.Value);
}
}
var entityChanges = auditLogInfo
.EntityChanges?
.Select(entityChangeInfo => new EntityChange(GuidGenerator, auditLogId, entityChangeInfo, tenantId: auditLogInfo.TenantId))
.ToList()
?? new List<EntityChange>();
var actions = auditLogInfo
.Actions?
.Select(auditLogActionInfo => new AuditLogAction(GuidGenerator.Create(), auditLogId, auditLogActionInfo, tenantId: auditLogInfo.TenantId))
.ToList()
?? new List<AuditLogAction>();
var remoteServiceErrorInfos = auditLogInfo.Exceptions?.Select(exception =>
ExceptionToErrorInfoConverter.Convert(exception, options =>
{
options.SendExceptionsDetailsToClients = ExceptionHandlingOptions.SendExceptionsDetailsToClients;
options.SendStackTraceToClients = ExceptionHandlingOptions.SendStackTraceToClients;
})) ?? new List<RemoteServiceErrorInfo>();
var exceptions = remoteServiceErrorInfos.Any()
? JsonSerializer.Serialize(remoteServiceErrorInfos, indented: true)
: null;
var comments = auditLogInfo
.Comments?
.JoinAsString(Environment.NewLine);
var auditLog = new AuditLog(
auditLogId,
auditLogInfo.ApplicationName,
auditLogInfo.TenantId,
auditLogInfo.TenantName,
auditLogInfo.UserId,
auditLogInfo.UserName,
auditLogInfo.ExecutionTime,
auditLogInfo.ExecutionDuration,
auditLogInfo.ClientIpAddress,
auditLogInfo.ClientName,
auditLogInfo.ClientId,
auditLogInfo.CorrelationId,
auditLogInfo.BrowserInfo,
auditLogInfo.HttpMethod,
auditLogInfo.Url,
auditLogInfo.HttpStatusCode,
auditLogInfo.ImpersonatorUserId,
auditLogInfo.ImpersonatorTenantId,
extraProperties,
entityChanges,
actions,
exceptions,
comments
);
return Task.FromResult(auditLog);
}
}
}

362
modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/ElasticsearchAuditLogManager.cs

@ -0,0 +1,362 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Nest;
using Sanhe.Abp.Elasticsearch;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Auditing;
using Volo.Abp.DependencyInjection;
namespace Sanhe.Abp.AuditLogging.Elasticsearch
{
[Dependency(ReplaceServices = true)]
public class ElasticsearchAuditLogManager : IAuditLogManager, ITransientDependency
{
private readonly AbpAuditingOptions _auditingOptions;
private readonly AbpElasticsearchOptions _elasticsearchOptions;
private readonly IIndexNameNormalizer _indexNameNormalizer;
private readonly IElasticsearchClientFactory _clientFactory;
private readonly IAuditLogInfoToAuditLogConverter _converter;
public ILogger<ElasticsearchAuditLogManager> Logger { protected get; set; }
public ElasticsearchAuditLogManager(
IIndexNameNormalizer indexNameNormalizer,
IOptions<AbpElasticsearchOptions> elasticsearchOptions,
IElasticsearchClientFactory clientFactory,
IOptions<AbpAuditingOptions> auditingOptions,
IAuditLogInfoToAuditLogConverter converter)
{
_converter = converter;
_clientFactory = clientFactory;
_auditingOptions = auditingOptions.Value;
_elasticsearchOptions = elasticsearchOptions.Value;
_indexNameNormalizer = indexNameNormalizer;
Logger = NullLogger<ElasticsearchAuditLogManager>.Instance;
}
public virtual async Task<long> GetCountAsync(
DateTime? startTime = null,
DateTime? endTime = null,
string httpMethod = null,
string url = null,
Guid? userId = null,
string userName = null,
string applicationName = null,
string correlationId = null,
string clientId = null,
string clientIpAddress = null,
int? maxExecutionDuration = null,
int? minExecutionDuration = null,
bool? hasException = null,
HttpStatusCode? httpStatusCode = null,
CancellationToken cancellationToken = default)
{
var client = _clientFactory.Create();
var querys = BuildQueryDescriptor(
startTime,
endTime,
httpMethod,
url,
userId,
userName,
applicationName,
correlationId,
clientId,
clientIpAddress,
maxExecutionDuration,
minExecutionDuration,
hasException,
httpStatusCode);
var response = await client.CountAsync<AuditLog>(dsl =>
dsl.Index(CreateIndex())
.Query(log => log.Bool(b => b.Must(querys.ToArray()))),
cancellationToken);
return response.Count;
}
public virtual async Task<List<AuditLog>> GetListAsync(
string sorting = null,
int maxResultCount = 50,
int skipCount = 0,
DateTime? startTime = null,
DateTime? endTime = null,
string httpMethod = null,
string url = null,
Guid? userId = null,
string userName = null,
string applicationName = null,
string correlationId = null,
string clientId = null,
string clientIpAddress = null,
int? maxExecutionDuration = null,
int? minExecutionDuration = null,
bool? hasException = null,
HttpStatusCode? httpStatusCode = null,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
var client = _clientFactory.Create();
var sortOrder = !sorting.IsNullOrWhiteSpace() && sorting.EndsWith("asc", StringComparison.InvariantCultureIgnoreCase)
? SortOrder.Ascending : SortOrder.Descending;
sorting = !sorting.IsNullOrWhiteSpace()
? sorting.Split()[0]
: nameof(AuditLog.ExecutionTime);
var querys = BuildQueryDescriptor(
startTime,
endTime,
httpMethod,
url,
userId,
userName,
applicationName,
correlationId,
clientId,
clientIpAddress,
maxExecutionDuration,
minExecutionDuration,
hasException,
httpStatusCode);
SourceFilterDescriptor<AuditLog> SourceFilter(SourceFilterDescriptor<AuditLog> selector)
{
selector.IncludeAll();
if (!includeDetails)
{
selector.Excludes(field =>
field.Field(f => f.Actions)
.Field(f => f.Comments)
.Field(f => f.Exceptions)
.Field(f => f.EntityChanges));
}
return selector;
}
var response = await client.SearchAsync<AuditLog>(dsl =>
dsl.Index(CreateIndex())
.Query(log => log.Bool(b => b.Must(querys.ToArray())))
.Source(SourceFilter)
.Sort(log => log.Field(GetField(sorting), sortOrder))
.From(skipCount)
.Size(maxResultCount),
cancellationToken);
return response.Documents.ToList();
}
public virtual async Task<AuditLog> GetAsync(
Guid id,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
var client = _clientFactory.Create();
var response = await client.GetAsync<AuditLog>(
id,
dsl =>
dsl.Index(CreateIndex()),
cancellationToken);
return response.Source;
}
public virtual async Task DeleteAsync(Guid id, CancellationToken cancellationToken = default)
{
var client = _clientFactory.Create();
await client.DeleteAsync<AuditLog>(
id,
dsl =>
dsl.Index(CreateIndex()),
cancellationToken);
}
public virtual async Task<string> SaveAsync(
AuditLogInfo auditInfo,
CancellationToken cancellationToken = default)
{
if (!_auditingOptions.HideErrors)
{
return await SaveLogAsync(auditInfo, cancellationToken);
}
try
{
return await SaveLogAsync(auditInfo, cancellationToken);
}
catch (Exception ex)
{
Logger.LogWarning("Could not save the audit log object: " + Environment.NewLine + auditInfo.ToString());
Logger.LogException(ex, Microsoft.Extensions.Logging.LogLevel.Error);
}
return "";
}
protected virtual async Task<string> SaveLogAsync(
AuditLogInfo auditLogInfo,
CancellationToken cancellationToken = default)
{
var client = _clientFactory.Create();
var auditLog = await _converter.ConvertAsync(auditLogInfo);
var response = await client.IndexAsync(
auditLog,
(x) => x.Index(CreateIndex())
.Id(auditLog.Id),
cancellationToken);
return response.Id;
}
protected virtual List<Func<QueryContainerDescriptor<AuditLog>, QueryContainer>> BuildQueryDescriptor(
DateTime? startTime = null,
DateTime? endTime = null,
string httpMethod = null,
string url = null,
Guid? userId = null,
string userName = null,
string applicationName = null,
string correlationId = null,
string clientId = null,
string clientIpAddress = null,
int? maxExecutionDuration = null,
int? minExecutionDuration = null,
bool? hasException = null,
HttpStatusCode? httpStatusCode = null)
{
var querys = new List<Func<QueryContainerDescriptor<AuditLog>, QueryContainer>>();
if (startTime.HasValue)
{
querys.Add((log) => log.DateRange((q) => q.Field(GetField(nameof(AuditLog.ExecutionTime))).GreaterThanOrEquals(startTime)));
}
if (endTime.HasValue)
{
querys.Add((log) => log.DateRange((q) => q.Field(GetField(nameof(AuditLog.ExecutionTime))).LessThanOrEquals(endTime)));
}
if (!httpMethod.IsNullOrWhiteSpace())
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(AuditLog.HttpMethod))).Value(httpMethod)));
}
if (!url.IsNullOrWhiteSpace())
{
querys.Add((log) => log.Wildcard((q) => q.Field(GetField(nameof(AuditLog.Url))).Value($"*{url}*")));
}
if (userId.HasValue)
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(AuditLog.UserId))).Value(userId)));
}
if (!userName.IsNullOrWhiteSpace())
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(AuditLog.UserName))).Value(userName)));
}
if (!applicationName.IsNullOrWhiteSpace())
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(AuditLog.ApplicationName))).Value(applicationName)));
}
if (!correlationId.IsNullOrWhiteSpace())
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(AuditLog.CorrelationId))).Value(correlationId)));
}
if (!clientId.IsNullOrWhiteSpace())
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(AuditLog.ClientId))).Value(clientId)));
}
if (!clientIpAddress.IsNullOrWhiteSpace())
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(AuditLog.ClientIpAddress))).Value(clientIpAddress)));
}
if (maxExecutionDuration.HasValue)
{
querys.Add((log) => log.Range((q) => q.Field(GetField(nameof(AuditLog.ExecutionDuration))).LessThanOrEquals(maxExecutionDuration)));
}
if (minExecutionDuration.HasValue)
{
querys.Add((log) => log.Range((q) => q.Field(GetField(nameof(AuditLog.ExecutionDuration))).GreaterThanOrEquals(minExecutionDuration)));
}
if (hasException.HasValue)
{
if (hasException.Value)
{
querys.Add(
(q) => q.Bool(
(b) => b.Must(
(m) => m.Exists(
(e) => e.Field((f) => f.Exceptions)))
)
);
}
else
{
querys.Add(
(q) => q.Bool(
(b) => b.MustNot(
(mn) => mn.Exists(
(e) => e.Field(
(f) => f.Exceptions)))
)
);
}
}
if (httpStatusCode.HasValue)
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(AuditLog.HttpStatusCode))).Value(httpStatusCode)));
}
return querys;
}
protected virtual string CreateIndex()
{
return _indexNameNormalizer.NormalizeIndex("audit-log");
}
private readonly static IDictionary<string, string> _fieldMaps = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase)
{
{ "Id", "Id.keyword" },
{ "ApplicationName", "ApplicationName.keyword" },
{ "UserId", "UserId.keyword" },
{ "UserName", "UserName.keyword" },
{ "TenantId", "TenantId.keyword" },
{ "TenantName", "TenantName.keyword" },
{ "ImpersonatorUserId", "ImpersonatorUserId.keyword" },
{ "ImpersonatorTenantId", "ImpersonatorTenantId.keyword" },
{ "ClientName", "ClientName.keyword" },
{ "ClientIpAddress", "ClientIpAddress.keyword" },
{ "ClientId", "ClientId.keyword" },
{ "CorrelationId", "CorrelationId.keyword" },
{ "BrowserInfo", "BrowserInfo.keyword" },
{ "HttpMethod", "HttpMethod.keyword" },
{ "Url", "Url.keyword" },
{ "ExecutionDuration", "ExecutionDuration" },
{ "ExecutionTime", "ExecutionTime" },
{ "HttpStatusCode", "HttpStatusCode" },
};
protected virtual string GetField(string field)
{
if (_fieldMaps.TryGetValue(field, out var mapField))
{
return _elasticsearchOptions.FieldCamelCase ? mapField.ToCamelCase() : mapField.ToPascalCase();
}
return _elasticsearchOptions.FieldCamelCase ? field.ToCamelCase() : field.ToPascalCase();
}
}
}

371
modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/ElasticsearchEntityChangeStore.cs

@ -0,0 +1,371 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Nest;
using Sanhe.Abp.Elasticsearch;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Auditing;
using Volo.Abp.DependencyInjection;
namespace Sanhe.Abp.AuditLogging.Elasticsearch;
[Dependency(ReplaceServices = true)]
public class ElasticsearchEntityChangeStore : IEntityChangeStore, ITransientDependency
{
private readonly AbpElasticsearchOptions _elasticsearchOptions;
private readonly IIndexNameNormalizer _indexNameNormalizer;
private readonly IElasticsearchClientFactory _clientFactory;
public ILogger<ElasticsearchEntityChangeStore> Logger { protected get; set; }
public ElasticsearchEntityChangeStore(
IIndexNameNormalizer indexNameNormalizer,
IElasticsearchClientFactory clientFactory,
IOptions<AbpElasticsearchOptions> elasticsearchOptions)
{
_clientFactory = clientFactory;
_indexNameNormalizer = indexNameNormalizer;
_elasticsearchOptions = elasticsearchOptions.Value;
Logger = NullLogger<ElasticsearchEntityChangeStore>.Instance;
}
public async virtual Task<EntityChange> GetAsync(
Guid entityChangeId,
CancellationToken cancellationToken = default)
{
var client = _clientFactory.Create();
var resposne = await client.SearchAsync<EntityChange>(
dsl => dsl.Index(CreateIndex())
.Query(query =>
query.Bool(bo =>
bo.Must(m =>
m.Nested(n =>
n.InnerHits()
.Path("EntityChanges")
.Query(nq =>
nq.Term(nqt =>
nqt.Field(GetField(nameof(EntityChange.Id))).Value(entityChangeId)))))))
.Source(x => x.Excludes(f => f.Field("*")))
.Sort(entity => entity.Field("EntityChanges.ChangeTime", SortOrder.Descending))
.Size(1),
ct: cancellationToken);
if (resposne.Shards.Successful > 0)
{
var hits = resposne.Hits.FirstOrDefault();
if (hits.InnerHits.Count > 0)
{
return hits.InnerHits.First().Value.Documents<EntityChange>().FirstOrDefault();
}
}
return null;
}
public async virtual Task<long> GetCountAsync(
Guid? auditLogId = null,
DateTime? startTime = null,
DateTime? endTime = null,
EntityChangeType? changeType = null,
string entityId = null,
string entityTypeFullName = null,
CancellationToken cancellationToken = default)
{
await Task.CompletedTask;
return 0;
//var client = _clientFactory.Create();
//var querys = BuildQueryDescriptor(
// auditLogId,
// startTime,
// endTime,
// changeType,
// entityId,
// entityTypeFullName);
//Func<QueryContainerDescriptor<EntityChange>, QueryContainer> selector = q => q.MatchAll();
//if (querys.Count > 0)
//{
// selector = q => q.Bool(b => b.Must(querys.ToArray()));
//}
//var response = await client.CountAsync<EntityChange>(dsl =>
// dsl.Index(CreateIndex())
// .Query(q =>
// q.Bool(b =>
// b.Must(m =>
// m.Nested(n =>
// n.InnerHits(hit => hit.Source(s => s.ExcludeAll()))
// .Path("EntityChanges")
// .Query(selector)
// )
// )
// )
// ),
// ct: cancellationToken);
//return response.Count;
}
public async virtual Task<List<EntityChange>> GetListAsync(
string sorting = null,
int maxResultCount = 50,
int skipCount = 0,
Guid? auditLogId = null,
DateTime? startTime = null,
DateTime? endTime = null,
EntityChangeType? changeType = null,
string entityId = null,
string entityTypeFullName = null,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
// TODO: 需要解决Nested格式数据返回方式
//var client = _clientFactory.Create();
//var sortOrder = !sorting.IsNullOrWhiteSpace() && sorting.EndsWith("asc", StringComparison.InvariantCultureIgnoreCase)
// ? SortOrder.Ascending : SortOrder.Descending;
//sorting = !sorting.IsNullOrWhiteSpace()
// ? sorting.Split()[0]
// : nameof(EntityChange.ChangeTime);
//var querys = BuildQueryDescriptor(
// auditLogId,
// startTime,
// endTime,
// changeType,
// entityId,
// entityTypeFullName);
//SourceFilterDescriptor<EntityChange> SourceFilter(SourceFilterDescriptor<EntityChange> selector)
//{
// selector.Includes(GetEntityChangeSources());
// if (!includeDetails)
// {
// selector.Excludes(field =>
// field.Field("EntityChanges.PropertyChanges")
// .Field("EntityChanges.ExtraProperties"));
// }
// return selector;
//}
//Func<QueryContainerDescriptor<EntityChange>, QueryContainer> selector = q => q.MatchAll();
//if (querys.Count > 0)
//{
// selector = q => q.Bool(b => b.Must(querys.ToArray()));
//}
//var response = await client.SearchAsync<EntityChange>(dsl =>
// dsl.Index(CreateIndex())
// .Query(q =>
// q.Bool(b =>
// b.Must(m =>
// m.Nested(n =>
// n.InnerHits(hit => hit.Source(SourceFilter))
// .Path("EntityChanges")
// .Query(selector)
// )
// )
// )
// )
// .Source(x => x.Excludes(f => f.Field("*")))
// .Sort(entity => entity.Field(GetField(sorting), sortOrder))
// .From(skipCount)
// .Size(maxResultCount),
// cancellationToken);
//if (response.Shards.Successful > 0)
//{
// var hits = response.Hits.FirstOrDefault();
// if (hits.InnerHits.Count > 0)
// {
// return hits.InnerHits.First().Value.Documents<EntityChange>().ToList();
// }
//}
await Task.CompletedTask;
return new List<EntityChange>();
}
public async virtual Task<EntityChangeWithUsername> GetWithUsernameAsync(
Guid entityChangeId,
CancellationToken cancellationToken = default)
{
var client = _clientFactory.Create();
var response = await client.SearchAsync<AuditLog>(
dsl => dsl.Index(CreateIndex())
.Query(query =>
query.Bool(bo =>
bo.Must(m =>
m.Nested(n =>
n.InnerHits()
.Path("EntityChanges")
.Query(nq =>
nq.Bool(nb =>
nb.Must(nm =>
nm.Term(nt =>
nt.Field(GetField(nameof(EntityChange.Id))).Value(entityChangeId)))))))))
.Source(selector => selector.Includes(field =>
field.Field(f => f.UserName)))
.Size(1),
ct: cancellationToken);
var auditLog = response.Documents.FirstOrDefault();
EntityChange entityChange = null;
if (response.Shards.Successful > 0)
{
var hits = response.Hits.FirstOrDefault();
if (hits.InnerHits.Count > 0)
{
entityChange = hits.InnerHits.First().Value.Documents<EntityChange>().FirstOrDefault();
}
}
return new EntityChangeWithUsername()
{
EntityChange = entityChange,
UserName = auditLog?.UserName
};
}
public async virtual Task<List<EntityChangeWithUsername>> GetWithUsernameAsync(
string entityId,
string entityTypeFullName,
CancellationToken cancellationToken = default)
{
var client = _clientFactory.Create();
var response = await client.SearchAsync<AuditLog>(
dsl => dsl.Index(CreateIndex())
.Query(query =>
query.Bool(bo =>
bo.Must(m =>
m.Nested(n =>
n.InnerHits()
.Path("EntityChanges")
.Query(nq =>
nq.Bool(nb =>
nb.Must(nm =>
nm.Term(nt =>
nt.Field(GetField(nameof(EntityChange.EntityId))).Value(entityId)),
nm =>
nm.Term(nt =>
nt.Field(GetField(nameof(EntityChange.EntityTypeFullName))).Value(entityTypeFullName))
)
)
)
)
)
)
)
.Source(selector => selector.Includes(field =>
field.Field(f => f.UserName)))
.Sort(entity => entity.Field(f => f.ExecutionTime, SortOrder.Descending)),
ct: cancellationToken);
if (response.Hits.Count > 0)
{
return response.Hits.
Select(hit => new EntityChangeWithUsername
{
UserName = hit.Source.UserName,
EntityChange = hit.InnerHits.Any() ?
hit.InnerHits.First().Value.Documents<EntityChange>().FirstOrDefault()
: null
})
.ToList();
}
return new List<EntityChangeWithUsername>();
}
protected virtual List<Func<QueryContainerDescriptor<EntityChange>, QueryContainer>> BuildQueryDescriptor(
Guid? auditLogId = null,
DateTime? startTime = null,
DateTime? endTime = null,
EntityChangeType? changeType = null,
string entityId = null,
string entityTypeFullName = null)
{
var querys = new List<Func<QueryContainerDescriptor<EntityChange>, QueryContainer>>();
if (auditLogId.HasValue)
{
querys.Add(entity => entity.Term(q => q.Field(GetField(nameof(EntityChange.AuditLogId))).Value(auditLogId)));
}
if (startTime.HasValue)
{
querys.Add(entity => entity.DateRange(q => q.Field(GetField(nameof(EntityChange.ChangeTime))).GreaterThanOrEquals(startTime)));
}
if (endTime.HasValue)
{
querys.Add(entity => entity.DateRange(q => q.Field(GetField(nameof(EntityChange.ChangeTime))).LessThanOrEquals(endTime)));
}
if (changeType.HasValue)
{
querys.Add(entity => entity.Term(q => q.Field(GetField(nameof(EntityChange.ChangeType))).Value(changeType)));
}
if (!entityId.IsNullOrWhiteSpace())
{
querys.Add(entity => entity.Term(q => q.Field(GetField(nameof(EntityChange.EntityId))).Value(entityId)));
}
if (!entityTypeFullName.IsNullOrWhiteSpace())
{
querys.Add(entity => entity.Wildcard(q => q.Field(GetField(nameof(EntityChange.EntityTypeFullName))).Value($"*{entityTypeFullName}*")));
}
return querys;
}
protected virtual string CreateIndex()
{
return _indexNameNormalizer.NormalizeIndex("audit-log");
}
protected Func<FieldsDescriptor<EntityChange>, IPromise<Fields>> GetEntityChangeSources()
{
return field => field
.Field("EntityChanges.Id")
.Field("EntityChanges.AuditLogId")
.Field("EntityChanges.TenantId")
.Field("EntityChanges.ChangeTime")
.Field("EntityChanges.ChangeType")
.Field("EntityChanges.EntityTenantId")
.Field("EntityChanges.EntityId")
.Field("EntityChanges.EntityTypeFullName")
.Field("EntityChanges.PropertyChanges")
.Field("EntityChanges.ExtraProperties");
}
private readonly static IDictionary<string, string> _fieldMaps = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase)
{
{ "Id", "EntityChanges.Id.keyword" },
{ "AuditLogId", "EntityChanges.AuditLogId.keyword" },
{ "TenantId", "EntityChanges.TenantId.keyword" },
{ "EntityTenantId", "EntityChanges.EntityTenantId.keyword" },
{ "EntityId", "EntityChanges.EntityId.keyword" },
{ "EntityTypeFullName", "EntityChanges.EntityTypeFullName.keyword" },
{ "PropertyChanges", "EntityChanges.PropertyChanges" },
{ "ExtraProperties", "EntityChanges.ExtraProperties" },
{ "ChangeType", "EntityChanges.ChangeType" },
{ "ChangeTime", "EntityChanges.ChangeTime" },
};
protected virtual string GetField(string field)
{
if (_fieldMaps.TryGetValue(field, out var mapField))
{
return _elasticsearchOptions.FieldCamelCase ? mapField.ToCamelCase() : mapField.ToPascalCase();
}
return _elasticsearchOptions.FieldCamelCase ? field.ToCamelCase() : field.ToPascalCase();
}
}

268
modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/ElasticsearchSecurityLogManager.cs

@ -0,0 +1,268 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Nest;
using Sanhe.Abp.Elasticsearch;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Guids;
using Volo.Abp.SecurityLog;
namespace Sanhe.Abp.AuditLogging.Elasticsearch
{
[Dependency(ReplaceServices = true)]
public class ElasticsearchSecurityLogManager : ISecurityLogManager, ITransientDependency
{
private readonly AbpSecurityLogOptions _securityLogOptions;
private readonly AbpElasticsearchOptions _elasticsearchOptions;
private readonly IIndexNameNormalizer _indexNameNormalizer;
private readonly IGuidGenerator _guidGenerator;
private readonly IElasticsearchClientFactory _clientFactory;
public ILogger<ElasticsearchSecurityLogManager> Logger { protected get; set; }
public ElasticsearchSecurityLogManager(
IGuidGenerator guidGenerator,
IIndexNameNormalizer indexNameNormalizer,
IOptions<AbpSecurityLogOptions> securityLogOptions,
IOptions<AbpElasticsearchOptions> elasticsearchOptions,
IElasticsearchClientFactory clientFactory)
{
_guidGenerator = guidGenerator;
_clientFactory = clientFactory;
_indexNameNormalizer = indexNameNormalizer;
_securityLogOptions = securityLogOptions.Value;
_elasticsearchOptions = elasticsearchOptions.Value;
Logger = NullLogger<ElasticsearchSecurityLogManager>.Instance;
}
public virtual async Task SaveAsync(
SecurityLogInfo securityLogInfo,
CancellationToken cancellationToken = default)
{
// TODO: 框架不把这玩意儿放在 ISecurityLogManager?
if (!_securityLogOptions.IsEnabled)
{
return;
}
var client = _clientFactory.Create();
var securityLog = new SecurityLog(
_guidGenerator.Create(),
securityLogInfo);
await client.IndexAsync(
securityLog,
(x) => x.Index(CreateIndex())
.Id(securityLog.Id),
cancellationToken);
}
public virtual async Task<SecurityLog> GetAsync(
Guid id,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
var client = _clientFactory.Create();
var response = await client.GetAsync<SecurityLog>(
id,
dsl =>
dsl.Index(CreateIndex()),
cancellationToken);
return response.Source;
}
public virtual async Task DeleteAsync(Guid id, CancellationToken cancellationToken = default)
{
var client = _clientFactory.Create();
await client.DeleteAsync<SecurityLog>(
id,
dsl =>
dsl.Index(CreateIndex()),
cancellationToken);
}
public virtual async Task<List<SecurityLog>> GetListAsync(
string sorting = null,
int maxResultCount = 50,
int skipCount = 0,
DateTime? startTime = null,
DateTime? endTime = null,
string applicationName = null,
string identity = null,
string action = null,
Guid? userId = null,
string userName = null,
string clientId = null,
string clientIpAddress = null,
string correlationId = null,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
var client = _clientFactory.Create();
var sortOrder = !sorting.IsNullOrWhiteSpace() && sorting.EndsWith("asc", StringComparison.InvariantCultureIgnoreCase)
? SortOrder.Ascending : SortOrder.Descending;
sorting = !sorting.IsNullOrWhiteSpace()
? sorting.Split()[0]
: nameof(SecurityLog.CreationTime);
var querys = BuildQueryDescriptor(
startTime,
endTime,
applicationName,
identity,
action,
userId,
userName,
clientId,
clientIpAddress,
correlationId);
var response = await client.SearchAsync<SecurityLog>(dsl =>
dsl.Index(CreateIndex())
.Query(log => log.Bool(b => b.Must(querys.ToArray())))
.Source(log => log.IncludeAll())
.Sort(log => log.Field(GetField(sorting), sortOrder))
.From(skipCount)
.Size(maxResultCount),
cancellationToken);
return response.Documents.ToList();
}
public virtual async Task<long> GetCountAsync(
DateTime? startTime = null,
DateTime? endTime = null,
string applicationName = null,
string identity = null,
string action = null,
Guid? userId = null,
string userName = null,
string clientId = null,
string clientIpAddress = null,
string correlationId = null,
CancellationToken cancellationToken = default)
{
var client = _clientFactory.Create();
var querys = BuildQueryDescriptor(
startTime,
endTime,
applicationName,
identity,
action,
userId,
userName,
clientId,
clientIpAddress,
correlationId);
var response = await client.CountAsync<SecurityLog>(dsl =>
dsl.Index(CreateIndex())
.Query(log => log.Bool(b => b.Must(querys.ToArray()))),
cancellationToken);
return response.Count;
}
protected virtual List<Func<QueryContainerDescriptor<SecurityLog>, QueryContainer>> BuildQueryDescriptor(
DateTime? startTime = null,
DateTime? endTime = null,
string applicationName = null,
string identity = null,
string action = null,
Guid? userId = null,
string userName = null,
string clientId = null,
string clientIpAddress = null,
string correlationId = null)
{
var querys = new List<Func<QueryContainerDescriptor<SecurityLog>, QueryContainer>>();
if (startTime.HasValue)
{
querys.Add((log) => log.DateRange((q) => q.Field(GetField(nameof(SecurityLog.CreationTime))).GreaterThanOrEquals(startTime)));
}
if (endTime.HasValue)
{
querys.Add((log) => log.DateRange((q) => q.Field(GetField(nameof(SecurityLog.CreationTime))).LessThanOrEquals(endTime)));
}
if (!applicationName.IsNullOrWhiteSpace())
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(SecurityLog.ApplicationName))).Value(applicationName)));
}
if (!identity.IsNullOrWhiteSpace())
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(SecurityLog.Identity))).Value(identity)));
}
if (!action.IsNullOrWhiteSpace())
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(SecurityLog.Action))).Value(action)));
}
if (userId.HasValue)
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(SecurityLog.UserId))).Value(userId)));
}
if (!userName.IsNullOrWhiteSpace())
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(SecurityLog.UserName))).Value(userName)));
}
if (!clientId.IsNullOrWhiteSpace())
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(SecurityLog.ClientId))).Value(clientId)));
}
if (!clientIpAddress.IsNullOrWhiteSpace())
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(SecurityLog.ClientIpAddress))).Value(clientIpAddress)));
}
if (!correlationId.IsNullOrWhiteSpace())
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(SecurityLog.CorrelationId))).Value(correlationId)));
}
return querys;
}
protected virtual string CreateIndex()
{
return _indexNameNormalizer.NormalizeIndex("security-log");
}
private readonly static IDictionary<string, string> _fieldMaps = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase)
{
{ "Id", "Id.keyword" },
{ "ApplicationName", "ApplicationName.keyword" },
{ "UserId", "UserId.keyword" },
{ "UserName", "UserName.keyword" },
{ "TenantId", "TenantId.keyword" },
{ "TenantName", "TenantName.keyword" },
{ "Identity", "Identity.keyword" },
{ "Action", "Action.keyword" },
{ "BrowserInfo", "BrowserInfo.keyword" },
{ "ClientIpAddress", "ClientIpAddress.keyword" },
{ "ClientId", "ClientId.keyword" },
{ "CorrelationId", "CorrelationId.keyword" },
{ "CreationTime", "CreationTime" },
};
protected virtual string GetField(string field)
{
if (_fieldMaps.TryGetValue(field, out var mapField))
{
return _elasticsearchOptions.FieldCamelCase ? mapField.ToCamelCase() : mapField.ToPascalCase();
}
return _elasticsearchOptions.FieldCamelCase ? field.ToCamelCase() : field.ToPascalCase();
}
}
}

10
modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/IAuditLogInfoToAuditLogConverter.cs

@ -0,0 +1,10 @@
using System.Threading.Tasks;
using Volo.Abp.Auditing;
namespace Sanhe.Abp.AuditLogging.Elasticsearch
{
public interface IAuditLogInfoToAuditLogConverter
{
Task<AuditLog> ConvertAsync(AuditLogInfo auditLogInfo);
}
}

9
modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/IIndexInitializer.cs

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace Sanhe.Abp.AuditLogging.Elasticsearch
{
public interface IIndexInitializer
{
Task InitializeAsync();
}
}

7
modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/IIndexNameNormalizer.cs

@ -0,0 +1,7 @@
namespace Sanhe.Abp.AuditLogging.Elasticsearch
{
public interface IIndexNameNormalizer
{
string NormalizeIndex(string index);
}
}

107
modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/IndexInitializer.cs

@ -0,0 +1,107 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Nest;
using Sanhe.Abp.Elasticsearch;
using System;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;
namespace Sanhe.Abp.AuditLogging.Elasticsearch
{
public class IndexInitializer : IIndexInitializer, ISingletonDependency
{
private readonly AbpJsonOptions _jsonOptions;
private readonly AbpAuditLoggingElasticsearchOptions _elasticsearchOptions;
private readonly IIndexNameNormalizer _nameNormalizer;
private readonly IElasticsearchClientFactory _clientFactory;
public ILogger<IndexInitializer> Logger { protected get; set; }
public IndexInitializer(
IOptions<AbpJsonOptions> jsonOptions,
IOptions<AbpAuditLoggingElasticsearchOptions> elasticsearchOptions,
IIndexNameNormalizer nameNormalizer,
IElasticsearchClientFactory clientFactory)
{
_jsonOptions = jsonOptions.Value;
_elasticsearchOptions = elasticsearchOptions.Value;
_nameNormalizer = nameNormalizer;
_clientFactory = clientFactory;
Logger = NullLogger<IndexInitializer>.Instance;
}
public virtual async Task InitializeAsync()
{
var client = _clientFactory.Create();
var dateTimeFormat = !_jsonOptions.DefaultDateTimeFormat.IsNullOrWhiteSpace()
? $"{_jsonOptions.DefaultDateTimeFormat}||strict_date_optional_time||epoch_millis"
: "strict_date_optional_time||epoch_millis";
var indexState = new IndexState
{
Settings = _elasticsearchOptions.IndexSettings,
};
await InitlizeAuditLogIndex(client, indexState, dateTimeFormat);
await InitlizeSecurityLogIndex(client, indexState, dateTimeFormat);
}
protected virtual async Task InitlizeAuditLogIndex(IElasticClient client, IIndexState indexState, string dateTimeFormat)
{
var indexName = _nameNormalizer.NormalizeIndex("audit-log");
var indexExists = await client.Indices.ExistsAsync(indexName);
if (!indexExists.Exists)
{
var indexCreateResponse = await client.Indices.CreateAsync(
indexName,
dsl => dsl.InitializeUsing(indexState)
.Map<AuditLog>(map =>
map.AutoMap()
.Properties(mp =>
mp.Date(p => p.Name(n => n.ExecutionTime).Format(dateTimeFormat))
.Object<ExtraPropertyDictionary>(p => p.Name(n => n.ExtraProperties))
.Nested<EntityChange>(n =>
n.AutoMap()
.Name(nameof(AuditLog.EntityChanges))
.Properties(np =>
np.Object<ExtraPropertyDictionary>(p => p.Name(n => n.ExtraProperties))
.Date(p => p.Name(n => n.ChangeTime).Format(dateTimeFormat))
.Nested<EntityPropertyChange>(npn => npn.Name(nameof(EntityChange.PropertyChanges)))))
.Nested<AuditLogAction>(n => n.Name(nameof(AuditLog.Actions))
.AutoMap()
.Properties(np =>
np.Object<ExtraPropertyDictionary>(p => p.Name(n => n.ExtraProperties))
.Date(p => p.Name(n => n.ExecutionTime).Format(dateTimeFormat)))))));
if (!indexCreateResponse.IsValid)
{
Logger.LogWarning("Failed to initialize index and audit log may not be retrieved.");
Logger.LogWarning(indexCreateResponse.OriginalException.ToString());
}
}
}
protected virtual async Task InitlizeSecurityLogIndex(IElasticClient client, IIndexState indexState, string dateTimeFormat)
{
var indexName = _nameNormalizer.NormalizeIndex("security-log");
var indexExists = await client.Indices.ExistsAsync(indexName);
if (!indexExists.Exists)
{
var indexCreateResponse = await client.Indices.CreateAsync(
indexName,
dsl => dsl.InitializeUsing(indexState)
.Map<SecurityLog>(map =>
map.AutoMap()
.Properties(mp =>
mp.Object<ExtraPropertyDictionary>(p => p.Name(n => n.ExtraProperties))
.Date(p => p.Name(n => n.CreationTime).Format(dateTimeFormat)))));
if (!indexCreateResponse.IsValid)
{
Logger.LogWarning("Failed to initialize index and security log may not be retrieved.");
Logger.LogWarning(indexCreateResponse.OriginalException.ToString());
}
}
}
}
}

21
modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/IndexInitializerService.cs

@ -0,0 +1,21 @@
using Microsoft.Extensions.Hosting;
using System.Threading;
using System.Threading.Tasks;
namespace Sanhe.Abp.AuditLogging.Elasticsearch
{
public class IndexInitializerService : BackgroundService
{
private readonly IIndexInitializer _indexInitializer;
public IndexInitializerService(IIndexInitializer indexInitializer)
{
_indexInitializer = indexInitializer;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await _indexInitializer.InitializeAsync();
}
}
}

30
modules/auditing/Sanhe.Abp.AuditLogging.Elasticsearch/Sanhe/Abp/AuditLogging/Elasticsearch/IndexNameNormalizer.cs

@ -0,0 +1,30 @@
using Microsoft.Extensions.Options;
using System;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
namespace Sanhe.Abp.AuditLogging.Elasticsearch
{
public class IndexNameNormalizer : IIndexNameNormalizer, ISingletonDependency
{
private readonly ICurrentTenant _currentTenant;
private readonly AbpAuditLoggingElasticsearchOptions _options;
public IndexNameNormalizer(ICurrentTenant currentTenant, IOptions<AbpAuditLoggingElasticsearchOptions> options)
{
_currentTenant = currentTenant;
_options = options.Value;
}
public string NormalizeIndex(string index)
{
if (_currentTenant.IsAvailable)
{
return $"{_options.IndexPrefix}-{index}-{_currentTenant.Id:N}";
}
return _options.IndexPrefix.IsNullOrWhiteSpace()
? index
: $"{_options.IndexPrefix}-{index}";
}
}
}

3
modules/auditing/Sanhe.Abp.AuditLogging.EntityFrameworkCore/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

32
modules/auditing/Sanhe.Abp.AuditLogging.EntityFrameworkCore/README.md

@ -0,0 +1,32 @@
# LINGYUN.Abp.AuditLogging.EntityFrameworkCore
审计模块 EntityFrameworkCore 实现, 此模块仅作为桥梁, 具体实现交给abp官方模块
AuditLogManager 实现了 IAuditLogManager, 审计日志由Volo.Abp.AuditLogging模块管理
SecurityLogManager 实现了 ISecurityLogManager, 安全日志由Volo.Abp.Identity模块管理
## 模块引用
```csharp
[DependsOn(typeof(AbpAuditLoggingEntityFrameworkCoreModule))]
public class YouProjectModule : AbpModule
{
// other
}
```
## 配置项
请遵循 Volo.Abp.AuditLogging、Volo.Abp.Identity模块中的配置
## appsettings.json
```json
{
"ConnectionStrings": {
"AbpIdentity": "Server=127.0.0.1;Database=Identity;User Id=root;Password=*",
"AbpAuditLogging": "Server=127.0.0.1;Database=AuditLogging;User Id=root;Password=*",
}
}
```

21
modules/auditing/Sanhe.Abp.AuditLogging.EntityFrameworkCore/Sanhe.Abp.AuditLogging.EntityFrameworkCore.csproj

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.AutoMapper" Version="$(VoloAbpVersion)" />
<PackageReference Include="Volo.Abp.Identity.EntityFrameworkCore" Version="$(VoloAbpVersion)" />
<PackageReference Include="Volo.Abp.AuditLogging.EntityFrameworkCore" Version="$(VoloAbpVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Sanhe.Abp.AuditLogging\Sanhe.Abp.AuditLogging.csproj" />
</ItemGroup>
</Project>

25
modules/auditing/Sanhe.Abp.AuditLogging.EntityFrameworkCore/Sanhe/Abp/AuditLogging/EntityFrameworkCore/AbpAuditLoggingEntityFrameworkCoreModule.cs

@ -0,0 +1,25 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AutoMapper;
using Volo.Abp.Modularity;
namespace Sanhe.Abp.AuditLogging.EntityFrameworkCore
{
[DependsOn(
typeof(Volo.Abp.Identity.EntityFrameworkCore.AbpIdentityEntityFrameworkCoreModule),
typeof(Volo.Abp.AuditLogging.EntityFrameworkCore.AbpAuditLoggingEntityFrameworkCoreModule))]
[DependsOn(
typeof(AbpAuditLoggingModule),
typeof(AbpAutoMapperModule))]
public class AbpAuditLoggingEntityFrameworkCoreModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAutoMapperObjectMapper<AbpAuditLoggingEntityFrameworkCoreModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<AbpAuditingMapperProfile>(validate: true);
});
}
}
}

21
modules/auditing/Sanhe.Abp.AuditLogging.EntityFrameworkCore/Sanhe/Abp/AuditLogging/EntityFrameworkCore/AbpAuditingMapperProfile.cs

@ -0,0 +1,21 @@
using AutoMapper;
namespace Sanhe.Abp.AuditLogging.EntityFrameworkCore
{
public class AbpAuditingMapperProfile : Profile
{
public AbpAuditingMapperProfile()
{
CreateMap<Volo.Abp.AuditLogging.AuditLogAction, AuditLogAction>()
.MapExtraProperties();
CreateMap<Volo.Abp.AuditLogging.EntityPropertyChange, EntityPropertyChange>();
CreateMap<Volo.Abp.AuditLogging.EntityChange, EntityChange>()
.MapExtraProperties();
CreateMap<Volo.Abp.AuditLogging.AuditLog, AuditLog>()
.MapExtraProperties();
CreateMap<Volo.Abp.Identity.IdentitySecurityLog, SecurityLog>()
.MapExtraProperties();
}
}
}

179
modules/auditing/Sanhe.Abp.AuditLogging.EntityFrameworkCore/Sanhe/Abp/AuditLogging/EntityFrameworkCore/AuditLogManager.cs

@ -0,0 +1,179 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Auditing;
using Volo.Abp.AuditLogging;
using Volo.Abp.DependencyInjection;
using Volo.Abp.ObjectMapping;
using Volo.Abp.Uow;
namespace Sanhe.Abp.AuditLogging.EntityFrameworkCore
{
[Dependency(ReplaceServices = true)]
public class AuditLogManager : IAuditLogManager, ISingletonDependency
{
protected IObjectMapper ObjectMapper { get; }
protected IAuditLogRepository AuditLogRepository { get; }
protected IUnitOfWorkManager UnitOfWorkManager { get; }
protected AbpAuditingOptions Options { get; }
protected IAuditLogInfoToAuditLogConverter Converter { get; }
public ILogger<AuditLogManager> Logger { protected get; set; }
public AuditLogManager(
IObjectMapper objectMapper,
IAuditLogRepository auditLogRepository,
IUnitOfWorkManager unitOfWorkManager,
IOptions<AbpAuditingOptions> options,
IAuditLogInfoToAuditLogConverter converter)
{
ObjectMapper = objectMapper;
AuditLogRepository = auditLogRepository;
UnitOfWorkManager = unitOfWorkManager;
Converter = converter;
Options = options.Value;
Logger = NullLogger<AuditLogManager>.Instance;
}
public virtual async Task<long> GetCountAsync(
DateTime? startTime = null,
DateTime? endTime = null,
string httpMethod = null,
string url = null,
Guid? userId = null,
string userName = null,
string applicationName = null,
string correlationId = null,
string clientId = null,
string clientIpAddress = null,
int? maxExecutionDuration = null,
int? minExecutionDuration = null,
bool? hasException = null,
HttpStatusCode? httpStatusCode = null,
CancellationToken cancellationToken = default)
{
return await AuditLogRepository.GetCountAsync(
startTime,
endTime,
httpMethod,
url,
userId,
userName,
applicationName,
clientIpAddress,
correlationId,
maxExecutionDuration,
minExecutionDuration,
hasException,
httpStatusCode,
cancellationToken);
}
public virtual async Task<List<AuditLog>> GetListAsync(
string sorting = null,
int maxResultCount = 50,
int skipCount = 0,
DateTime? startTime = null,
DateTime? endTime = null,
string httpMethod = null,
string url = null,
Guid? userId = null,
string userName = null,
string applicationName = null,
string correlationId = null,
string clientId = null,
string clientIpAddress = null,
int? maxExecutionDuration = null,
int? minExecutionDuration = null,
bool? hasException = null,
HttpStatusCode? httpStatusCode = null,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
var auditLogs = await AuditLogRepository.GetListAsync(
sorting,
maxResultCount,
skipCount,
startTime,
endTime,
httpMethod,
url,
userId,
userName,
applicationName,
clientIpAddress,
correlationId,
maxExecutionDuration,
minExecutionDuration,
hasException,
httpStatusCode,
includeDetails,
cancellationToken);
return ObjectMapper.Map<List<Volo.Abp.AuditLogging.AuditLog>, List<AuditLog>>(auditLogs);
}
public virtual async Task<AuditLog> GetAsync(
Guid id,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
var auditLog = await AuditLogRepository.GetAsync(id, includeDetails, cancellationToken);
return ObjectMapper.Map<Volo.Abp.AuditLogging.AuditLog, AuditLog>(auditLog);
}
public virtual async Task DeleteAsync(Guid id, CancellationToken cancellationToken = default)
{
using (var uow = UnitOfWorkManager.Begin(true))
{
await AuditLogRepository.DeleteAsync(id);
await uow.CompleteAsync();
}
}
public virtual async Task<string> SaveAsync(
AuditLogInfo auditInfo,
CancellationToken cancellationToken = default)
{
if (!Options.HideErrors)
{
return await SaveLogAsync(auditInfo, cancellationToken);
}
try
{
return await SaveLogAsync(auditInfo, cancellationToken);
}
catch (Exception ex)
{
Logger.LogWarning("Could not save the audit log object: " + Environment.NewLine + auditInfo.ToString());
Logger.LogException(ex, LogLevel.Error);
}
return "";
}
protected virtual async Task<string> SaveLogAsync(
AuditLogInfo auditInfo,
CancellationToken cancellationToken = default)
{
using (var uow = UnitOfWorkManager.Begin(true))
{
var auditLog = await AuditLogRepository.InsertAsync(
await Converter.ConvertAsync(auditInfo),
false,
cancellationToken);
await uow.CompleteAsync();
return auditLog.Id.ToString();
}
}
}
}

144
modules/auditing/Sanhe.Abp.AuditLogging.EntityFrameworkCore/Sanhe/Abp/AuditLogging/EntityFrameworkCore/SecurityLogManager.cs

@ -0,0 +1,144 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Guids;
using Volo.Abp.Identity;
using Volo.Abp.ObjectMapping;
using Volo.Abp.SecurityLog;
using Volo.Abp.Uow;
namespace Sanhe.Abp.AuditLogging.EntityFrameworkCore
{
[Dependency(ReplaceServices = true)]
public class SecurityLogManager : ISecurityLogManager, ISingletonDependency
{
public ILogger<SecurityLogManager> Logger { get; set; }
protected IObjectMapper ObjectMapper { get; }
protected AbpSecurityLogOptions SecurityLogOptions { get; }
protected IIdentitySecurityLogRepository IdentitySecurityLogRepository { get; }
protected IGuidGenerator GuidGenerator { get; }
protected IUnitOfWorkManager UnitOfWorkManager { get; }
public SecurityLogManager(
IObjectMapper objectMapper,
ILogger<SecurityLogManager> logger,
IOptions<AbpSecurityLogOptions> securityLogOptions,
IIdentitySecurityLogRepository identitySecurityLogRepository,
IGuidGenerator guidGenerator,
IUnitOfWorkManager unitOfWorkManager)
{
Logger = logger;
ObjectMapper = objectMapper;
SecurityLogOptions = securityLogOptions.Value;
IdentitySecurityLogRepository = identitySecurityLogRepository;
GuidGenerator = guidGenerator;
UnitOfWorkManager = unitOfWorkManager;
}
public virtual async Task SaveAsync(
SecurityLogInfo securityLogInfo,
CancellationToken cancellationToken = default)
{
if (!SecurityLogOptions.IsEnabled)
{
return;
}
using (var uow = UnitOfWorkManager.Begin(requiresNew: true))
{
await IdentitySecurityLogRepository.InsertAsync(
new IdentitySecurityLog(GuidGenerator, securityLogInfo),
false,
cancellationToken);
await uow.CompleteAsync();
}
}
public virtual async Task<SecurityLog> GetAsync(
Guid id,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
var securityLog = await IdentitySecurityLogRepository.GetAsync(id, includeDetails, cancellationToken);
return ObjectMapper.Map<IdentitySecurityLog, SecurityLog>(securityLog);
}
public virtual async Task DeleteAsync(Guid id, CancellationToken cancellationToken = default)
{
using (var uow = UnitOfWorkManager.Begin(true))
{
await IdentitySecurityLogRepository.DeleteAsync(id);
await uow.CompleteAsync();
}
}
public virtual async Task<List<SecurityLog>> GetListAsync(
string sorting = null,
int maxResultCount = 50,
int skipCount = 0,
DateTime? startTime = null,
DateTime? endTime = null,
string applicationName = null,
string identity = null,
string action = null,
Guid? userId = null,
string userName = null,
string clientId = null,
string clientIpAddress = null,
string correlationId = null,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
var securityLogs = await IdentitySecurityLogRepository.GetListAsync(
sorting,
maxResultCount,
skipCount,
startTime,
endTime,
applicationName,
identity,
action,
userId,
userName,
clientId,
correlationId,
includeDetails,
cancellationToken);
return ObjectMapper.Map<List<IdentitySecurityLog>, List<SecurityLog>>(securityLogs);
}
public virtual async Task<long> GetCountAsync(
DateTime? startTime = null,
DateTime? endTime = null,
string applicationName = null,
string identity = null,
string action = null,
Guid? userId = null,
string userName = null,
string clientId = null,
string clientIpAddress = null,
string correlationId = null,
CancellationToken cancellationToken = default)
{
return await IdentitySecurityLogRepository.GetCountAsync(
startTime,
endTime,
applicationName,
identity,
action,
userId,
userName,
clientId,
correlationId,
cancellationToken);
}
}
}

3
modules/auditing/Sanhe.Abp.AuditLogging/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

17
modules/auditing/Sanhe.Abp.AuditLogging/Sanhe.Abp.AuditLogging.csproj

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Auditing" Version="$(VoloAbpVersion)" />
<PackageReference Include="Volo.Abp.Guids" Version="$(VoloAbpVersion)" />
<PackageReference Include="Volo.Abp.ExceptionHandling" Version="$(VoloAbpVersion)" />
</ItemGroup>
</Project>

15
modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/AbpAuditLoggingModule.cs

@ -0,0 +1,15 @@
using Volo.Abp.Auditing;
using Volo.Abp.ExceptionHandling;
using Volo.Abp.Guids;
using Volo.Abp.Modularity;
namespace Sanhe.Abp.AuditLogging
{
[DependsOn(
typeof(AbpAuditingModule),
typeof(AbpGuidsModule),
typeof(AbpExceptionHandlingModule))]
public class AbpAuditLoggingModule : AbpModule
{
}
}

115
modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/AuditLog.cs

@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using Volo.Abp.Auditing;
using Volo.Abp.Data;
namespace Sanhe.Abp.AuditLogging
{
[DisableAuditing]
public class AuditLog : IHasExtraProperties
{
public Guid Id { get; set; }
public string ApplicationName { get; set; }
public Guid? UserId { get; set; }
public string UserName { get; set; }
public Guid? TenantId { get; set; }
public string TenantName { get; set; }
public Guid? ImpersonatorUserId { get; set; }
public Guid? ImpersonatorTenantId { get; set; }
public DateTime ExecutionTime { get; set; }
public int ExecutionDuration { get; set; }
public string ClientIpAddress { get; set; }
public string ClientName { get; set; }
public string ClientId { get; set; }
public string CorrelationId { get; set; }
public string BrowserInfo { get; set; }
public string HttpMethod { get; set; }
public string Url { get; set; }
public string Exceptions { get; set; }
public string Comments { get; set; }
public int? HttpStatusCode { get; set; }
public List<EntityChange> EntityChanges { get; set; }
public List<AuditLogAction> Actions { get; set; }
public ExtraPropertyDictionary ExtraProperties { get; set; }
public AuditLog()
{
Actions = new List<AuditLogAction>();
EntityChanges = new List<EntityChange>();
ExtraProperties = new ExtraPropertyDictionary();
}
public AuditLog(
Guid id,
string applicationName,
Guid? tenantId,
string tenantName,
Guid? userId,
string userName,
DateTime executionTime,
int executionDuration,
string clientIpAddress,
string clientName,
string clientId,
string correlationId,
string browserInfo,
string httpMethod,
string url,
int? httpStatusCode,
Guid? impersonatorUserId,
Guid? impersonatorTenantId,
ExtraPropertyDictionary extraPropertyDictionary,
List<EntityChange> entityChanges,
List<AuditLogAction> actions,
string exceptions,
string comments)
{
Id = id;
ApplicationName = applicationName;
TenantId = tenantId;
TenantName = tenantName;
UserId = userId;
UserName = userName;
ExecutionTime = executionTime;
ExecutionDuration = executionDuration;
ClientIpAddress = clientIpAddress;
ClientName = clientName;
ClientId = clientId;
CorrelationId = correlationId;
BrowserInfo = browserInfo;
HttpMethod = httpMethod;
Url = url;
HttpStatusCode = httpStatusCode;
ImpersonatorUserId = impersonatorUserId;
ImpersonatorTenantId = impersonatorTenantId;
ExtraProperties = extraPropertyDictionary;
EntityChanges = entityChanges;
Actions = actions;
Exceptions = exceptions;
Comments = comments;
}
}
}

47
modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/AuditLogAction.cs

@ -0,0 +1,47 @@
using System;
using Volo.Abp.Auditing;
using Volo.Abp.Data;
namespace Sanhe.Abp.AuditLogging
{
[DisableAuditing]
public class AuditLogAction : IHasExtraProperties
{
public Guid Id { get; set; }
public Guid? TenantId { get; set; }
public Guid AuditLogId { get; set; }
public string ServiceName { get; set; }
public string MethodName { get; set; }
public string Parameters { get; set; }
public DateTime ExecutionTime { get; set; }
public int ExecutionDuration { get; set; }
public ExtraPropertyDictionary ExtraProperties { get; set; }
public AuditLogAction()
{
ExtraProperties = new ExtraPropertyDictionary();
}
public AuditLogAction(Guid id, Guid auditLogId, AuditLogActionInfo actionInfo, Guid? tenantId = null)
{
Id = id;
TenantId = tenantId;
AuditLogId = auditLogId;
ExecutionTime = actionInfo.ExecutionTime;
ExecutionDuration = actionInfo.ExecutionDuration;
ExtraProperties = new ExtraPropertyDictionary(actionInfo.ExtraProperties);
ServiceName = actionInfo.ServiceName;
MethodName = actionInfo.MethodName;
Parameters = actionInfo.Parameters.Length > 2000 ? "" : actionInfo.Parameters;
}
}
}

23
modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/AuditingStore.cs

@ -0,0 +1,23 @@
using System.Threading.Tasks;
using Volo.Abp.Auditing;
using Volo.Abp.DependencyInjection;
namespace Sanhe.Abp.AuditLogging
{
[Dependency(ReplaceServices = true)]
public class AuditingStore : IAuditingStore, ITransientDependency
{
private readonly IAuditLogManager _manager;
public AuditingStore(
IAuditLogManager manager)
{
_manager = manager;
}
public virtual async Task SaveAsync(AuditLogInfo auditInfo)
{
await _manager.SaveAsync(auditInfo);
}
}
}

96
modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/DefaultAuditLogManager.cs

@ -0,0 +1,96 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Auditing;
using Volo.Abp.DependencyInjection;
namespace Sanhe.Abp.AuditLogging
{
[Dependency(TryRegister = true)]
public class DefaultAuditLogManager : IAuditLogManager, ISingletonDependency
{
public ILogger<DefaultAuditLogManager> Logger { protected get; set; }
public DefaultAuditLogManager()
{
Logger = NullLogger<DefaultAuditLogManager>.Instance;
}
public virtual Task<long> GetCountAsync(
DateTime? startTime = null,
DateTime? endTime = null,
string httpMethod = null,
string url = null,
Guid? userId = null,
string userName = null,
string applicationName = null,
string correlationId = null,
string clientId = null,
string clientIpAddress = null,
int? maxExecutionDuration = null,
int? minExecutionDuration = null,
bool? hasException = null,
HttpStatusCode? httpStatusCode = null,
CancellationToken cancellationToken = default)
{
Logger.LogDebug("No audit log manager is available!");
return Task.FromResult(0L);
}
public virtual Task<List<AuditLog>> GetListAsync(
string sorting = null,
int maxResultCount = 50,
int skipCount = 0,
DateTime? startTime = null,
DateTime? endTime = null,
string httpMethod = null,
string url = null,
Guid? userId = null,
string userName = null,
string applicationName = null,
string correlationId = null,
string clientId = null,
string clientIpAddress = null,
int? maxExecutionDuration = null,
int? minExecutionDuration = null,
bool? hasException = null,
HttpStatusCode? httpStatusCode = null,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
Logger.LogDebug("No audit log manager is available!");
return Task.FromResult(new List<AuditLog>());
}
public virtual Task<string> SaveAsync(
AuditLogInfo auditInfo,
CancellationToken cancellationToken = default)
{
Logger.LogDebug("No audit log manager is available and is written to the local log by default");
Logger.LogInformation(auditInfo.ToString());
return Task.FromResult("");
}
public virtual Task<AuditLog> GetAsync(
Guid id,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
Logger.LogDebug("No audit log manager is available!");
AuditLog auditLog = null;
return Task.FromResult(auditLog);
}
public virtual Task DeleteAsync(Guid id, CancellationToken cancellationToken = default)
{
Logger.LogDebug("No audit log manager is available!");
return Task.CompletedTask;
}
}
}

40
modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/DefaultEntityChangeStore.cs

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Auditing;
using Volo.Abp.DependencyInjection;
namespace Sanhe.Abp.AuditLogging
{
[Dependency(TryRegister = true)]
public class DefaultEntityChangeStore : IEntityChangeStore, ISingletonDependency
{
public Task<EntityChange> GetAsync(Guid entityChangeId, CancellationToken cancellationToken = default)
{
EntityChange entityChange = null;
return Task.FromResult(entityChange);
}
public Task<long> GetCountAsync(Guid? auditLogId = null, DateTime? startTime = null, DateTime? endTime = null, EntityChangeType? changeType = null, string entityId = null, string entityTypeFullName = null, CancellationToken cancellationToken = default)
{
return Task.FromResult(0L);
}
public Task<List<EntityChange>> GetListAsync(string sorting = null, int maxResultCount = 50, int skipCount = 0, Guid? auditLogId = null, DateTime? startTime = null, DateTime? endTime = null, EntityChangeType? changeType = null, string entityId = null, string entityTypeFullName = null, bool includeDetails = false, CancellationToken cancellationToken = default)
{
return Task.FromResult(new List<EntityChange>());
}
public Task<EntityChangeWithUsername> GetWithUsernameAsync(Guid entityChangeId, CancellationToken cancellationToken = default)
{
EntityChangeWithUsername entityChange = null;
return Task.FromResult(entityChange);
}
public Task<List<EntityChangeWithUsername>> GetWithUsernameAsync(string entityId, string entityTypeFullName, CancellationToken cancellationToken = default)
{
return Task.FromResult(new List<EntityChangeWithUsername>());
}
}
}

87
modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/DefaultSecurityLogManager.cs

@ -0,0 +1,87 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.SecurityLog;
namespace Sanhe.Abp.AuditLogging
{
[Dependency(TryRegister = true)]
public class DefaultSecurityLogManager : ISecurityLogManager, ISingletonDependency
{
public ILogger<DefaultSecurityLogManager> Logger { protected get; set; }
public DefaultSecurityLogManager()
{
Logger = NullLogger<DefaultSecurityLogManager>.Instance;
}
public Task<long> GetCountAsync(
DateTime? startTime = null,
DateTime? endTime = null,
string applicationName = null,
string identity = null,
string action = null,
Guid? userId = null,
string userName = null,
string clientId = null,
string clientIpAddress = null,
string correlationId = null,
CancellationToken cancellationToken = default)
{
Logger.LogDebug("No security log manager is available!");
return Task.FromResult(0L);
}
public Task<List<SecurityLog>> GetListAsync(
string sorting = null,
int maxResultCount = 50,
int skipCount = 0,
DateTime? startTime = null,
DateTime? endTime = null,
string applicationName = null,
string identity = null,
string action = null,
Guid? userId = null,
string userName = null,
string clientId = null,
string clientIpAddress = null,
string correlationId = null,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
Logger.LogDebug("No security log manager is available!");
return Task.FromResult(new List<SecurityLog>());
}
public Task SaveAsync(
SecurityLogInfo securityLogInfo,
CancellationToken cancellationToken = default)
{
Logger.LogDebug("No security log manager is available and is written to the local log by default");
Logger.LogInformation(securityLogInfo.ToString());
return Task.CompletedTask;
}
public virtual Task<SecurityLog> GetAsync(
Guid id,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
Logger.LogDebug("No security log manager is available!");
SecurityLog securityLog = null;
return Task.FromResult(securityLog);
}
public virtual Task DeleteAsync(Guid id, CancellationToken cancellationToken = default)
{
Logger.LogDebug("No security log manager is available!");
return Task.CompletedTask;
}
}
}

69
modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/EntityChange.cs

@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Volo.Abp.Auditing;
using Volo.Abp.Data;
using Volo.Abp.Guids;
namespace Sanhe.Abp.AuditLogging
{
[DisableAuditing]
public class EntityChange : IHasExtraProperties
{
public Guid Id { get; set; }
public Guid AuditLogId { get; set; }
public Guid? TenantId { get; set; }
public DateTime ChangeTime { get; set; }
public EntityChangeType ChangeType { get; set; }
public Guid? EntityTenantId { get; set; }
public string EntityId { get; set; }
public string EntityTypeFullName { get; set; }
public List<EntityPropertyChange> PropertyChanges { get; set; }
public ExtraPropertyDictionary ExtraProperties { get; set; }
public EntityChange()
{
PropertyChanges = new List<EntityPropertyChange>();
ExtraProperties = new ExtraPropertyDictionary();
}
public EntityChange(
IGuidGenerator guidGenerator,
Guid auditLogId,
EntityChangeInfo entityChangeInfo,
Guid? tenantId = null)
{
Id = guidGenerator.Create();
AuditLogId = auditLogId;
TenantId = tenantId;
ChangeTime = entityChangeInfo.ChangeTime;
ChangeType = entityChangeInfo.ChangeType;
EntityId = entityChangeInfo.EntityId;
EntityTypeFullName = entityChangeInfo.EntityTypeFullName;
PropertyChanges = entityChangeInfo
.PropertyChanges?
.Select(p => new EntityPropertyChange(guidGenerator, Id, p, tenantId))
.ToList()
?? new List<EntityPropertyChange>();
ExtraProperties = new ExtraPropertyDictionary();
if (entityChangeInfo.ExtraProperties != null)
{
foreach (var pair in entityChangeInfo.ExtraProperties)
{
ExtraProperties.Add(pair.Key, pair.Value);
}
}
}
}
}

9
modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/EntityChangeWithUsername.cs

@ -0,0 +1,9 @@
namespace Sanhe.Abp.AuditLogging
{
public class EntityChangeWithUsername
{
public EntityChange EntityChange { get; set; }
public string UserName { get; set; }
}
}

43
modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/EntityPropertyChange.cs

@ -0,0 +1,43 @@
using System;
using Volo.Abp.Auditing;
using Volo.Abp.Guids;
namespace Sanhe.Abp.AuditLogging
{
[DisableAuditing]
public class EntityPropertyChange
{
public Guid Id { get; set; }
public Guid? TenantId { get; set; }
public Guid EntityChangeId { get; set; }
public string NewValue { get; set; }
public string OriginalValue { get; set; }
public string PropertyName { get; set; }
public string PropertyTypeFullName { get; set; }
public EntityPropertyChange()
{
}
public EntityPropertyChange(
IGuidGenerator guidGenerator,
Guid entityChangeId,
EntityPropertyChangeInfo entityChangeInfo,
Guid? tenantId = null)
{
Id = guidGenerator.Create();
TenantId = tenantId;
EntityChangeId = entityChangeId;
NewValue = entityChangeInfo.NewValue;
OriginalValue = entityChangeInfo.OriginalValue;
PropertyName = entityChangeInfo.PropertyName;
PropertyTypeFullName = entityChangeInfo.PropertyTypeFullName;
}
}
}

64
modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/IAuditLogManager.cs

@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Auditing;
namespace Sanhe.Abp.AuditLogging
{
public interface IAuditLogManager
{
Task<AuditLog> GetAsync(
Guid id,
bool includeDetails = false,
CancellationToken cancellationToken = default);
Task DeleteAsync(
Guid id,
CancellationToken cancellationToken = default);
Task<string> SaveAsync(
AuditLogInfo auditInfo,
CancellationToken cancellationToken = default);
Task<long> GetCountAsync(
DateTime? startTime = null,
DateTime? endTime = null,
string httpMethod = null,
string url = null,
Guid? userId = null,
string userName = null,
string applicationName = null,
string correlationId = null,
string clientId = null,
string clientIpAddress = null,
int? maxExecutionDuration = null,
int? minExecutionDuration = null,
bool? hasException = null,
HttpStatusCode? httpStatusCode = null,
CancellationToken cancellationToken = default);
Task<List<AuditLog>> GetListAsync(
string sorting = null,
int maxResultCount = 50,
int skipCount = 0,
DateTime? startTime = null,
DateTime? endTime = null,
string httpMethod = null,
string url = null,
Guid? userId = null,
string userName = null,
string applicationName = null,
string correlationId = null,
string clientId = null,
string clientIpAddress = null,
int? maxExecutionDuration = null,
int? minExecutionDuration = null,
bool? hasException = null,
HttpStatusCode? httpStatusCode = null,
bool includeDetails = false,
CancellationToken cancellationToken = default);
}
}

46
modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/IEntityChangeStore.cs

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Auditing;
namespace Sanhe.Abp.AuditLogging
{
public interface IEntityChangeStore
{
Task<EntityChange> GetAsync(
Guid entityChangeId,
CancellationToken cancellationToken = default);
Task<long> GetCountAsync(
Guid? auditLogId = null,
DateTime? startTime = null,
DateTime? endTime = null,
EntityChangeType? changeType = null,
string entityId = null,
string entityTypeFullName = null,
CancellationToken cancellationToken = default);
Task<List<EntityChange>> GetListAsync(
string sorting = null,
int maxResultCount = 50,
int skipCount = 0,
Guid? auditLogId = null,
DateTime? startTime = null,
DateTime? endTime = null,
EntityChangeType? changeType = null,
string entityId = null,
string entityTypeFullName = null,
bool includeDetails = false,
CancellationToken cancellationToken = default);
Task<EntityChangeWithUsername> GetWithUsernameAsync(
Guid entityChangeId,
CancellationToken cancellationToken = default);
Task<List<EntityChangeWithUsername>> GetWithUsernameAsync(
string entityId,
string entityTypeFullName,
CancellationToken cancellationToken = default);
}
}

56
modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/ISecurityLogManager.cs

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.SecurityLog;
namespace Sanhe.Abp.AuditLogging
{
public interface ISecurityLogManager
{
Task<SecurityLog> GetAsync(
Guid id,
bool includeDetails = false,
CancellationToken cancellationToken = default);
Task DeleteAsync(
Guid id,
CancellationToken cancellationToken = default);
Task SaveAsync(
SecurityLogInfo securityLogInfo,
CancellationToken cancellationToken = default);
Task<List<SecurityLog>> GetListAsync(
string sorting = null,
int maxResultCount = 50,
int skipCount = 0,
DateTime? startTime = null,
DateTime? endTime = null,
string applicationName = null,
string identity = null,
string action = null,
Guid? userId = null,
string userName = null,
string clientId = null,
string clientIpAddress = null,
string correlationId = null,
bool includeDetails = false,
CancellationToken cancellationToken = default);
Task<long> GetCountAsync(
DateTime? startTime = null,
DateTime? endTime = null,
string applicationName = null,
string identity = null,
string action = null,
Guid? userId = null,
string userName = null,
string clientId = null,
string clientIpAddress = null,
string correlationId = null,
CancellationToken cancellationToken = default);
}
}

72
modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/SecurityLog.cs

@ -0,0 +1,72 @@
using System;
using Volo.Abp.Data;
using Volo.Abp.SecurityLog;
namespace Sanhe.Abp.AuditLogging
{
public class SecurityLog : IHasExtraProperties
{
public Guid Id { get; set; }
public Guid? TenantId { get; set; }
public string ApplicationName { get; set; }
public string Identity { get; set; }
public string Action { get; set; }
public Guid? UserId { get; set; }
public string UserName { get; set; }
public string TenantName { get; set; }
public string ClientId { get; set; }
public string CorrelationId { get; set; }
public string ClientIpAddress { get; set; }
public string BrowserInfo { get; set; }
public DateTime CreationTime { get; set; }
public ExtraPropertyDictionary ExtraProperties { get; set; }
public SecurityLog()
{
ExtraProperties = new ExtraPropertyDictionary();
}
public SecurityLog(Guid id, SecurityLogInfo securityLogInfo)
{
Id = id;
TenantId = securityLogInfo.TenantId;
TenantName = securityLogInfo.TenantName;
ApplicationName = securityLogInfo.ApplicationName;
Identity = securityLogInfo.Identity;
Action = securityLogInfo.Action;
UserId = securityLogInfo.UserId;
UserName = securityLogInfo.UserName;
CreationTime = securityLogInfo.CreationTime;
ClientIpAddress = securityLogInfo.ClientIpAddress;
ClientId = securityLogInfo.ClientId;
CorrelationId = securityLogInfo.CorrelationId;
BrowserInfo = securityLogInfo.BrowserInfo;
ExtraProperties = new ExtraPropertyDictionary();
if (securityLogInfo.ExtraProperties != null)
{
foreach (var pair in securityLogInfo.ExtraProperties)
{
ExtraProperties.Add(pair.Key, pair.Value);
}
}
}
}
}

23
modules/auditing/Sanhe.Abp.AuditLogging/Sanhe/Abp/AuditLogging/SecurityLogStore.cs

@ -0,0 +1,23 @@
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.SecurityLog;
namespace Sanhe.Abp.AuditLogging
{
[Dependency(ReplaceServices = true)]
public class SecurityLogStore : ISecurityLogStore, ITransientDependency
{
private readonly ISecurityLogManager _manager;
public SecurityLogStore(
ISecurityLogManager manager)
{
_manager = manager;
}
public virtual async Task SaveAsync(SecurityLogInfo securityLogInfo)
{
await _manager.SaveAsync(securityLogInfo);
}
}
}

3
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

28
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe.Abp.Auditing.Application.Contracts.csproj

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<None Remove="Sanhe\Abp\Auditing\Localization\Resources\en.json" />
<None Remove="Sanhe\Abp\Auditing\Localization\Resources\zh-Hans.json" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Sanhe\Abp\Auditing\Localization\Resources\en.json" />
<EmbeddedResource Include="Sanhe\Abp\Auditing\Localization\Resources\zh-Hans.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Features" Version="$(VoloAbpVersion)" />
<PackageReference Include="Volo.Abp.Authorization" Version="$(VoloAbpVersion)" />
<PackageReference Include="Volo.Abp.AuditLogging.Domain.Shared" Version="$(VoloAbpVersion)" />
<PackageReference Include="Volo.Abp.Ddd.Application.Contracts" Version="$(VoloAbpVersion)" />
</ItemGroup>
</Project>

34
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AbpAuditingApplicationContractsModule.cs

@ -0,0 +1,34 @@
using Volo.Abp.Application;
using Volo.Abp.AuditLogging;
using Volo.Abp.AuditLogging.Localization;
using Volo.Abp.Authorization;
using Volo.Abp.Features;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
namespace Sanhe.Abp.Auditing
{
[DependsOn(
typeof(AbpFeaturesModule),
typeof(AbpAuthorizationModule),
typeof(AbpAuditLoggingDomainSharedModule),
typeof(AbpDddApplicationContractsModule))]
public class AbpAuditingApplicationContractsModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpAuditingApplicationContractsModule>();
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Get<AuditLoggingResource>()
.AddVirtualJson("/Sanhe/Abp/Auditing/Localization/Resources");
});
}
}
}

18
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AuditLogs/AuditLogActionDto.cs

@ -0,0 +1,18 @@
using System;
using Volo.Abp.Application.Dtos;
namespace Sanhe.Abp.Auditing.AuditLogs
{
public class AuditLogActionDto : ExtensibleEntityDto<Guid>
{
public string ServiceName { get; set; }
public string MethodName { get; set; }
public string Parameters { get; set; }
public DateTime ExecutionTime { get; set; }
public int ExecutionDuration { get; set; }
}
}

55
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AuditLogs/AuditLogDto.cs

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using Volo.Abp.Application.Dtos;
namespace Sanhe.Abp.Auditing.AuditLogs
{
public class AuditLogDto : ExtensibleEntityDto<Guid>
{
public string ApplicationName { get; set; }
public Guid? UserId { get; set; }
public string UserName { get; set; }
public Guid? TenantId { get; set; }
public string TenantName { get; set; }
public Guid? ImpersonatorUserId { get; set; }
public Guid? ImpersonatorTenantId { get; set; }
public DateTime ExecutionTime { get; set; }
public int ExecutionDuration { get; set; }
public string ClientIpAddress { get; set; }
public string ClientName { get; set; }
public string ClientId { get; set; }
public string CorrelationId { get; set; }
public string BrowserInfo { get; set; }
public string HttpMethod { get; set; }
public string Url { get; set; }
public string Exceptions { get; set; }
public string Comments { get; set; }
public int? HttpStatusCode { get; set; }
public List<EntityChangeDto> EntityChanges { get; set; }
public List<AuditLogActionDto> Actions { get; set; }
public AuditLogDto()
{
EntityChanges = new List<EntityChangeDto>();
Actions = new List<AuditLogActionDto>();
}
}
}

24
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AuditLogs/AuditLogGetByPagedDto.cs

@ -0,0 +1,24 @@
using System;
using System.Net;
using Volo.Abp.Application.Dtos;
namespace Sanhe.Abp.Auditing.AuditLogs
{
public class AuditLogGetByPagedDto : PagedAndSortedResultRequestDto
{
public DateTime? StartTime { get; set; }
public DateTime? EndTime { get; set; }
public string HttpMethod { get; set; }
public string Url { get; set; }
public Guid? UserId { get; set; }
public string UserName { get; set; }
public string ApplicationName { get; set; }
public string CorrelationId { get; set; }
public string ClientId { get; set; }
public string ClientIpAddress { get; set; }
public int? MaxExecutionDuration { get; set; }
public int? MinExecutionDuration { get; set; }
public bool? HasException { get; set; }
public HttpStatusCode? HttpStatusCode { get; set; }
}
}

27
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AuditLogs/EntityChangeDto.cs

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Auditing;
namespace Sanhe.Abp.Auditing.AuditLogs
{
public class EntityChangeDto : ExtensibleEntityDto<Guid>
{
public DateTime ChangeTime { get; set; }
public EntityChangeType ChangeType { get; set; }
public Guid? EntityTenantId { get; set; }
public string EntityId { get; set; }
public string EntityTypeFullName { get; set; }
public List<EntityPropertyChangeDto> PropertyChanges { get; set; }
public EntityChangeDto()
{
PropertyChanges = new List<EntityPropertyChangeDto>();
}
}
}

15
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AuditLogs/EntityChangeGetByPagedDto.cs

@ -0,0 +1,15 @@
using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Auditing;
namespace Sanhe.Abp.Auditing.AuditLogs;
public class EntityChangeGetByPagedDto : PagedAndSortedResultRequestDto
{
public Guid? AuditLogId { get; set; }
public DateTime? StartTime { get; set; }
public DateTime? EndTime { get; set; }
public EntityChangeType? ChangeType { get; set; }
public string EntityId { get; set; }
public string EntityTypeFullName { get; set; }
}

7
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AuditLogs/EntityChangeGetWithUsernameDto.cs

@ -0,0 +1,7 @@
namespace Sanhe.Abp.Auditing.AuditLogs;
public class EntityChangeGetWithUsernameDto
{
public string EntityId { get; set; }
public string EntityTypeFullName { get; set; }
}

8
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AuditLogs/EntityChangeWithUsernameDto.cs

@ -0,0 +1,8 @@
namespace Sanhe.Abp.Auditing.AuditLogs;
public class EntityChangeWithUsernameDto
{
public EntityChangeDto EntityChange { get; set; }
public string UserName { get; set; }
}

16
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AuditLogs/EntityPropertyChangeDto.cs

@ -0,0 +1,16 @@
using System;
using Volo.Abp.Application.Dtos;
namespace Sanhe.Abp.Auditing.AuditLogs
{
public class EntityPropertyChangeDto : EntityDto<Guid>
{
public string NewValue { get; set; }
public string OriginalValue { get; set; }
public string PropertyName { get; set; }
public string PropertyTypeFullName { get; set; }
}
}

16
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AuditLogs/IAuditLogAppService.cs

@ -0,0 +1,16 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Sanhe.Abp.Auditing.AuditLogs
{
public interface IAuditLogAppService : IApplicationService
{
Task<PagedResultDto<AuditLogDto>> GetListAsync(AuditLogGetByPagedDto input);
Task<AuditLogDto> GetAsync(Guid id);
Task DeleteAsync(Guid id);
}
}

17
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AuditLogs/IEntityChangesAppService.cs

@ -0,0 +1,17 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Sanhe.Abp.Auditing.AuditLogs;
public interface IEntityChangesAppService : IApplicationService
{
Task<EntityChangeDto> GetAsync(Guid id);
Task<EntityChangeWithUsernameDto> GetWithUsernameAsync(Guid id);
Task<PagedResultDto<EntityChangeDto>> GetListAsync(EntityChangeGetByPagedDto input);
Task<ListResultDto<EntityChangeWithUsernameDto>> GetWithUsernameAsync(EntityChangeGetWithUsernameDto input);
}

7
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/AuditingRemoteServiceConsts.cs

@ -0,0 +1,7 @@
namespace Sanhe.Abp.Auditing
{
public static class AuditingRemoteServiceConsts
{
public const string RemoteServiceName = "AbpAuditing";
}
}

43
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/Features/AuditingFeatureDefinitionProvider.cs

@ -0,0 +1,43 @@
using Volo.Abp.AuditLogging.Localization;
using Volo.Abp.Features;
using Volo.Abp.Localization;
using Volo.Abp.Validation.StringValues;
namespace Sanhe.Abp.Auditing.Features
{
public class AuditingFeatureDefinitionProvider : FeatureDefinitionProvider
{
public override void Define(IFeatureDefinitionContext context)
{
var auditingGroup = context.AddGroup(
name: AuditingFeatureNames.GroupName,
displayName: L("Features:Auditing"));
var loggingFeature = auditingGroup.AddFeature(
name: AuditingFeatureNames.Logging.Default,
displayName: L("Features:Auditing"),
description: L("Features:Auditing")
);
loggingFeature.CreateChild(
name: AuditingFeatureNames.Logging.AuditLog,
defaultValue: true.ToString(),
displayName: L("Features:DisplayName:AuditLog"),
description: L("Features:Description:AuditLog"),
valueType: new ToggleStringValueType(new BooleanValueValidator())
);
loggingFeature.CreateChild(
name: AuditingFeatureNames.Logging.SecurityLog,
defaultValue: true.ToString(),
displayName: L("Features:DisplayName:SecurityLog"),
description: L("Features:Description:SecurityLog"),
valueType: new ToggleStringValueType(new BooleanValueValidator())
);
}
protected LocalizableString L(string name)
{
return LocalizableString.Create<AuditLoggingResource>(name);
}
}
}

15
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/Features/AuditingFeatureNames.cs

@ -0,0 +1,15 @@
namespace Sanhe.Abp.Auditing.Features
{
public static class AuditingFeatureNames
{
public const string GroupName = "AbpAuditing";
public class Logging
{
public const string Default = GroupName + ".Logging";
public const string AuditLog = Default + ".AuditLog";
public const string SecurityLog = Default + ".SecurityLog";
}
}
}

88
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/Localization/Resources/en.json

@ -0,0 +1,88 @@
{
"culture": "en",
"texts": {
"Permissions:Auditing": "Auditing",
"Permissions:AuditLog": "Audit log",
"Permissions:SecurityLog": "Security log",
"Permissions:DeleteLog": "Delete",
"Features:Auditing": "Auditing",
"Features:DisplayName:AuditLog": "Audit log",
"Features:Description:AuditLog": "Whether to enable audit logging",
"Features:DisplayName:SecurityLog": "Security log",
"Features:Description:SecurityLog": "Whether to enable security logging",
"SecurityLog": "Security log",
"AuditLog": "Audit log",
"Logging": "System Log",
"Application": "Application",
"ApplicationName": "Application name",
"TenantId": "Tenant id",
"TenantName": "Tenant name",
"ImpersonatorTenantId": "Impersonator tenant",
"UserInfo": "User info",
"UserId": "User id",
"UserName": "User name",
"ImpersonatorUserId": "Impersonator user",
"ClientId": "Client id",
"ClientName": "Client name",
"ClientIpAddress": "Ip address",
"BrowserInfo": "Browser",
"Operation": "Operation",
"HttpMethod": "Http method",
"RequestUrl": "Request url",
"HttpStatusCode": "StatusCode",
"HasException": "Has exception",
"ExecutionTime": "Execution time",
"MinExecutionDuration": "Min execution duration(ms)",
"MaxExecutionDuration": "Max execution duration(ms)",
"ExecutionDuration": "Execution duration(ms)",
"Identity": "Identity",
"ActionName": "Action",
"CreationTime": "Creation time",
"Additional": "Additional",
"CorrelationId": "Correlation",
"StartTime": "Start time",
"EndTime": "End time",
"SelectDateTime": "Select time",
"InvokeMethod": "Invoke method",
"ServiceName": "Service",
"MethodName": "Method",
"Parameters": "Parameters",
"EntitiesChanged": "Entities changed",
"ChangeType": "Change type",
"EntityTypeFullName": "Entity type",
"EntityId": "Entity id",
"PropertyChanges": "Property changes",
"PropertyName": "Property name",
"NewValue": "New value",
"OriginalValue": "Original value",
"PropertyTypeFullName": "Property type",
"Exception": "Exception",
"StackTrack": "Stack track",
"SecrchLog": "Secrch",
"Created": "Created",
"Updated": "Updated",
"Deleted": "Deleted",
"ShowLogDialog": "Show log",
"DeleteLog": "Delete log",
"MachineName": "Machine",
"Environment": "Environment",
"Context": "Context",
"RequestId": "Request Id",
"RequestPath": "Request Path",
"ProcessId": "Process Id",
"ThreadId": "Thread Id",
"ActionId": "Action Id",
"ConnectionId": "Connection Id",
"Depth": "Depth",
"Class": "Class",
"Message": "Message",
"Source": "Source",
"StackTrace": "Stack Trace",
"HResult": "HResult",
"HelpURL": "Help Url",
"TimeStamp": "Timestamp",
"Level": "Level",
"Fields": "Fields",
"Exceptions": "Exceptions"
}
}

88
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/Localization/Resources/zh-Hans.json

@ -0,0 +1,88 @@
{
"culture": "zh-Hans",
"texts": {
"Permissions:Auditing": "内部审计",
"Permissions:AuditLog": "审计日志",
"Permissions:SecurityLog": "安全日志",
"Permissions:DeleteLog": "删除日志",
"Features:Auditing": "内部审计",
"Features:DisplayName:AuditLog": "审计日志",
"Features:Description:AuditLog": "是否启用审计日志功能",
"Features:DisplayName:SecurityLog": "安全日志",
"Features:Description:SecurityLog": "是否启用安全日志功能",
"SecurityLog": "安全日志",
"AuditLog": "审计日志",
"Logging": "系统日志",
"Application": "应用信息",
"ApplicationName": "应用名称",
"TenantId": "租户标识",
"TenantName": "租户名称",
"ImpersonatorTenantId": "模拟租户",
"UserInfo": "用户信息",
"UserId": "用户标识",
"UserName": "用户名称",
"ImpersonatorUserId": "模拟用户",
"ClientId": "客户端标识",
"ClientName": "客户端名称",
"ClientIpAddress": "客户端地址",
"BrowserInfo": "浏览器信息",
"Operation": "操作信息",
"HttpMethod": "请求方法",
"RequestUrl": "请求路径",
"HttpStatusCode": "响应状态",
"HasException": "包含异常",
"ExecutionTime": "调用时间",
"MinExecutionDuration": "最短响应时间(ms)",
"MaxExecutionDuration": "最长响应时间(ms)",
"ExecutionDuration": "响应时间(ms)",
"Identity": "主体名称",
"ActionName": "方法名称",
"CreationTime": "创建时间",
"Additional": "附加信息",
"CorrelationId": "链路标识",
"StartTime": "开始时间",
"EndTime": "结束时间",
"SelectDateTime": "选择日期时间",
"InvokeMethod": "调用方法",
"ServiceName": "服务名称",
"MethodName": "方法名称",
"Parameters": "参数列表",
"EntitiesChanged": "实体变更",
"ChangeType": "变更类型",
"EntityTypeFullName": "实体类型",
"EntityId": "实体标识",
"PropertyChanges": "属性变更",
"PropertyName": "属性名称",
"NewValue": "当前值",
"OriginalValue": "原始值",
"PropertyTypeFullName": "属性类型",
"Exception": "异常信息",
"StackTrack": "异常堆栈",
"SecrchLog": "查询日志",
"Created": "新增",
"Updated": "修改",
"Deleted": "删除",
"ShowLogDialog": "查看日志",
"DeleteLog": "删除日志",
"MachineName": "机器名称",
"Environment": "应用环境",
"Context": "上下文",
"RequestId": "请求标识",
"RequestPath": "请求路径",
"ProcessId": "进程标识",
"ThreadId": "线程标识",
"ActionId": "方法标识",
"ConnectionId": "连接标识",
"Depth": "深度",
"Class": "类型",
"Message": "信息",
"Source": "来源",
"StackTrace": "堆栈",
"HResult": "代码",
"HelpURL": "帮助",
"TimeStamp": "时间戳",
"Level": "级别",
"Fields": "字段",
"Exceptions": "错误信息"
}
}

15
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/Logging/Dto/LogDto.cs

@ -0,0 +1,15 @@
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
namespace Sanhe.Abp.Auditing.Logging.Dto
{
public class LogDto
{
public DateTime TimeStamp { get; set; }
public LogLevel Level { get; set; }
public string Message { get; set; }
public LogFieldDto Fields { get; set; }
public List<LogExceptionDto> Exceptions { get; set; }
}
}

13
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/Logging/Dto/LogExceptionDto.cs

@ -0,0 +1,13 @@
namespace Sanhe.Abp.Auditing.Logging.Dto
{
public class LogExceptionDto
{
public int Depth { get; set; }
public string Class { get; set; }
public string Message { get; set; }
public string Source { get; set; }
public string StackTrace { get; set; }
public int HResult { get; set; }
public string HelpURL { get; set; }
}
}

21
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/Logging/Dto/LogFieldDto.cs

@ -0,0 +1,21 @@
namespace Sanhe.Abp.Auditing.Logging.Dto
{
public class LogFieldDto
{
public string Id { get; set; }
public string MachineName { get; set; }
public string Environment { get; set; }
public string Application { get; set; }
public string Context { get; set; }
public string ActionId { get; set; }
public string ActionName { get; set; }
public string RequestId { get; set; }
public string RequestPath { get; set; }
public string ConnectionId { get; set; }
public string CorrelationId { get; set; }
public string ClientId { get; set; }
public string UserId { get; set; }
public int ProcessId { get; set; }
public int ThreadId { get; set; }
}
}

23
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/Logging/Dto/LogGetByPagedDto.cs

@ -0,0 +1,23 @@
using Microsoft.Extensions.Logging;
using System;
using Volo.Abp.Application.Dtos;
namespace Sanhe.Abp.Auditing.Logging.Dto
{
public class LogGetByPagedDto : PagedAndSortedResultRequestDto
{
public DateTime? StartTime { get; set; }
public DateTime? EndTime { get; set; }
public LogLevel? Level { get; set; }
public string MachineName { get; set; }
public string Environment { get; set; }
public string Application { get; set; }
public string Context { get; set; }
public string RequestId { get; set; }
public string RequestPath { get; set; }
public string CorrelationId { get; set; }
public int? ProcessId { get; set; }
public int? ThreadId { get; set; }
public bool? HasException { get; set; }
}
}

14
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/Logging/ILogAppService.cs

@ -0,0 +1,14 @@
using Sanhe.Abp.Auditing.Logging.Dto;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Sanhe.Abp.Auditing.Logging
{
public interface ILogAppService : IApplicationService
{
Task<LogDto> GetAsync(string id);
Task<PagedResultDto<LogDto>> GetListAsync(LogGetByPagedDto input);
}
}

35
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/Permissions/AuditingPermissionDefinitionProvider.cs

@ -0,0 +1,35 @@
using Volo.Abp.AuditLogging.Localization;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Localization;
namespace Sanhe.Abp.Auditing.Permissions
{
public class AuditingPermissionDefinitionProvider : PermissionDefinitionProvider
{
public override void Define(IPermissionDefinitionContext context)
{
var auditingGroup = context.AddGroup(
name: AuditingPermissionNames.GroupName,
displayName: L("Permissions:Auditing"));
var auditLogPermission = auditingGroup.AddPermission(
name: AuditingPermissionNames.AuditLog.Default,
displayName: L("Permissions:AuditLog"));
auditLogPermission.AddChild(
name: AuditingPermissionNames.AuditLog.Delete,
displayName: L("Permissions:DeleteLog"));
var securityLogPermission = auditingGroup.AddPermission(
name: AuditingPermissionNames.SecurityLog.Default,
displayName: L("Permissions:SecurityLog"));
securityLogPermission.AddChild(
name: AuditingPermissionNames.SecurityLog.Delete,
displayName: L("Permissions:DeleteLog"));
}
protected LocalizableString L(string name)
{
return LocalizableString.Create<AuditLoggingResource>(name);
}
}
}

18
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/Permissions/AuditingPermissionNames.cs

@ -0,0 +1,18 @@
namespace Sanhe.Abp.Auditing.Permissions
{
public class AuditingPermissionNames
{
public const string GroupName = "AbpAuditing";
public class AuditLog
{
public const string Default = GroupName + ".AuditLog";
public const string Delete = Default + ".Delete";
}
public class SecurityLog
{
public const string Default = GroupName + ".SecurityLog";
public const string Delete = Default + ".Delete";
}
}
}

16
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/SecurityLogs/ISecurityLogAppService.cs

@ -0,0 +1,16 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Sanhe.Abp.Auditing.SecurityLogs
{
public interface ISecurityLogAppService : IApplicationService
{
Task<PagedResultDto<SecurityLogDto>> GetListAsync(SecurityLogGetByPagedDto input);
Task<SecurityLogDto> GetAsync(Guid id);
Task DeleteAsync(Guid id);
}
}

30
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/SecurityLogs/SecurityLogDto.cs

@ -0,0 +1,30 @@
using System;
using Volo.Abp.Application.Dtos;
namespace Sanhe.Abp.Auditing.SecurityLogs
{
public class SecurityLogDto : ExtensibleEntityDto<Guid>
{
public string ApplicationName { get; set; }
public string Identity { get; set; }
public string Action { get; set; }
public Guid? UserId { get; set; }
public string UserName { get; set; }
public string TenantName { get; set; }
public string ClientId { get; set; }
public string CorrelationId { get; set; }
public string ClientIpAddress { get; set; }
public string BrowserInfo { get; set; }
public DateTime CreationTime { get; set; }
}
}

18
modules/auditing/Sanhe.Abp.Auditing.Application.Contracts/Sanhe/Abp/Auditing/SecurityLogs/SecurityLogGetByPagedDto.cs

@ -0,0 +1,18 @@
using System;
using Volo.Abp.Application.Dtos;
namespace Sanhe.Abp.Auditing.SecurityLogs
{
public class SecurityLogGetByPagedDto : PagedAndSortedResultRequestDto
{
public DateTime? StartTime { get; set; }
public DateTime? EndTime { get; set; }
public string ApplicationName { get; set; }
public string Identity { get; set; }
public string ActionName { get; set; }
public Guid? UserId { get; set; }
public string UserName { get; set; }
public string ClientId { get; set; }
public string CorrelationId { get; set; }
}
}

3
modules/auditing/Sanhe.Abp.Auditing.Application/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

22
modules/auditing/Sanhe.Abp.Auditing.Application/Sanhe.Abp.Auditing.Application.csproj

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.AutoMapper" Version="$(VoloAbpVersion)" />
<PackageReference Include="Volo.Abp.Ddd.Application" Version="$(VoloAbpVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\logging\Sanhe.Abp.Logging\Sanhe.Abp.Logging.csproj" />
<ProjectReference Include="..\Sanhe.Abp.Auditing.Application.Contracts\Sanhe.Abp.Auditing.Application.Contracts.csproj" />
<ProjectReference Include="..\Sanhe.Abp.AuditLogging\Sanhe.Abp.AuditLogging.csproj" />
</ItemGroup>
</Project>

24
modules/auditing/Sanhe.Abp.Auditing.Application/Sanhe/Abp/Auditing/AbpAuditingApplicationModule.cs

@ -0,0 +1,24 @@
using Microsoft.Extensions.DependencyInjection;
using Sanhe.Abp.AuditLogging;
using Volo.Abp.AutoMapper;
using Volo.Abp.Modularity;
namespace Sanhe.Abp.Auditing
{
[DependsOn(
typeof(AbpAutoMapperModule),
typeof(AbpAuditLoggingModule),
typeof(AbpAuditingApplicationContractsModule))]
public class AbpAuditingApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAutoMapperObjectMapper<AbpAuditingApplicationModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<AbpAuditingMapperProfile>(validate: true);
});
}
}
}

31
modules/auditing/Sanhe.Abp.Auditing.Application/Sanhe/Abp/Auditing/AbpAuditingMapperProfile.cs

@ -0,0 +1,31 @@
using AutoMapper;
using Sanhe.Abp.Auditing.AuditLogs;
using Sanhe.Abp.Auditing.Logging.Dto;
using Sanhe.Abp.Auditing.SecurityLogs;
using Sanhe.Abp.AuditLogging;
using Sanhe.Abp.Logging;
namespace Sanhe.Abp.Auditing
{
public class AbpAuditingMapperProfile : Profile
{
public AbpAuditingMapperProfile()
{
CreateMap<AuditLogAction, AuditLogActionDto>()
.MapExtraProperties();
CreateMap<EntityPropertyChange, EntityPropertyChangeDto>();
CreateMap<EntityChangeWithUsername, EntityChangeWithUsernameDto>();
CreateMap<EntityChange, EntityChangeDto>()
.MapExtraProperties();
CreateMap<AuditLog, AuditLogDto>()
.MapExtraProperties();
CreateMap<SecurityLog, SecurityLogDto>()
.MapExtraProperties();
CreateMap<LogField, LogFieldDto>();
CreateMap<LogException, LogExceptionDto>();
CreateMap<LogInfo, LogDto>();
}
}
}

63
modules/auditing/Sanhe.Abp.Auditing.Application/Sanhe/Abp/Auditing/AuditLogs/AuditLogAppService.cs

@ -0,0 +1,63 @@
using Microsoft.AspNetCore.Authorization;
using Sanhe.Abp.Auditing.Features;
using Sanhe.Abp.Auditing.Permissions;
using Sanhe.Abp.AuditLogging;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Features;
namespace Sanhe.Abp.Auditing.AuditLogs
{
[Authorize(AuditingPermissionNames.AuditLog.Default)]
[RequiresFeature(AuditingFeatureNames.Logging.AuditLog)]
public class AuditLogAppService : AuditingApplicationServiceBase, IAuditLogAppService
{
protected IAuditLogManager AuditLogManager { get; }
public AuditLogAppService(IAuditLogManager auditLogManager)
{
AuditLogManager = auditLogManager;
}
public virtual async Task<AuditLogDto> GetAsync(Guid id)
{
var auditLog = await AuditLogManager.GetAsync(id, includeDetails: true);
return ObjectMapper.Map<AuditLog, AuditLogDto>(auditLog);
}
public virtual async Task<PagedResultDto<AuditLogDto>> GetListAsync(AuditLogGetByPagedDto input)
{
var auditLogCount = await AuditLogManager
.GetCountAsync(input.StartTime, input.EndTime,
input.HttpMethod, input.Url,
input.UserId, input.UserName,
input.ApplicationName, input.CorrelationId,
input.ClientId, input.ClientIpAddress,
input.MaxExecutionDuration, input.MinExecutionDuration,
input.HasException, input.HttpStatusCode);
var auditLogs = await AuditLogManager
.GetListAsync(input.Sorting, input.MaxResultCount, input.SkipCount,
input.StartTime, input.EndTime,
input.HttpMethod, input.Url,
input.UserId, input.UserName,
input.ApplicationName, input.CorrelationId,
input.ClientId, input.ClientIpAddress,
input.MaxExecutionDuration, input.MinExecutionDuration,
input.HasException, input.HttpStatusCode, includeDetails: false);
return new PagedResultDto<AuditLogDto>(auditLogCount,
ObjectMapper.Map<List<AuditLog>, List<AuditLogDto>>(auditLogs));
}
[Authorize(AuditingPermissionNames.AuditLog.Delete)]
public virtual async Task DeleteAsync([Required] Guid id)
{
await AuditLogManager.DeleteAsync(id);
}
}
}

61
modules/auditing/Sanhe.Abp.Auditing.Application/Sanhe/Abp/Auditing/AuditLogs/EntityChangesAppService.cs

@ -0,0 +1,61 @@
using Microsoft.AspNetCore.Authorization;
using Sanhe.Abp.Auditing.Features;
using Sanhe.Abp.Auditing.Permissions;
using Sanhe.Abp.AuditLogging;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Features;
namespace Sanhe.Abp.Auditing.AuditLogs;
[Authorize(AuditingPermissionNames.AuditLog.Default)]
[RequiresFeature(AuditingFeatureNames.Logging.AuditLog)]
public class EntityChangesAppService : AuditingApplicationServiceBase, IEntityChangesAppService
{
protected IEntityChangeStore EntityChangeStore { get; }
public EntityChangesAppService(IEntityChangeStore entityChangeStore)
{
EntityChangeStore = entityChangeStore;
}
public async virtual Task<EntityChangeDto> GetAsync(Guid id)
{
var entityChange = await EntityChangeStore.GetAsync(id);
return ObjectMapper.Map<EntityChange, EntityChangeDto>(entityChange);
}
public async virtual Task<PagedResultDto<EntityChangeDto>> GetListAsync(EntityChangeGetByPagedDto input)
{
var totalCount = await EntityChangeStore.GetCountAsync(
input.AuditLogId, input.StartTime, input.EndTime,
input.ChangeType, input.EntityId, input.EntityTypeFullName);
var entityChanges = await EntityChangeStore.GetListAsync(
input.Sorting, input.MaxResultCount, input.SkipCount,
input.AuditLogId, input.StartTime, input.EndTime,
input.ChangeType, input.EntityId, input.EntityTypeFullName);
return new PagedResultDto<EntityChangeDto>(totalCount,
ObjectMapper.Map<List<EntityChange>, List<EntityChangeDto>>(entityChanges));
}
public async virtual Task<EntityChangeWithUsernameDto> GetWithUsernameAsync(Guid id)
{
var entityChangeWithUsername = await EntityChangeStore.GetWithUsernameAsync(id);
return ObjectMapper.Map<EntityChangeWithUsername, EntityChangeWithUsernameDto>(entityChangeWithUsername);
}
public async virtual Task<ListResultDto<EntityChangeWithUsernameDto>> GetWithUsernameAsync(EntityChangeGetWithUsernameDto input)
{
var entityChangeWithUsernames = await EntityChangeStore.GetWithUsernameAsync(
input.EntityId, input.EntityTypeFullName);
return new ListResultDto<EntityChangeWithUsernameDto>(
ObjectMapper.Map<List<EntityChangeWithUsername>, List<EntityChangeWithUsernameDto>>(entityChangeWithUsernames));
}
}

14
modules/auditing/Sanhe.Abp.Auditing.Application/Sanhe/Abp/Auditing/AuditingApplicationServiceBase.cs

@ -0,0 +1,14 @@
using Volo.Abp.Application.Services;
using Volo.Abp.AuditLogging.Localization;
namespace Sanhe.Abp.Auditing
{
public abstract class AuditingApplicationServiceBase : ApplicationService
{
protected AuditingApplicationServiceBase()
{
LocalizationResource = typeof(AuditLoggingResource);
ObjectMapperContext = typeof(AbpAuditingApplicationModule);
}
}
}

49
modules/auditing/Sanhe.Abp.Auditing.Application/Sanhe/Abp/Auditing/Logging/LogAppService.cs

@ -0,0 +1,49 @@
using Sanhe.Abp.Auditing.Logging.Dto;
using Sanhe.Abp.Logging;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
namespace Sanhe.Abp.Auditing.Logging
{
public class LogAppService : AuditingApplicationServiceBase, ILogAppService
{
private readonly ILoggingManager _manager;
public LogAppService(ILoggingManager manager)
{
_manager = manager;
}
public virtual async Task<LogDto> GetAsync(string id)
{
var log = await _manager.GetAsync(id);
return ObjectMapper.Map<LogInfo, LogDto>(log);
}
public virtual async Task<PagedResultDto<LogDto>> GetListAsync(LogGetByPagedDto input)
{
var count = await _manager.GetCountAsync(
input.StartTime, input.EndTime, input.Level,
input.MachineName, input.Environment,
input.Application, input.Context,
input.RequestId, input.RequestPath,
input.CorrelationId, input.ProcessId,
input.ThreadId, input.HasException);
var logs = await _manager.GetListAsync(
input.Sorting, input.MaxResultCount, input.SkipCount,
input.StartTime, input.EndTime, input.Level,
input.MachineName, input.Environment,
input.Application, input.Context,
input.RequestId, input.RequestPath,
input.CorrelationId, input.ProcessId,
input.ThreadId, input.HasException,
includeDetails: false);
return new PagedResultDto<LogDto>(count,
ObjectMapper.Map<List<LogInfo>, List<LogDto>>(logs));
}
}
}

57
modules/auditing/Sanhe.Abp.Auditing.Application/Sanhe/Abp/Auditing/SecurityLogs/SecurityLogAppService.cs

@ -0,0 +1,57 @@
using Microsoft.AspNetCore.Authorization;
using Sanhe.Abp.Auditing.Features;
using Sanhe.Abp.Auditing.Permissions;
using Sanhe.Abp.AuditLogging;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Features;
namespace Sanhe.Abp.Auditing.SecurityLogs
{
[Authorize(AuditingPermissionNames.SecurityLog.Default)]
[RequiresFeature(AuditingFeatureNames.Logging.SecurityLog)]
public class SecurityLogAppService : AuditingApplicationServiceBase, ISecurityLogAppService
{
protected ISecurityLogManager SecurityLogManager { get; }
public SecurityLogAppService(ISecurityLogManager securityLogManager)
{
SecurityLogManager = securityLogManager;
}
public virtual async Task<SecurityLogDto> GetAsync(Guid id)
{
var securityLog = await SecurityLogManager.GetAsync(id, includeDetails: true);
return ObjectMapper.Map<SecurityLog, SecurityLogDto>(securityLog);
}
public virtual async Task<PagedResultDto<SecurityLogDto>> GetListAsync(SecurityLogGetByPagedDto input)
{
var securityLogCount = await SecurityLogManager
.GetCountAsync(input.StartTime, input.EndTime,
input.ApplicationName, input.Identity, input.ActionName,
input.UserId, input.UserName, input.ClientId, input.CorrelationId
);
var securityLogs = await SecurityLogManager
.GetListAsync(input.Sorting, input.MaxResultCount, input.SkipCount,
input.StartTime, input.EndTime,
input.ApplicationName, input.Identity, input.ActionName,
input.UserId, input.UserName, input.ClientId, input.CorrelationId,
includeDetails: false
);
return new PagedResultDto<SecurityLogDto>(securityLogCount,
ObjectMapper.Map<List<SecurityLog>, List<SecurityLogDto>>(securityLogs));
}
[Authorize(AuditingPermissionNames.SecurityLog.Delete)]
public virtual async Task DeleteAsync(Guid id)
{
await SecurityLogManager.DeleteAsync(id);
}
}
}

3
modules/auditing/Sanhe.Abp.Auditing.HttpApi/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

19
modules/auditing/Sanhe.Abp.Auditing.HttpApi/Sanhe.Abp.Auditing.HttpApi.csproj

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.AspNetCore.Mvc" Version="$(VoloAbpVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Sanhe.Abp.Auditing.Application.Contracts\Sanhe.Abp.Auditing.Application.Contracts.csproj" />
</ItemGroup>
</Project>

41
modules/auditing/Sanhe.Abp.Auditing.HttpApi/Sanhe/Abp/Auditing/AbpAuditingHttpApiModule.cs

@ -0,0 +1,41 @@
using Localization.Resources.AbpUi;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AuditLogging.Localization;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
namespace Sanhe.Abp.Auditing
{
[DependsOn(
typeof(AbpAspNetCoreMvcModule),
typeof(AbpAuditingApplicationContractsModule))]
public class AbpAuditingHttpApiModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<IMvcBuilder>(mvcBuilder =>
{
mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpAuditingHttpApiModule).Assembly);
});
PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options =>
{
options.AddAssemblyResource(typeof(AuditLoggingResource), typeof(AbpAuditingApplicationContractsModule).Assembly);
});
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Get<AuditLoggingResource>()
.AddBaseTypes(
typeof(AbpUiResource)
);
});
}
}
}

61
modules/auditing/Sanhe.Abp.Auditing.HttpApi/Sanhe/Abp/Auditing/AuditLogs/AuditLogController.cs

@ -0,0 +1,61 @@
using Microsoft.AspNetCore.Mvc;
using System;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.AspNetCore.Mvc;
namespace Sanhe.Abp.Auditing.AuditLogs
{
/// <summary>
/// 审计日志
/// </summary>
[RemoteService(Name = AuditingRemoteServiceConsts.RemoteServiceName)]
[Area("auditing")]
[ControllerName("audit-log")]
[Route("api/auditing/audit-log")]
public class AuditLogController : AbpController, IAuditLogAppService
{
protected IAuditLogAppService AuditLogAppService { get; }
public AuditLogController(IAuditLogAppService auditLogAppService)
{
AuditLogAppService = auditLogAppService;
}
/// <summary>
/// 根据Id获取
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet]
[Route("{id}")]
public virtual Task<AuditLogDto> GetAsync(Guid id)
{
return AuditLogAppService.GetAsync(id);
}
/// <summary>
/// 分页获取
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet]
public virtual Task<PagedResultDto<AuditLogDto>> GetListAsync(AuditLogGetByPagedDto input)
{
return AuditLogAppService.GetListAsync(input);
}
/// <summary>
/// 根据Id删除
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpDelete]
[Route("{id}")]
public virtual Task DeleteAsync(Guid id)
{
return AuditLogAppService.DeleteAsync(id);
}
}
}

49
modules/auditing/Sanhe.Abp.Auditing.HttpApi/Sanhe/Abp/Auditing/AuditLogs/EntityChangesController.cs

@ -0,0 +1,49 @@
using Microsoft.AspNetCore.Mvc;
using System;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.AspNetCore.Mvc;
namespace Sanhe.Abp.Auditing.AuditLogs;
[RemoteService(Name = AuditingRemoteServiceConsts.RemoteServiceName)]
[Area("auditing")]
[ControllerName("entity-changes")]
[Route("api/auditing/entity-changes")]
public class EntityChangesController : AbpControllerBase, IEntityChangesAppService
{
protected IEntityChangesAppService EntityChangeAppService { get; }
public EntityChangesController(IEntityChangesAppService entityChangeAppService)
{
EntityChangeAppService = entityChangeAppService;
}
[HttpGet]
[Route("{id}")]
public Task<EntityChangeDto> GetAsync(Guid id)
{
return EntityChangeAppService.GetAsync(id);
}
[HttpGet]
public Task<PagedResultDto<EntityChangeDto>> GetListAsync(EntityChangeGetByPagedDto input)
{
return EntityChangeAppService.GetListAsync(input);
}
[HttpGet]
[Route("with-username/{id}")]
public Task<EntityChangeWithUsernameDto> GetWithUsernameAsync(Guid id)
{
return EntityChangeAppService.GetWithUsernameAsync(id);
}
[HttpGet]
[Route("with-username")]
public Task<ListResultDto<EntityChangeWithUsernameDto>> GetWithUsernameAsync(EntityChangeGetWithUsernameDto input)
{
return EntityChangeAppService.GetWithUsernameAsync(input);
}
}

49
modules/auditing/Sanhe.Abp.Auditing.HttpApi/Sanhe/Abp/Auditing/Logging/LogController.cs

@ -0,0 +1,49 @@
using Microsoft.AspNetCore.Mvc;
using Sanhe.Abp.Auditing.Logging.Dto;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.AspNetCore.Mvc;
namespace Sanhe.Abp.Auditing.Logging
{
/// <summary>
/// 日志
/// </summary>
[RemoteService(Name = AuditingRemoteServiceConsts.RemoteServiceName)]
[Area("auditing")]
[ControllerName("logging")]
[Route("api/auditing/logging")]
public class LogController : AbpController, ILogAppService
{
private readonly ILogAppService _service;
public LogController(ILogAppService service)
{
_service = service;
}
/// <summary>
/// 根据Id获取
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet]
[Route("{id}")]
public virtual Task<LogDto> GetAsync(string id)
{
return _service.GetAsync(id);
}
/// <summary>
/// 分页获取
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet]
public virtual Task<PagedResultDto<LogDto>> GetListAsync(LogGetByPagedDto input)
{
return _service.GetListAsync(input);
}
}
}

62
modules/auditing/Sanhe.Abp.Auditing.HttpApi/Sanhe/Abp/Auditing/SecurityLogs/SecurityLogController.cs

@ -0,0 +1,62 @@
using Microsoft.AspNetCore.Mvc;
using System;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.AspNetCore.Mvc;
namespace Sanhe.Abp.Auditing.SecurityLogs
{
/// <summary>
/// 安全日志
/// </summary>
[RemoteService(Name = AuditingRemoteServiceConsts.RemoteServiceName)]
[Area("auditing")]
[ControllerName("security-log")]
[Route("api/auditing/security-log")]
public class SecurityLogController : AbpController, ISecurityLogAppService
{
protected ISecurityLogAppService SecurityLogAppService { get; }
public SecurityLogController(ISecurityLogAppService securityLogAppService)
{
SecurityLogAppService = securityLogAppService;
}
/// <summary>
/// 根据Id获取
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet]
[Route("{id}")]
public virtual Task<SecurityLogDto> GetAsync(Guid id)
{
return SecurityLogAppService.GetAsync(id);
}
/// <summary>
/// 分页获取
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet]
public virtual Task<PagedResultDto<SecurityLogDto>> GetListAsync(SecurityLogGetByPagedDto input)
{
return SecurityLogAppService.GetListAsync(input);
}
/// <summary>
/// 根据Id删除
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpDelete]
[Route("{id}")]
public virtual Task DeleteAsync(Guid id)
{
return SecurityLogAppService.DeleteAsync(id);
}
}
}

3
modules/logging/Sanhe.Abp.Logging.Serilog.Elasticsearch/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

32
modules/logging/Sanhe.Abp.Logging.Serilog.Elasticsearch/README.md

@ -0,0 +1,32 @@
# LINGYUN.Abp.Logging.Serilog.Elasticsearch
ILoggingManager 接口的ES实现, 从ES中检索日志信息
## 模块引用
```csharp
[DependsOn(typeof(AbpLoggingSerilogElasticsearchModule))]
public class YouProjectModule : AbpModule
{
// other
}
```
## 配置项
* AbpLoggingSerilogElasticsearchOptions.IndexFormat 必须和Serilog配置项中的IndexFormat相同,否则无法定位到正确的索引
## appsettings.json
```json
{
"Logging": {
"Serilog": {
"Elasticsearch": {
"IndexFormat": "logstash-{0:yyyy.MM.dd}"
}
}
}
}
```

24
modules/logging/Sanhe.Abp.Logging.Serilog.Elasticsearch/Sanhe.Abp.Logging.Serilog.Elasticsearch.csproj

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Serilog.Sinks.Elasticsearch" Version="$(SerilogSinksElasticsearchPackageVersion)" />
<PackageReference Include="Volo.Abp.AutoMapper" Version="$(VoloAbpVersion)" />
<PackageReference Include="Volo.Abp.Json" Version="$(VoloAbpVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\elasticsearch\Sanhe.Abp.Elasticsearch\Sanhe.Abp.Elasticsearch.csproj" />
<ProjectReference Include="..\Sanhe.Abp.Logging\Sanhe.Abp.Logging.csproj" />
<ProjectReference Include="..\Sanhe.Abp.Serilog.Enrichers.Application\Sanhe.Abp.Serilog.Enrichers.Application.csproj" />
<ProjectReference Include="..\Sanhe.Abp.Serilog.Enrichers.UniqueId\Sanhe.Abp.Serilog.Enrichers.UniqueId.csproj" />
</ItemGroup>
</Project>

16
modules/logging/Sanhe.Abp.Logging.Serilog.Elasticsearch/Sanhe/Abp/AuditLogging/Serilog/Elasticsearch/AbpLoggingSerilogElasticsearchMapperProfile.cs

@ -0,0 +1,16 @@
using AutoMapper;
using Sanhe.Abp.Logging;
namespace Sanhe.Abp.AuditLogging.Serilog.Elasticsearch
{
public class AbpLoggingSerilogElasticsearchMapperProfile : Profile
{
public AbpLoggingSerilogElasticsearchMapperProfile()
{
CreateMap<SerilogException, LogException>();
CreateMap<SerilogField, LogField>()
.ForMember(log => log.Id, map => map.MapFrom(slog => slog.UniqueId.ToString()));
CreateMap<SerilogInfo, LogInfo>();
}
}
}

31
modules/logging/Sanhe.Abp.Logging.Serilog.Elasticsearch/Sanhe/Abp/AuditLogging/Serilog/Elasticsearch/AbpLoggingSerilogElasticsearchModule.cs

@ -0,0 +1,31 @@
using Sanhe.Abp.Elasticsearch;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AutoMapper;
using Volo.Abp.Json;
using Volo.Abp.Modularity;
using Sanhe.Abp.Logging;
namespace Sanhe.Abp.AuditLogging.Serilog.Elasticsearch
{
[DependsOn(
typeof(AbpLoggingModule),
typeof(AbpElasticsearchModule),
typeof(AbpAutoMapperModule),
typeof(AbpJsonModule))]
public class AbpLoggingSerilogElasticsearchModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
Configure<AbpLoggingSerilogElasticsearchOptions>(configuration.GetSection("Logging:Serilog:Elasticsearch"));
context.Services.AddAutoMapperObjectMapper<AbpLoggingSerilogElasticsearchModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<AbpLoggingSerilogElasticsearchMapperProfile>(validate: true);
});
}
}
}

12
modules/logging/Sanhe.Abp.Logging.Serilog.Elasticsearch/Sanhe/Abp/AuditLogging/Serilog/Elasticsearch/AbpLoggingSerilogElasticsearchOptions.cs

@ -0,0 +1,12 @@
namespace Sanhe.Abp.AuditLogging.Serilog.Elasticsearch
{
public class AbpLoggingSerilogElasticsearchOptions
{
public string IndexFormat { get; set; }
public AbpLoggingSerilogElasticsearchOptions()
{
IndexFormat = "logstash-{0:yyyy.MM.dd}";
}
}
}

412
modules/logging/Sanhe.Abp.Logging.Serilog.Elasticsearch/Sanhe/Abp/AuditLogging/Serilog/Elasticsearch/SerilogElasticsearchLoggingManager.cs

@ -0,0 +1,412 @@
using Sanhe.Abp.Elasticsearch;
using Sanhe.Abp.Serilog.Enrichers.Application;
using Sanhe.Abp.Serilog.Enrichers.UniqueId;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Nest;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
using Volo.Abp.ObjectMapping;
using Sanhe.Abp.Logging;
namespace Sanhe.Abp.AuditLogging.Serilog.Elasticsearch
{
[Dependency(ReplaceServices = true)]
public class SerilogElasticsearchLoggingManager : ILoggingManager, ISingletonDependency
{
private static readonly Regex IndexFormatRegex = new Regex(@"^(.*)(?:\{0\:.+\})(.*)$");
private readonly IObjectMapper _objectMapper;
private readonly ICurrentTenant _currentTenant;
private readonly AbpLoggingSerilogElasticsearchOptions _options;
private readonly IElasticsearchClientFactory _clientFactory;
public ILogger<SerilogElasticsearchLoggingManager> Logger { protected get; set; }
public SerilogElasticsearchLoggingManager(
IObjectMapper objectMapper,
ICurrentTenant currentTenant,
IOptions<AbpLoggingSerilogElasticsearchOptions> options,
IElasticsearchClientFactory clientFactory)
{
_objectMapper = objectMapper;
_currentTenant = currentTenant;
_clientFactory = clientFactory;
_options = options.Value;
Logger = NullLogger<SerilogElasticsearchLoggingManager>.Instance;
}
/// <summary>
///
/// </summary>
/// <param name="id">时间类型或者转换为timestamp都可以查询</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public virtual async Task<LogInfo> GetAsync(
string id,
CancellationToken cancellationToken = default)
{
var client = _clientFactory.Create();
ISearchResponse<SerilogInfo> response;
if (_currentTenant.IsAvailable)
{
/*
"query": {
"bool": {
"must": [
{
"term": {
"fields.TenantId.keyword": {
"value": _currentTenant.GetId()
}
}
},
{
"term": {
"fields.UniqueId": {
"value": "1474021081433481216"
}
}
}
]
}
}
*/
response = await client.SearchAsync<SerilogInfo>(
dsl =>
dsl.Index(CreateIndex())
.Query(
(q) => q.Bool(
(b) => b.Must(
(s) => s.Term(
(t) => t.Field(GetField(nameof(SerilogInfo.Fields.UniqueId))).Value(id)),
(s) => s.Term(
(t) => t.Field(GetField(nameof(SerilogInfo.Fields.TenantId))).Value(_currentTenant.GetId()))))),
cancellationToken);
}
else
{
/*
"query": {
"bool": {
"must": [
{
"term": {
"fields.UniqueId": {
"value": "1474021081433481216"
}
}
}
]
}
}
*/
response = await client.SearchAsync<SerilogInfo>(
dsl =>
dsl.Index(CreateIndex())
.Query(
(q) => q.Bool(
(b) => b.Must(
(s) => s.Term(
(t) => t.Field(GetField(nameof(SerilogInfo.Fields.UniqueId))).Value(id))))),
cancellationToken);
}
return _objectMapper.Map<SerilogInfo, LogInfo>(response.Documents.FirstOrDefault());
}
public virtual async Task<long> GetCountAsync(
DateTime? startTime = null,
DateTime? endTime = null,
Microsoft.Extensions.Logging.LogLevel? level = null,
string machineName = null,
string environment = null,
string application = null,
string context = null,
string requestId = null,
string requestPath = null,
string correlationId = null,
int? processId = null,
int? threadId = null,
bool? hasException = null,
CancellationToken cancellationToken = default)
{
var client = _clientFactory.Create();
var querys = BuildQueryDescriptor(
startTime,
endTime,
level,
machineName,
environment,
application,
context,
requestId,
requestPath,
correlationId,
processId,
threadId,
hasException);
var response = await client.CountAsync<SerilogInfo>((dsl) =>
dsl.Index(CreateIndex())
.Query(log => log.Bool(b => b.Must(querys.ToArray()))),
cancellationToken);
return response.Count;
}
/// <summary>
/// 获取日志列表
/// </summary>
/// <param name="sorting">排序字段</param>
/// <param name="maxResultCount"></param>
/// <param name="skipCount"></param>
/// <param name="startTime"></param>
/// <param name="endTime"></param>
/// <param name="level"></param>
/// <param name="machineName"></param>
/// <param name="environment"></param>
/// <param name="application"></param>
/// <param name="context"></param>
/// <param name="requestId"></param>
/// <param name="requestPath"></param>
/// <param name="correlationId"></param>
/// <param name="processId"></param>
/// <param name="threadId"></param>
/// <param name="hasException"></param>
/// <param name="includeDetails"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public virtual async Task<List<LogInfo>> GetListAsync(
string sorting = null,
int maxResultCount = 50,
int skipCount = 0,
DateTime? startTime = null,
DateTime? endTime = null,
Microsoft.Extensions.Logging.LogLevel? level = null,
string machineName = null,
string environment = null,
string application = null,
string context = null,
string requestId = null,
string requestPath = null,
string correlationId = null,
int? processId = null,
int? threadId = null,
bool? hasException = null,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
var client = _clientFactory.Create();
var sortOrder = !sorting.IsNullOrWhiteSpace() && sorting.EndsWith("asc", StringComparison.InvariantCultureIgnoreCase)
? SortOrder.Ascending : SortOrder.Descending;
sorting = !sorting.IsNullOrWhiteSpace()
? sorting.Split()[0]
: nameof(SerilogInfo.TimeStamp);
var querys = BuildQueryDescriptor(
startTime,
endTime,
level,
machineName,
environment,
application,
context,
requestId,
requestPath,
correlationId,
processId,
threadId,
hasException);
SourceFilterDescriptor<SerilogInfo> SourceFilter(SourceFilterDescriptor<SerilogInfo> selector)
{
selector.IncludeAll();
if (!includeDetails)
{
selector.Excludes(field =>
field.Field("exceptions"));
}
return selector;
}
var response = await client.SearchAsync<SerilogInfo>((dsl) =>
dsl.Index(CreateIndex())
.Query(log =>
log.Bool(b =>
b.Must(querys.ToArray())))
.Source(SourceFilter)
.Sort(log => log.Field(GetField(sorting), sortOrder))
.From(skipCount)
.Size(maxResultCount),
cancellationToken);
return _objectMapper.Map<List<SerilogInfo>, List<LogInfo>>(response.Documents.ToList());
}
protected virtual List<Func<QueryContainerDescriptor<SerilogInfo>, QueryContainer>> BuildQueryDescriptor(
DateTime? startTime = null,
DateTime? endTime = null,
Microsoft.Extensions.Logging.LogLevel? level = null,
string machineName = null,
string environment = null,
string application = null,
string context = null,
string requestId = null,
string requestPath = null,
string correlationId = null,
int? processId = null,
int? threadId = null,
bool? hasException = null)
{
var querys = new List<Func<QueryContainerDescriptor<SerilogInfo>, QueryContainer>>();
if (_currentTenant.IsAvailable)
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(SerilogInfo.Fields.TenantId))).Value(_currentTenant.GetId())));
}
if (startTime.HasValue)
{
querys.Add((log) => log.DateRange((q) => q.Field(GetField(nameof(SerilogInfo.TimeStamp))).GreaterThanOrEquals(startTime)));
}
if (endTime.HasValue)
{
querys.Add((log) => log.DateRange((q) => q.Field(GetField(nameof(SerilogInfo.TimeStamp))).LessThanOrEquals(endTime)));
}
if (level.HasValue)
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(SerilogInfo.Level))).Value(level.ToString())));
}
if (!machineName.IsNullOrWhiteSpace())
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(SerilogInfo.Fields.MachineName))).Value(machineName)));
}
if (!environment.IsNullOrWhiteSpace())
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(SerilogInfo.Fields.Environment))).Value(environment)));
}
if (!application.IsNullOrWhiteSpace())
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(SerilogInfo.Fields.Application))).Value(application)));
}
if (!context.IsNullOrWhiteSpace())
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(SerilogInfo.Fields.Context))).Value(context)));
}
if (!requestId.IsNullOrWhiteSpace())
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(SerilogInfo.Fields.RequestId))).Value(requestId)));
}
if (!requestPath.IsNullOrWhiteSpace())
{
// 模糊匹配
querys.Add((log) => log.MatchPhrasePrefix((q) => q.Field(f => f.Fields.RequestPath).Query(requestPath)));
}
if (!correlationId.IsNullOrWhiteSpace())
{
querys.Add((log) => log.MatchPhrase((q) => q.Field(GetField(nameof(SerilogInfo.Fields.CorrelationId))).Query(correlationId)));
}
if (processId.HasValue)
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(SerilogInfo.Fields.ProcessId))).Value(processId)));
}
if (threadId.HasValue)
{
querys.Add((log) => log.Term((q) => q.Field(GetField(nameof(SerilogInfo.Fields.ThreadId))).Value(threadId)));
}
if (hasException.HasValue)
{
if (hasException.Value)
{
/* exceptions字段则就是有异常信息
* "exists": {
"field": "exceptions"
}
*/
querys.Add(
(q) => q.Exists(
(e) => e.Field("exceptions")));
}
else
{
// 不存在 exceptions字段就是没有异常信息的消息
/*
* "bool": {
"must_not": [
{
"exists": {
"field": "exceptions"
}
}
]
}
*/
querys.Add(
(q) => q.Bool(
(b) => b.MustNot(
(m) => m.Exists(
(e) => e.Field("exceptions")))));
}
}
return querys;
}
protected virtual string CreateIndex(DateTimeOffset? offset = null)
{
if (!offset.HasValue)
{
return IndexFormatRegex.Replace(_options.IndexFormat, @"$1*$2");
}
return string.Format(_options.IndexFormat, offset.Value).ToLowerInvariant();
}
private readonly static IDictionary<string, string> _fieldMaps = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase)
{
{ "timestamp", "@timestamp" },
{ "level", "level.keyword" },
{ "machinename", $"fields.{AbpLoggingEnricherPropertyNames.MachineName}.keyword" },
{ "environment", $"fields.{AbpLoggingEnricherPropertyNames.EnvironmentName}.keyword" },
{ "application", $"fields.{AbpSerilogEnrichersConsts.ApplicationNamePropertyName}.keyword" },
{ "context", "fields.Context.keyword" },
{ "actionid", "fields.ActionId.keyword" },
{ "actionname", "fields.ActionName.keyword" },
{ "requestid", "fields.RequestId.keyword" },
{ "requestpath", "fields.RequestPath.keyword" },
{ "connectionid", "fields.ConnectionId.keyword" },
{ "correlationid", "fields.CorrelationId.keyword" },
{ "clientid", "fields.ClientId.keyword" },
{ "userid", "fields.UserId.keyword" },
{ "processid", "fields.ProcessId" },
{ "threadid", "fields.ThreadId" },
{ "id", $"fields.{AbpSerilogUniqueIdConsts.UniqueIdPropertyName}" },
{ "uniqueid", $"fields.{AbpSerilogUniqueIdConsts.UniqueIdPropertyName}" },
};
protected virtual string GetField(string field)
{
foreach (var fieldMap in _fieldMaps)
{
if (field.ToLowerInvariant().Contains(fieldMap.Key))
{
return fieldMap.Value;
}
}
return field;
}
}
}

26
modules/logging/Sanhe.Abp.Logging.Serilog.Elasticsearch/Sanhe/Abp/AuditLogging/Serilog/Elasticsearch/SerilogException.cs

@ -0,0 +1,26 @@
namespace Sanhe.Abp.AuditLogging.Serilog.Elasticsearch
{
public class SerilogException
{
[Nest.PropertyName("SourceContext")]
public int Depth { get; set; }
[Nest.PropertyName("ClassName")]
public string Class { get; set; }
[Nest.PropertyName("Message")]
public string Message { get; set; }
[Nest.PropertyName("Source")]
public string Source { get; set; }
[Nest.PropertyName("StackTraceString")]
public string StackTrace { get; set; }
[Nest.PropertyName("HResult")]
public int HResult { get; set; }
[Nest.PropertyName("HelpURL")]
public string HelpURL { get; set; }
}
}

58
modules/logging/Sanhe.Abp.Logging.Serilog.Elasticsearch/Sanhe/Abp/AuditLogging/Serilog/Elasticsearch/SerilogField.cs

@ -0,0 +1,58 @@
using Sanhe.Abp.Logging;
using Sanhe.Abp.Serilog.Enrichers.Application;
using Sanhe.Abp.Serilog.Enrichers.UniqueId;
using System;
namespace Sanhe.Abp.AuditLogging.Serilog.Elasticsearch
{
public class SerilogField
{
[Nest.PropertyName(AbpSerilogUniqueIdConsts.UniqueIdPropertyName)]
public long UniqueId { get; set; }
[Nest.PropertyName(AbpLoggingEnricherPropertyNames.MachineName)]
public string MachineName { get; set; }
[Nest.PropertyName(AbpLoggingEnricherPropertyNames.EnvironmentName)]
public string Environment { get; set; }
[Nest.PropertyName(AbpSerilogEnrichersConsts.ApplicationNamePropertyName)]
public string Application { get; set; }
[Nest.PropertyName("SourceContext")]
public string Context { get; set; }
[Nest.PropertyName("ActionId")]
public string ActionId { get; set; }
[Nest.PropertyName("ActionName")]
public string ActionName { get; set; }
[Nest.PropertyName("RequestId")]
public string RequestId { get; set; }
[Nest.PropertyName("RequestPath")]
public string RequestPath { get; set; }
[Nest.PropertyName("ConnectionId")]
public string ConnectionId { get; set; }
[Nest.PropertyName("CorrelationId")]
public string CorrelationId { get; set; }
[Nest.PropertyName("ClientId")]
public string ClientId { get; set; }
[Nest.PropertyName("UserId")]
public string UserId { get; set; }
[Nest.PropertyName("TenantId")]
public Guid? TenantId { get; set; }
[Nest.PropertyName("ProcessId")]
public int ProcessId { get; set; }
[Nest.PropertyName("ThreadId")]
public int ThreadId { get; set; }
}
}

26
modules/logging/Sanhe.Abp.Logging.Serilog.Elasticsearch/Sanhe/Abp/AuditLogging/Serilog/Elasticsearch/SerilogInfo.cs

@ -0,0 +1,26 @@
using Microsoft.Extensions.Logging;
using Serilog.Formatting.Elasticsearch;
using System;
using System.Collections.Generic;
namespace Sanhe.Abp.AuditLogging.Serilog.Elasticsearch
{
[Serializable]
public class SerilogInfo
{
[Nest.PropertyName(ElasticsearchJsonFormatter.TimestampPropertyName)]
public DateTime TimeStamp { get; set; }
[Nest.PropertyName(ElasticsearchJsonFormatter.LevelPropertyName)]
public LogLevel Level { get; set; }
[Nest.PropertyName(ElasticsearchJsonFormatter.RenderedMessagePropertyName)]
public string Message { get; set; }
[Nest.PropertyName("fields")]
public SerilogField Fields { get; set; }
[Nest.PropertyName("exceptions")]
public List<SerilogException> Exceptions { get; set; }
}
}

3
modules/logging/Sanhe.Abp.Logging/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

15
modules/logging/Sanhe.Abp.Logging/README.md

@ -0,0 +1,15 @@
# LINGYUN.Abp.Logging
日志基础模块
定义 ILoggingManager 接口, 实现日志信息查询
## 模块引用
```csharp
[DependsOn(typeof(AbpLoggingModule))]
public class YouProjectModule : AbpModule
{
// other
}
```

14
modules/logging/Sanhe.Abp.Logging/Sanhe.Abp.Logging.csproj

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Core" Version="$(VoloAbpVersion)" />
</ItemGroup>
</Project>

8
modules/logging/Sanhe.Abp.Logging/Sanhe/Abp/Logging/AbpLoggingEnricherPropertyNames.cs

@ -0,0 +1,8 @@
namespace Sanhe.Abp.Logging
{
public class AbpLoggingEnricherPropertyNames
{
public const string MachineName = "MachineName";
public const string EnvironmentName = "EnvironmentName";
}
}

15
modules/logging/Sanhe.Abp.Logging/Sanhe/Abp/Logging/AbpLoggingModule.cs

@ -0,0 +1,15 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
namespace Sanhe.Abp.Logging
{
public class AbpLoggingModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
Configure<AbpLoggingEnricherPropertyNames>(configuration.GetSection("Logging"));
}
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save