aury-boot 0.0.39__tar.gz → 0.0.40__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. {aury_boot-0.0.39 → aury_boot-0.0.40}/PKG-INFO +10 -4
  2. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/_version.py +2 -2
  3. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/adapter/http.py +17 -6
  4. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/app/base.py +1 -0
  5. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/app/components.py +81 -2
  6. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/config/settings.py +73 -0
  7. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/init.py +20 -0
  8. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/pkg.py +31 -1
  9. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/aury_docs/00-overview.md.tpl +1 -0
  10. aury_boot-0.0.40/aury/boot/commands/templates/project/aury_docs/18-monitoring-profiling.md.tpl +239 -0
  11. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/env_templates/monitoring.tpl +15 -0
  12. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/common/logging/setup.py +8 -3
  13. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/database/manager.py +6 -4
  14. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/monitoring/__init__.py +10 -2
  15. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/monitoring/alerting/notifiers/feishu.py +32 -16
  16. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/monitoring/alerting/notifiers/webhook.py +14 -13
  17. aury_boot-0.0.40/aury/boot/infrastructure/monitoring/profiling/__init__.py +573 -0
  18. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/scheduler/manager.py +15 -3
  19. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/toolkit/http/__init__.py +180 -85
  20. {aury_boot-0.0.39 → aury_boot-0.0.40}/pyproject.toml +14 -3
  21. {aury_boot-0.0.39 → aury_boot-0.0.40}/.gitignore +0 -0
  22. {aury_boot-0.0.39 → aury_boot-0.0.40}/README.md +0 -0
  23. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/__init__.py +0 -0
  24. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/__init__.py +0 -0
  25. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/adapter/__init__.py +0 -0
  26. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/adapter/base.py +0 -0
  27. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/adapter/config.py +0 -0
  28. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/adapter/decorators.py +0 -0
  29. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/adapter/exceptions.py +0 -0
  30. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/app/__init__.py +0 -0
  31. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/app/middlewares.py +0 -0
  32. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/app/startup.py +0 -0
  33. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/config/__init__.py +0 -0
  34. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/config/multi_instance.py +0 -0
  35. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/constants/__init__.py +0 -0
  36. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/constants/components.py +0 -0
  37. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/constants/scheduler.py +0 -0
  38. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/constants/service.py +0 -0
  39. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/errors/__init__.py +0 -0
  40. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/errors/chain.py +0 -0
  41. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/errors/codes.py +0 -0
  42. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/errors/exceptions.py +0 -0
  43. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/errors/handlers.py +0 -0
  44. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/errors/response.py +0 -0
  45. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/interfaces/__init__.py +0 -0
  46. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/interfaces/egress.py +0 -0
  47. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/interfaces/ingress.py +0 -0
  48. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/middleware/__init__.py +0 -0
  49. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/middleware/logging.py +0 -0
  50. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/migrations/__init__.py +0 -0
  51. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/migrations/manager.py +0 -0
  52. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/migrations/setup.py +0 -0
  53. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/rpc/__init__.py +0 -0
  54. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/rpc/base.py +0 -0
  55. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/rpc/client.py +0 -0
  56. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/rpc/discovery.py +0 -0
  57. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/scheduler/__init__.py +0 -0
  58. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/scheduler/runner.py +0 -0
  59. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/application/server/__init__.py +0 -0
  60. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/__init__.py +0 -0
  61. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/add.py +0 -0
  62. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/app.py +0 -0
  63. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/config.py +0 -0
  64. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/docker.py +0 -0
  65. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/docs.py +0 -0
  66. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/generate.py +0 -0
  67. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/migrate/__init__.py +0 -0
  68. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/migrate/app.py +0 -0
  69. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/migrate/commands.py +0 -0
  70. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/scheduler.py +0 -0
  71. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/server/__init__.py +0 -0
  72. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/server/app.py +0 -0
  73. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/generate/api.py.tpl +0 -0
  74. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/generate/model.py.tpl +0 -0
  75. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/generate/repository.py.tpl +0 -0
  76. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/generate/schema.py.tpl +0 -0
  77. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/generate/service.py.tpl +0 -0
  78. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/AGENTS.md.tpl +0 -0
  79. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/README.md.tpl +0 -0
  80. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/admin_console_init.py.tpl +0 -0
  81. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/alert_rules.example.yaml.tpl +0 -0
  82. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/aury_docs/01-model.md.tpl +0 -0
  83. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/aury_docs/02-repository.md.tpl +0 -0
  84. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/aury_docs/03-service.md.tpl +0 -0
  85. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/aury_docs/04-schema.md.tpl +0 -0
  86. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/aury_docs/05-api.md.tpl +0 -0
  87. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/aury_docs/06-exception.md.tpl +0 -0
  88. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/aury_docs/07-cache.md.tpl +0 -0
  89. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/aury_docs/08-scheduler.md.tpl +0 -0
  90. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/aury_docs/09-tasks.md.tpl +0 -0
  91. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/aury_docs/10-storage.md.tpl +0 -0
  92. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/aury_docs/11-logging.md.tpl +0 -0
  93. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/aury_docs/12-admin.md.tpl +0 -0
  94. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/aury_docs/13-channel.md.tpl +0 -0
  95. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/aury_docs/14-mq.md.tpl +0 -0
  96. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/aury_docs/15-events.md.tpl +0 -0
  97. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/aury_docs/16-adapter.md.tpl +0 -0
  98. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/aury_docs/17-alerting.md.tpl +0 -0
  99. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/aury_docs/99-cli.md.tpl +0 -0
  100. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/config.py.tpl +0 -0
  101. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/conftest.py.tpl +0 -0
  102. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/env_templates/_header.tpl +0 -0
  103. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/env_templates/admin.tpl +0 -0
  104. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/env_templates/cache.tpl +0 -0
  105. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/env_templates/database.tpl +0 -0
  106. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/env_templates/log.tpl +0 -0
  107. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/env_templates/messaging.tpl +0 -0
  108. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/env_templates/rpc.tpl +0 -0
  109. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/env_templates/scheduler.tpl +0 -0
  110. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/env_templates/service.tpl +0 -0
  111. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/env_templates/storage.tpl +0 -0
  112. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/env_templates/third_party.tpl +0 -0
  113. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/gitignore.tpl +0 -0
  114. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/main.py.tpl +0 -0
  115. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/modules/api.py.tpl +0 -0
  116. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/modules/exceptions.py.tpl +0 -0
  117. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/modules/schedules.py.tpl +0 -0
  118. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/templates/project/modules/tasks.py.tpl +0 -0
  119. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/commands/worker.py +0 -0
  120. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/common/__init__.py +0 -0
  121. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/common/exceptions/__init__.py +0 -0
  122. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/common/i18n/__init__.py +0 -0
  123. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/common/i18n/translator.py +0 -0
  124. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/common/logging/__init__.py +0 -0
  125. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/common/logging/context.py +0 -0
  126. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/common/logging/decorators.py +0 -0
  127. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/common/logging/format.py +0 -0
  128. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/contrib/__init__.py +0 -0
  129. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/contrib/admin_console/__init__.py +0 -0
  130. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/contrib/admin_console/auth.py +0 -0
  131. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/contrib/admin_console/discovery.py +0 -0
  132. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/contrib/admin_console/install.py +0 -0
  133. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/contrib/admin_console/utils.py +0 -0
  134. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/domain/__init__.py +0 -0
  135. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/domain/exceptions/__init__.py +0 -0
  136. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/domain/models/__init__.py +0 -0
  137. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/domain/models/base.py +0 -0
  138. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/domain/models/mixins.py +0 -0
  139. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/domain/models/models.py +0 -0
  140. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/domain/pagination/__init__.py +0 -0
  141. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/domain/repository/__init__.py +0 -0
  142. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/domain/repository/impl.py +0 -0
  143. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/domain/repository/interceptors.py +0 -0
  144. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/domain/repository/interface.py +0 -0
  145. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/domain/repository/query_builder.py +0 -0
  146. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/domain/service/__init__.py +0 -0
  147. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/domain/service/base.py +0 -0
  148. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/domain/transaction/__init__.py +0 -0
  149. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/__init__.py +0 -0
  150. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/cache/__init__.py +0 -0
  151. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/cache/backends.py +0 -0
  152. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/cache/base.py +0 -0
  153. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/cache/exceptions.py +0 -0
  154. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/cache/factory.py +0 -0
  155. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/cache/manager.py +0 -0
  156. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/cache/memory.py +0 -0
  157. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/cache/redis.py +0 -0
  158. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/channel/__init__.py +0 -0
  159. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/channel/backends/__init__.py +0 -0
  160. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/channel/backends/broadcaster.py +0 -0
  161. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/channel/base.py +0 -0
  162. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/channel/manager.py +0 -0
  163. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/clients/__init__.py +0 -0
  164. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/clients/rabbitmq/__init__.py +0 -0
  165. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/clients/rabbitmq/config.py +0 -0
  166. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/clients/rabbitmq/manager.py +0 -0
  167. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/clients/redis/__init__.py +0 -0
  168. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/clients/redis/config.py +0 -0
  169. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/clients/redis/manager.py +0 -0
  170. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/database/__init__.py +0 -0
  171. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/database/config.py +0 -0
  172. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/database/exceptions.py +0 -0
  173. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/database/query_tools/__init__.py +0 -0
  174. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/database/strategies/__init__.py +0 -0
  175. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/di/__init__.py +0 -0
  176. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/di/container.py +0 -0
  177. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/events/__init__.py +0 -0
  178. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/events/backends/__init__.py +0 -0
  179. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/events/backends/broadcaster.py +0 -0
  180. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/events/backends/rabbitmq.py +0 -0
  181. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/events/base.py +0 -0
  182. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/events/manager.py +0 -0
  183. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/events/middleware.py +0 -0
  184. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/monitoring/alerting/__init__.py +0 -0
  185. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/monitoring/alerting/aggregator.py +0 -0
  186. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/monitoring/alerting/events.py +0 -0
  187. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/monitoring/alerting/manager.py +0 -0
  188. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/monitoring/alerting/notifiers/__init__.py +0 -0
  189. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/monitoring/alerting/notifiers/base.py +0 -0
  190. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/monitoring/alerting/rules.py +0 -0
  191. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/monitoring/health/__init__.py +0 -0
  192. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/monitoring/tracing/__init__.py +0 -0
  193. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/monitoring/tracing/context.py +0 -0
  194. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/monitoring/tracing/logging.py +0 -0
  195. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/monitoring/tracing/processor.py +0 -0
  196. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/monitoring/tracing/provider.py +0 -0
  197. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/monitoring/tracing/tracing.py +0 -0
  198. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/mq/__init__.py +0 -0
  199. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/mq/backends/__init__.py +0 -0
  200. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/mq/backends/rabbitmq.py +0 -0
  201. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/mq/backends/redis.py +0 -0
  202. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/mq/backends/redis_stream.py +0 -0
  203. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/mq/base.py +0 -0
  204. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/mq/manager.py +0 -0
  205. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/scheduler/__init__.py +0 -0
  206. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/scheduler/exceptions.py +0 -0
  207. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/storage/__init__.py +0 -0
  208. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/storage/base.py +0 -0
  209. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/storage/exceptions.py +0 -0
  210. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/storage/factory.py +0 -0
  211. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/tasks/__init__.py +0 -0
  212. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/tasks/config.py +0 -0
  213. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/tasks/constants.py +0 -0
  214. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/tasks/exceptions.py +0 -0
  215. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/infrastructure/tasks/manager.py +0 -0
  216. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/testing/__init__.py +0 -0
  217. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/testing/base.py +0 -0
  218. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/testing/client.py +0 -0
  219. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/testing/factory.py +0 -0
  220. {aury_boot-0.0.39 → aury_boot-0.0.40}/aury/boot/toolkit/__init__.py +0 -0
@@ -1,8 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aury-boot
3
- Version: 0.0.39
3
+ Version: 0.0.40
4
4
  Summary: Aury Boot - 基于 FastAPI 生态的企业级 API 开发框架
5
5
  Requires-Python: >=3.13
6
+ Requires-Dist: aiohttp>=3.11.0
6
7
  Requires-Dist: alembic>=1.17.2
7
8
  Requires-Dist: aury-sdk-storage[aws]>=0.0.6
8
9
  Requires-Dist: babel>=2.17.0
@@ -10,7 +11,6 @@ Requires-Dist: broadcaster[redis]>=0.3.1
10
11
  Requires-Dist: faker>=38.2.0
11
12
  Requires-Dist: fastapi>=0.122.0
12
13
  Requires-Dist: greenlet>=3.2.4
13
- Requires-Dist: httpx>=0.28.1
14
14
  Requires-Dist: loguru>=0.7.3
15
15
  Requires-Dist: pydantic-settings>=2.12.0
16
16
  Requires-Dist: pydantic>=2.12.5
@@ -30,10 +30,13 @@ Requires-Dist: asyncpg>=0.31.0; extra == 'all'
30
30
  Requires-Dist: aury-sdk-storage[aws]>=0.0.1; extra == 'all'
31
31
  Requires-Dist: dramatiq>=1.18.0; extra == 'all'
32
32
  Requires-Dist: pika>=1.3.2; extra == 'all'
33
+ Requires-Dist: psutil>=7.0.0; extra == 'all'
34
+ Requires-Dist: pyroscope-io>=0.8.7; extra == 'all'
33
35
  Requires-Dist: redis>=7.1.0; extra == 'all'
34
36
  Provides-Extra: broadcaster
35
37
  Requires-Dist: broadcaster[redis]>=0.3.1; extra == 'broadcaster'
36
38
  Provides-Extra: dev
39
+ Requires-Dist: httpx>=0.28.1; extra == 'dev'
37
40
  Requires-Dist: mypy>=1.19.0; extra == 'dev'
38
41
  Requires-Dist: pytest-asyncio>=1.3.0; extra == 'dev'
39
42
  Requires-Dist: pytest-cov>=7.0.0; extra == 'dev'
@@ -47,14 +50,17 @@ Provides-Extra: mysql
47
50
  Requires-Dist: aiomysql>=0.3.2; extra == 'mysql'
48
51
  Provides-Extra: otel
49
52
  Requires-Dist: opentelemetry-api>=1.25.0; extra == 'otel'
53
+ Requires-Dist: opentelemetry-instrumentation-aiohttp-client>=0.46b0; extra == 'otel'
50
54
  Requires-Dist: opentelemetry-instrumentation-fastapi>=0.46b0; extra == 'otel'
51
- Requires-Dist: opentelemetry-instrumentation-httpx>=0.46b0; extra == 'otel'
52
55
  Requires-Dist: opentelemetry-instrumentation-sqlalchemy>=0.46b0; extra == 'otel'
53
56
  Requires-Dist: opentelemetry-sdk>=1.25.0; extra == 'otel'
54
57
  Provides-Extra: otel-exporter
55
58
  Requires-Dist: opentelemetry-exporter-otlp>=1.25.0; extra == 'otel-exporter'
56
59
  Provides-Extra: postgres
57
60
  Requires-Dist: asyncpg>=0.31.0; extra == 'postgres'
61
+ Provides-Extra: profiling
62
+ Requires-Dist: psutil>=7.0.0; extra == 'profiling'
63
+ Requires-Dist: pyroscope-io>=0.8.7; extra == 'profiling'
58
64
  Provides-Extra: rabbitmq
59
65
  Requires-Dist: amqp>=5.3.1; extra == 'rabbitmq'
60
66
  Provides-Extra: recommended
@@ -64,8 +70,8 @@ Requires-Dist: asyncpg>=0.31.0; extra == 'recommended'
64
70
  Requires-Dist: aury-sdk-storage[aws]>=0.0.1; extra == 'recommended'
65
71
  Requires-Dist: dramatiq>=1.18.0; extra == 'recommended'
66
72
  Requires-Dist: opentelemetry-api>=1.25.0; extra == 'recommended'
73
+ Requires-Dist: opentelemetry-instrumentation-aiohttp-client>=0.46b0; extra == 'recommended'
67
74
  Requires-Dist: opentelemetry-instrumentation-fastapi>=0.46b0; extra == 'recommended'
68
- Requires-Dist: opentelemetry-instrumentation-httpx>=0.46b0; extra == 'recommended'
69
75
  Requires-Dist: opentelemetry-instrumentation-sqlalchemy>=0.46b0; extra == 'recommended'
70
76
  Requires-Dist: opentelemetry-sdk>=1.25.0; extra == 'recommended'
71
77
  Requires-Dist: redis>=7.1.0; extra == 'recommended'
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.0.39'
32
- __version_tuple__ = version_tuple = (0, 0, 39)
31
+ __version__ = version = '0.0.40'
32
+ __version_tuple__ = version_tuple = (0, 0, 40)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -25,10 +25,14 @@ from __future__ import annotations
25
25
 
26
26
  from typing import Any
27
27
 
28
- import httpx
29
-
30
28
  from aury.boot.common.logging import get_trace_id, logger
31
- from aury.boot.toolkit.http import HttpClient, RetryConfig
29
+ from aury.boot.toolkit.http import (
30
+ HttpClient,
31
+ HttpNetworkError,
32
+ HttpStatusError,
33
+ HttpTimeoutError,
34
+ RetryConfig,
35
+ )
32
36
 
33
37
  from .base import BaseAdapter
34
38
  from .config import AdapterSettings
@@ -185,7 +189,7 @@ class HttpAdapter(BaseAdapter):
185
189
  json: JSON 请求体
186
190
  data: 表单数据
187
191
  files: 上传文件
188
- **kwargs: 其他 httpx 参数
192
+ **kwargs: 其他 aiohttp 参数
189
193
 
190
194
  Returns:
191
195
  dict: 响应 JSON
@@ -228,7 +232,7 @@ class HttpAdapter(BaseAdapter):
228
232
  "content": response.text,
229
233
  }
230
234
 
231
- except httpx.TimeoutException as exc:
235
+ except HttpTimeoutError as exc:
232
236
  raise AdapterTimeoutError(
233
237
  f"请求超时: {method} {path}",
234
238
  adapter_name=self.name,
@@ -236,7 +240,7 @@ class HttpAdapter(BaseAdapter):
236
240
  cause=exc,
237
241
  ) from exc
238
242
 
239
- except httpx.HTTPStatusError as exc:
243
+ except HttpStatusError as exc:
240
244
  # HTTP 错误状态码
241
245
  response = exc.response
242
246
  try:
@@ -255,6 +259,13 @@ class HttpAdapter(BaseAdapter):
255
259
  cause=exc,
256
260
  ) from exc
257
261
 
262
+ except HttpNetworkError as exc:
263
+ raise AdapterError(
264
+ f"网络错误: {method} {path} - {exc}",
265
+ adapter_name=self.name,
266
+ cause=exc,
267
+ ) from exc
268
+
258
269
  except Exception as exc:
259
270
  raise AdapterError(
260
271
  f"请求失败: {method} {path} - {type(exc).__name__}: {exc}",
@@ -313,6 +313,7 @@ class FoundationApp(FastAPI):
313
313
  enable_file_rotation=config.log.enable_file_rotation,
314
314
  enable_console=config.log.enable_console,
315
315
  logger_levels=logger_levels,
316
+ enqueue=config.log.enqueue,
316
317
  )
317
318
 
318
319
  # 注册 access 日志(HTTP 请求日志)
@@ -320,11 +320,24 @@ class SchedulerComponent(Component):
320
320
  url = scheduler_config.jobstore_url
321
321
  if url.startswith("redis://"):
322
322
  try:
323
+ from urllib.parse import urlparse
323
324
  from apscheduler.jobstores.redis import RedisJobStore
325
+
326
+ # 解析 Redis URL
327
+ parsed = urlparse(url)
328
+ redis_kwargs: dict = {
329
+ "host": parsed.hostname or "localhost",
330
+ "port": parsed.port or 6379,
331
+ }
332
+ if parsed.password:
333
+ redis_kwargs["password"] = parsed.password
334
+ if parsed.path and parsed.path != "/":
335
+ redis_kwargs["db"] = int(parsed.path.lstrip("/") or 0)
336
+
324
337
  scheduler_kwargs["jobstores"] = {
325
- "default": RedisJobStore.from_url(url)
338
+ "default": RedisJobStore(**redis_kwargs)
326
339
  }
327
- logger.info(f"调度器使用 Redis 存储: {url.split('@')[-1]}")
340
+ logger.info(f"调度器使用 Redis 存储: {parsed.hostname}:{parsed.port}")
328
341
  except ImportError:
329
342
  logger.warning("Redis jobstore 需要安装 redis: pip install redis")
330
343
  else:
@@ -766,6 +779,70 @@ class AlertComponent(Component):
766
779
  pass
767
780
 
768
781
 
782
+ class ProfilingComponent(Component):
783
+ """Profiling 组件。
784
+
785
+ 提供持续性能分析和事件循环阻塞检测:
786
+ - Pyroscope:持续采样生成火焰图
787
+ - 阻塞检测:检测同步代码阻塞事件循环
788
+ """
789
+
790
+ name = "profiling"
791
+ enabled = True
792
+ depends_on: ClassVar[list[str]] = ["alert"] # 告警依赖
793
+
794
+ def can_enable(self, config: BaseConfig) -> bool:
795
+ """当启用 Pyroscope 或阻塞检测时启用。"""
796
+ return self.enabled and (
797
+ config.profiling.enabled or config.profiling.blocking_detector_enabled
798
+ )
799
+
800
+ async def setup(self, app: FoundationApp, config: BaseConfig) -> None:
801
+ """初始化 Profiling 组件。"""
802
+ try:
803
+ from aury.boot.infrastructure.monitoring.profiling import (
804
+ ProfilingConfig,
805
+ ProfilingManager,
806
+ )
807
+
808
+ profiling_config = ProfilingConfig(
809
+ enabled=config.profiling.enabled,
810
+ pyroscope_endpoint=config.profiling.pyroscope_endpoint,
811
+ pyroscope_auth_token=config.profiling.pyroscope_auth_token,
812
+ service_name=config.service.name,
813
+ environment=config.service.environment,
814
+ blocking_detector_enabled=config.profiling.blocking_detector_enabled,
815
+ blocking_check_interval_ms=config.profiling.blocking_check_interval_ms,
816
+ blocking_threshold_ms=config.profiling.blocking_threshold_ms,
817
+ blocking_severe_threshold_ms=config.profiling.blocking_severe_threshold_ms,
818
+ blocking_alert_enabled=config.profiling.blocking_alert_enabled,
819
+ blocking_alert_cooldown_seconds=config.profiling.blocking_alert_cooldown_seconds,
820
+ blocking_max_history=config.profiling.blocking_max_history,
821
+ tags=config.profiling.pyroscope_tags,
822
+ )
823
+
824
+ manager = ProfilingManager.get_instance()
825
+ manager.configure(profiling_config)
826
+ await manager.start()
827
+
828
+ # 保存到 app.state
829
+ app.state.profiling_manager = manager
830
+
831
+ except ImportError as e:
832
+ logger.warning(f"Profiling 依赖未安装,跳过初始化: {e}")
833
+ except Exception as e:
834
+ logger.warning(f"Profiling 初始化失败(非关键): {e}")
835
+
836
+ async def teardown(self, app: FoundationApp) -> None:
837
+ """停止 Profiling 组件。"""
838
+ try:
839
+ manager = getattr(app.state, "profiling_manager", None)
840
+ if manager:
841
+ await manager.stop()
842
+ except Exception as e:
843
+ logger.warning(f"Profiling 关闭失败: {e}")
844
+
845
+
769
846
  class EventBusComponent(Component):
770
847
  """事件总线组件。
771
848
 
@@ -815,6 +892,7 @@ FoundationApp.plugins = [
815
892
  # 设置默认组件
816
893
  FoundationApp.components = [
817
894
  AlertComponent, # 最先初始化告警管理器
895
+ ProfilingComponent, # Profiling 依赖告警
818
896
  DatabaseComponent,
819
897
  MigrationComponent,
820
898
  AdminConsoleComponent,
@@ -837,6 +915,7 @@ __all__ = [
837
915
  "EventBusComponent",
838
916
  "MessageQueueComponent",
839
917
  "MigrationComponent",
918
+ "ProfilingComponent",
840
919
  "SchedulerComponent",
841
920
  "StorageComponent",
842
921
  "TaskComponent",
@@ -401,6 +401,14 @@ class LogSettings(BaseModel):
401
401
  default=False,
402
402
  description="是否记录 WebSocket 消息内容(注意性能和敏感数据)"
403
403
  )
404
+ enqueue: bool = Field(
405
+ default=False,
406
+ description=(
407
+ "是否启用多进程安全队列。"
408
+ "启用后日志通过 multiprocessing.Queue 传输,"
409
+ "可能导致事件循环阻塞。建议在 asyncio 应用中保持 False"
410
+ )
411
+ )
404
412
 
405
413
 
406
414
  class ServiceSettings(BaseModel):
@@ -741,6 +749,70 @@ class AlertSettings(BaseModel):
741
749
  return self._notifiers
742
750
 
743
751
 
752
+ class ProfilingSettings(BaseModel):
753
+ """Profiling 配置。
754
+
755
+ 环境变量格式: PROFILING__{FIELD}
756
+ 示例: PROFILING__ENABLED, PROFILING__PYROSCOPE_ENDPOINT
757
+
758
+ 功能说明:
759
+ - Pyroscope:持续采样生成火焰图(需安装 pyroscope-io)
760
+ - 阻塞检测:检测同步代码阻塞事件循环(需安装 psutil)
761
+ """
762
+
763
+ # Pyroscope 持续 Profiling
764
+ enabled: bool = Field(
765
+ default=False,
766
+ description="是否启用 Pyroscope 持续 profiling"
767
+ )
768
+ pyroscope_endpoint: str | None = Field(
769
+ default=None,
770
+ description="Pyroscope 服务端点(如 http://pyroscope:4040)"
771
+ )
772
+ pyroscope_auth_token: str | None = Field(
773
+ default=None,
774
+ description="Pyroscope 认证 token(可选)"
775
+ )
776
+ pyroscope_sample_rate: int = Field(
777
+ default=100,
778
+ description="Pyroscope 采样率 (Hz),降低可减少开销"
779
+ )
780
+ pyroscope_tags: dict[str, str] = Field(
781
+ default_factory=dict,
782
+ description="Pyroscope 自定义标签"
783
+ )
784
+
785
+ # 事件循环阻塞检测
786
+ blocking_detector_enabled: bool = Field(
787
+ default=False,
788
+ description="是否启用事件循环阻塞检测"
789
+ )
790
+ blocking_check_interval_ms: float = Field(
791
+ default=100,
792
+ description="阻塞检测间隔 (ms)"
793
+ )
794
+ blocking_threshold_ms: float = Field(
795
+ default=100,
796
+ description="阻塞阈值 (ms),超过此时间记录阻塞事件"
797
+ )
798
+ blocking_severe_threshold_ms: float = Field(
799
+ default=500,
800
+ description="严重阻塞阈值 (ms),超过此时间触发严重告警"
801
+ )
802
+ blocking_alert_enabled: bool = Field(
803
+ default=True,
804
+ description="检测到阻塞时是否发送告警"
805
+ )
806
+ blocking_alert_cooldown_seconds: float = Field(
807
+ default=60,
808
+ description="阻塞告警冷却时间 (秒),避免告警风暴"
809
+ )
810
+ blocking_max_history: int = Field(
811
+ default=50,
812
+ description="保留的阻塞事件历史数量"
813
+ )
814
+
815
+
744
816
  class MigrationSettings(BaseModel):
745
817
  """数据库迁移配置。
746
818
 
@@ -1014,6 +1086,7 @@ class BaseConfig(BaseSettings):
1014
1086
  # ========== 监控告警 ==========
1015
1087
  telemetry: TelemetrySettings = Field(default_factory=TelemetrySettings)
1016
1088
  alert: AlertSettings = Field(default_factory=AlertSettings)
1089
+ profiling: ProfilingSettings = Field(default_factory=ProfilingSettings)
1017
1090
 
1018
1091
  model_config = SettingsConfigDict(
1019
1092
  case_sensitive=False,
@@ -542,6 +542,18 @@ def _collect_interactive_config() -> dict:
542
542
 
543
543
  config["features"] = features
544
544
 
545
+ # 5.5 监控配置
546
+ console.print()
547
+ console.print("[bold]📊 监控配置[/bold]")
548
+ config["with_otel"] = Confirm.ask(
549
+ " 启用 OpenTelemetry 链路追踪",
550
+ default=True,
551
+ )
552
+ config["with_profiling"] = Confirm.ask(
553
+ " 启用 Profiling (火焰图/阻塞检测)",
554
+ default=False,
555
+ )
556
+
545
557
  # 6. 开发工具
546
558
  console.print()
547
559
  config["with_dev"] = Confirm.ask(
@@ -589,6 +601,12 @@ def _build_dependency_list(config: dict) -> list[str]:
589
601
  if config.get("with_admin_console", True):
590
602
  extras.add("admin")
591
603
 
604
+ # 监控
605
+ if config.get("with_otel", True):
606
+ extras.add("otel")
607
+ if config.get("with_profiling", False):
608
+ extras.add("profiling")
609
+
592
610
  # 开发工具
593
611
  if config.get("with_dev"):
594
612
  extras.add("dev")
@@ -616,6 +634,8 @@ def _show_config_summary(config: dict) -> None:
616
634
  ("服务模式", config.get("service_mode", "api")),
617
635
  ("管理后台", "是" if config.get("with_admin_console", True) else "否"),
618
636
  ("可选功能", ", ".join(config.get("features", [])) or "无"),
637
+ ("OpenTelemetry", "是" if config.get("with_otel", True) else "否"),
638
+ ("Profiling", "是" if config.get("with_profiling", False) else "否"),
619
639
  ("开发工具", "是" if config.get("with_dev") else "否"),
620
640
  ("Docker", "是" if config.get("with_docker") else "否"),
621
641
  ]
@@ -45,6 +45,7 @@ class Category(str, Enum):
45
45
  SCHEDULER = "scheduler"
46
46
  ADMIN = "admin"
47
47
  STORAGE = "storage"
48
+ MONITORING = "monitoring"
48
49
  ECOSYSTEM = "ecosystem"
49
50
 
50
51
 
@@ -132,6 +133,29 @@ MODULES: dict[str, ModuleInfo] = {
132
133
  category=Category.STORAGE,
133
134
  deps=["aury-sdk-storage[aws]"],
134
135
  ),
136
+ # 监控
137
+ "otel": ModuleInfo(
138
+ name="otel",
139
+ desc="OpenTelemetry 链路追踪",
140
+ usage="启用 TELEMETRY__ENABLED 自动 instrument FastAPI/SQLAlchemy/httpx",
141
+ category=Category.MONITORING,
142
+ deps=["opentelemetry-api", "opentelemetry-sdk", "opentelemetry-instrumentation-fastapi",
143
+ "opentelemetry-instrumentation-sqlalchemy", "opentelemetry-instrumentation-httpx"],
144
+ ),
145
+ "otel-exporter": ModuleInfo(
146
+ name="otel-exporter",
147
+ desc="OpenTelemetry OTLP 导出器",
148
+ usage="导出 Traces/Metrics/Logs 到 Jaeger/Prometheus/Loki",
149
+ category=Category.MONITORING,
150
+ deps=["opentelemetry-exporter-otlp"],
151
+ ),
152
+ "profiling": ModuleInfo(
153
+ name="profiling",
154
+ desc="Profiling 性能分析",
155
+ usage="Pyroscope 火焰图 + 事件循环阻塞检测",
156
+ category=Category.MONITORING,
157
+ deps=["pyroscope-io", "psutil"],
158
+ ),
135
159
  # 生态包
136
160
  "storage-aws": ModuleInfo(
137
161
  name="storage-aws",
@@ -182,7 +206,12 @@ PRESETS: dict[str, PresetInfo] = {
182
206
  "full": PresetInfo(
183
207
  name="full",
184
208
  desc="完整功能(所有模块)",
185
- modules=["postgres", "redis", "tasks", "rabbitmq", "scheduler", "admin", "storage-cos"],
209
+ modules=["postgres", "redis", "tasks", "rabbitmq", "scheduler", "admin", "storage-cos", "otel", "profiling"],
210
+ ),
211
+ "monitoring": PresetInfo(
212
+ name="monitoring",
213
+ desc="完整监控(OTel + Profiling)",
214
+ modules=["otel", "otel-exporter", "profiling"],
186
215
  ),
187
216
  }
188
217
 
@@ -195,6 +224,7 @@ CATEGORY_NAMES: dict[Category, str] = {
195
224
  Category.SCHEDULER: "📦 定时调度",
196
225
  Category.ADMIN: "📦 管理后台",
197
226
  Category.STORAGE: "📦 对象存储",
227
+ Category.MONITORING: "📊 监控分析",
198
228
  Category.ECOSYSTEM: "🌐 生态包",
199
229
  }
200
230
 
@@ -60,3 +60,4 @@ CLI 命令参考请查看 [99-cli.md](./99-cli.md)。
60
60
 
61
61
  ### 监控与告警
62
62
  - [17-alerting.md](./17-alerting.md) - 告警系统(慢请求/慢SQL/异常 → 飞书)
63
+ - [18-monitoring-profiling.md](./18-monitoring-profiling.md) - 监控与 Profiling(火焰图/阻塞检测)
@@ -0,0 +1,239 @@
1
+ # 监控与 Profiling
2
+
3
+ 本文档介绍 {project_name} 项目中的监控和性能分析配置。
4
+
5
+ ## 监控能力概览
6
+
7
+ | 功能 | 用途 | 建议环境 |
8
+ |------|------|----------|
9
+ | OpenTelemetry | 链路追踪、慢请求检测 | 所有环境 |
10
+ | 告警系统 | 异常/慢请求通知 | 所有环境 |
11
+ | Pyroscope | 持续 Profiling、火焰图 | 测试/灰度 |
12
+ | 阻塞检测 | 检测同步代码阻塞协程 | 测试/按需 |
13
+
14
+ ---
15
+
16
+ ## 不同环境的最佳实践
17
+
18
+ ### 开发环境
19
+
20
+ ```bash
21
+ # .env.development
22
+ TELEMETRY__ENABLED=false
23
+ ALERT__ENABLED=false
24
+ PROFILING__ENABLED=false
25
+ PROFILING__BLOCKING_DETECTOR_ENABLED=true # 开发时检测阻塞问题
26
+ ```
27
+
28
+ ### 测试/灰度环境
29
+
30
+ ```bash
31
+ # .env.staging
32
+ TELEMETRY__ENABLED=true
33
+ TELEMETRY__TRACES_ENDPOINT=http://jaeger:4317
34
+
35
+ ALERT__ENABLED=true
36
+ ALERT__NOTIFIERS__DEFAULT__TYPE=feishu
37
+ ALERT__NOTIFIERS__DEFAULT__WEBHOOK=https://...
38
+
39
+ # 开启 Profiling 排查性能问题
40
+ PROFILING__ENABLED=true
41
+ PROFILING__PYROSCOPE_ENDPOINT=http://pyroscope:4040
42
+
43
+ PROFILING__BLOCKING_DETECTOR_ENABLED=true
44
+ ```
45
+
46
+ ### 生产环境
47
+
48
+ ```bash
49
+ # .env.production
50
+ # 链路追踪 - 必开
51
+ TELEMETRY__ENABLED=true
52
+ TELEMETRY__TRACES_ENDPOINT=http://jaeger:4317
53
+ TELEMETRY__SAMPLING_RATE=0.1 # 采样 10% 减少开销
54
+
55
+ # 告警 - 必开
56
+ ALERT__ENABLED=true
57
+ ALERT__NOTIFIERS__DEFAULT__TYPE=feishu
58
+ ALERT__NOTIFIERS__DEFAULT__WEBHOOK=https://...
59
+
60
+ # Profiling - 按需(有约 2-5% CPU 开销)
61
+ PROFILING__ENABLED=false # 出问题时临时开启
62
+ # PROFILING__PYROSCOPE_ENDPOINT=http://pyroscope:4040
63
+ # PROFILING__PYROSCOPE_SAMPLE_RATE=10 # 降低采样率减少开销
64
+
65
+ # 阻塞检测 - 按需
66
+ PROFILING__BLOCKING_DETECTOR_ENABLED=false # 出问题时临时开启
67
+ ```
68
+
69
+ ---
70
+
71
+ ## OpenTelemetry
72
+
73
+ 自动 instrument:
74
+ - FastAPI 请求
75
+ - SQLAlchemy SQL 查询
76
+ - httpx 外部调用
77
+
78
+ ### 配置
79
+
80
+ ```bash
81
+ TELEMETRY__ENABLED=true
82
+ TELEMETRY__TRACES_ENDPOINT=http://jaeger:4317 # 可选
83
+ TELEMETRY__SAMPLING_RATE=1.0 # 采样率,1.0=100%
84
+ ```
85
+
86
+ ### 手动 Span
87
+
88
+ ```python
89
+ from aury.boot.infrastructure.monitoring.tracing import span, trace_span
90
+
91
+ # 装饰器方式
92
+ @trace_span(name="call_external_api")
93
+ async def call_api():
94
+ ...
95
+
96
+ # 上下文管理器
97
+ async def process():
98
+ with span("step_1"):
99
+ await do_step_1()
100
+ with span("step_2"):
101
+ await do_step_2()
102
+ ```
103
+
104
+ ---
105
+
106
+ ## Pyroscope 持续 Profiling
107
+
108
+ 生成 CPU 火焰图,定位性能瓶颈。
109
+
110
+ ### 安装
111
+
112
+ ```bash
113
+ pip install pyroscope-io
114
+ ```
115
+
116
+ ### 配置
117
+
118
+ ```bash
119
+ PROFILING__ENABLED=true
120
+ PROFILING__PYROSCOPE_ENDPOINT=http://pyroscope:4040
121
+ PROFILING__PYROSCOPE_SAMPLE_RATE=100 # 采样率 Hz
122
+ ```
123
+
124
+ ### 部署 Pyroscope
125
+
126
+ ```yaml
127
+ # docker-compose.yml
128
+ services:
129
+ pyroscope:
130
+ image: grafana/pyroscope:latest
131
+ ports:
132
+ - "4040:4040"
133
+ ```
134
+
135
+ 访问 http://localhost:4040 查看火焰图。
136
+
137
+ ---
138
+
139
+ ## 事件循环阻塞检测
140
+
141
+ 检测同步代码阻塞 asyncio 事件循环的问题。
142
+
143
+ ### 安装
144
+
145
+ ```bash
146
+ pip install psutil
147
+ ```
148
+
149
+ ### 配置
150
+
151
+ ```bash
152
+ PROFILING__BLOCKING_DETECTOR_ENABLED=true
153
+ PROFILING__BLOCKING_THRESHOLD_MS=100 # 阻塞阈值
154
+ PROFILING__BLOCKING_SEVERE_THRESHOLD_MS=500 # 严重阈值
155
+ PROFILING__BLOCKING_ALERT_ENABLED=true # 阻塞时发送告警
156
+ PROFILING__BLOCKING_ALERT_COOLDOWN_SECONDS=60 # 告警冷却
157
+ ```
158
+
159
+ ### 工作原理
160
+
161
+ 1. 后台线程每 100ms 向事件循环投递空任务
162
+ 2. 如果响应延迟 > 阈值,说明事件循环被阻塞
163
+ 3. 自动捕获主线程调用栈 + 进程状态
164
+ 4. 发送告警(含阻塞代码位置)
165
+
166
+ ### 告警示例
167
+
168
+ ```
169
+ 事件循环阻塞(严重): 520ms
170
+
171
+ 调用栈:
172
+ app/services/sync_io.py:42 in read_file
173
+ > data = open(path).read() # 同步 IO!
174
+
175
+ 进程状态:
176
+ cpu: 95%, memory: 256MB, threads: 12
177
+ ```
178
+
179
+ ### 常见阻塞原因
180
+
181
+ - `time.sleep()` 应使用 `asyncio.sleep()`
182
+ - `open().read()` 应使用 `aiofiles`
183
+ - `requests.get()` 应使用 `httpx` 或 `aiohttp`
184
+ - CPU 密集计算 应使用 `run_in_executor()`
185
+
186
+ ---
187
+
188
+ ## 环境变量参考
189
+
190
+ ### Telemetry
191
+
192
+ | 变量 | 说明 | 默认值 |
193
+ |------|------|--------|
194
+ | `TELEMETRY__ENABLED` | 是否启用 | `false` |
195
+ | `TELEMETRY__TRACES_ENDPOINT` | Traces 导出端点 | - |
196
+ | `TELEMETRY__LOGS_ENDPOINT` | Logs 导出端点 | - |
197
+ | `TELEMETRY__METRICS_ENDPOINT` | Metrics 导出端点 | - |
198
+ | `TELEMETRY__SAMPLING_RATE` | 采样率 | `1.0` |
199
+
200
+ ### Profiling
201
+
202
+ | 变量 | 说明 | 默认值 |
203
+ |------|------|--------|
204
+ | `PROFILING__ENABLED` | 是否启用 Pyroscope | `false` |
205
+ | `PROFILING__PYROSCOPE_ENDPOINT` | Pyroscope 端点 | - |
206
+ | `PROFILING__PYROSCOPE_SAMPLE_RATE` | 采样率 (Hz) | `100` |
207
+ | `PROFILING__BLOCKING_DETECTOR_ENABLED` | 阻塞检测 | `false` |
208
+ | `PROFILING__BLOCKING_THRESHOLD_MS` | 阻塞阈值 | `100` |
209
+ | `PROFILING__BLOCKING_SEVERE_THRESHOLD_MS` | 严重阈值 | `500` |
210
+ | `PROFILING__BLOCKING_ALERT_ENABLED` | 阻塞告警 | `true` |
211
+ | `PROFILING__BLOCKING_ALERT_COOLDOWN_SECONDS` | 告警冷却 | `60` |
212
+
213
+ ---
214
+
215
+ ## 推荐的监控栈
216
+
217
+ ### 开源方案
218
+
219
+ ```
220
+ OpenTelemetry → Jaeger (Traces)
221
+ → Grafana Loki (Logs)
222
+ → Prometheus (Metrics)
223
+
224
+ Pyroscope → 火焰图
225
+ ```
226
+
227
+ ### 云服务方案
228
+
229
+ - **阿里云 ARMS** - APM + 告警
230
+ - **腾讯云 APM** - 类似
231
+ - **Datadog** - 全功能 APM
232
+ - **Sentry** - 错误监控
233
+
234
+ ---
235
+
236
+ ## 相关文档
237
+
238
+ - [17-alerting.md](./17-alerting.md) - 告警系统详细配置
239
+ - [11-logging.md](./11-logging.md) - 日志配置