clm-kernel 0.0.0__py3-none-any.whl

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 (333) hide show
  1. clm/__init__.py +230 -0
  2. clm/__main__.py +25 -0
  3. clm/cross_cutting/__init__.py +50 -0
  4. clm/cross_cutting/_test_runner.py +36 -0
  5. clm/cross_cutting/async_utils.py +25 -0
  6. clm/cross_cutting/cel_builder.py +123 -0
  7. clm/cross_cutting/cel_converter.py +697 -0
  8. clm/cross_cutting/cel_engine.py +252 -0
  9. clm/cross_cutting/cel_ops.py +72 -0
  10. clm/cross_cutting/cel_ops_db.py +157 -0
  11. clm/cross_cutting/cel_ops_files.py +99 -0
  12. clm/cross_cutting/cel_ops_state.py +71 -0
  13. clm/cross_cutting/cel_ops_strings.py +64 -0
  14. clm/cross_cutting/cel_resolver.py +63 -0
  15. clm/cross_cutting/cel_slices.py +56 -0
  16. clm/cross_cutting/cel_store.py +330 -0
  17. clm/cross_cutting/clm_logger.py +140 -0
  18. clm/cross_cutting/config/__init__.py +155 -0
  19. clm/cross_cutting/config/config_constants.py +392 -0
  20. clm/cross_cutting/config/env_parameters.py +90 -0
  21. clm/cross_cutting/config/logging.py +378 -0
  22. clm/cross_cutting/config/settings.py +504 -0
  23. clm/cross_cutting/context.py +5 -0
  24. clm/cross_cutting/domain_models.py +55 -0
  25. clm/cross_cutting/domain_types.py +61 -0
  26. clm/cross_cutting/effects.py +67 -0
  27. clm/cross_cutting/errors.py +153 -0
  28. clm/cross_cutting/governance.py +331 -0
  29. clm/cross_cutting/guards.py +41 -0
  30. clm/cross_cutting/mcard.py +321 -0
  31. clm/cross_cutting/native.py +185 -0
  32. clm/cross_cutting/observability.py +289 -0
  33. clm/cross_cutting/pcard.py +434 -0
  34. clm/cross_cutting/registry.py +71 -0
  35. clm/cross_cutting/resources.py +84 -0
  36. clm/cross_cutting/secrets.py +44 -0
  37. clm/cross_cutting/subprocess_utils.py +118 -0
  38. clm/cross_cutting/telemetry.py +164 -0
  39. clm/cross_cutting/testing/__init__.py +8 -0
  40. clm/cross_cutting/testing/comparator.py +187 -0
  41. clm/cross_cutting/testing/datasets.py +87 -0
  42. clm/cross_cutting/timeutil.py +20 -0
  43. clm/cross_cutting/types/new_type_check.py +0 -0
  44. clm/cross_cutting/utils/__init__.py +1 -0
  45. clm/cross_cutting/utils/url_safety.py +50 -0
  46. clm/cross_cutting/vcard.py +560 -0
  47. clm/cross_cutting/writer.py +118 -0
  48. clm/layer0/README.md +50 -0
  49. clm/layer0/__init__.py +223 -0
  50. clm/layer0/algebra.py +60 -0
  51. clm/layer0/algebra_baldwin.py +133 -0
  52. clm/layer0/algebra_baldwin_generators.py +36 -0
  53. clm/layer0/algebra_equivalence.py +262 -0
  54. clm/layer0/algebra_ingest.py +306 -0
  55. clm/layer0/algebra_manifest_io.py +156 -0
  56. clm/layer0/assembler.py +481 -0
  57. clm/layer0/cel/__init__.py +23 -0
  58. clm/layer0/cel_eval.py +491 -0
  59. clm/layer0/codec.py +106 -0
  60. clm/layer0/context.py +122 -0
  61. clm/layer0/db.py +160 -0
  62. clm/layer0/exceptions.py +73 -0
  63. clm/layer0/fibration.py +106 -0
  64. clm/layer0/gates.py +50 -0
  65. clm/layer0/hash.py +80 -0
  66. clm/layer0/loader.py +826 -0
  67. clm/layer0/math_utils.py +163 -0
  68. clm/layer0/mcard.py +96 -0
  69. clm/layer0/model/__init__.py +0 -0
  70. clm/layer0/model/action.py +223 -0
  71. clm/layer0/model/card.py +280 -0
  72. clm/layer0/model/card_triad.py +427 -0
  73. clm/layer0/model/compatibility.py +60 -0
  74. clm/layer0/model/dictionary.py +46 -0
  75. clm/layer0/model/dots.py +331 -0
  76. clm/layer0/model/event_producer.py +88 -0
  77. clm/layer0/model/g_time.py +89 -0
  78. clm/layer0/model/handle.py +163 -0
  79. clm/layer0/model/hash/__init__.py +6 -0
  80. clm/layer0/model/hash/algorithms/__init__.py +3 -0
  81. clm/layer0/model/hash/algorithms/custom_hash.py +7 -0
  82. clm/layer0/model/hash/algorithms/local_sha256.py +178 -0
  83. clm/layer0/model/hash/constants.py +53 -0
  84. clm/layer0/model/hash/enums.py +60 -0
  85. clm/layer0/model/hash/validator.py +307 -0
  86. clm/layer0/model/interpreter.py +275 -0
  87. clm/layer0/model/pagination.py +45 -0
  88. clm/layer0/model/pcard.py +716 -0
  89. clm/layer0/model/schema.py +44 -0
  90. clm/layer0/model/utils/__init__.py +1 -0
  91. clm/layer0/model/utils/content_analyzer.py +152 -0
  92. clm/layer0/model/validators/__init__.py +1 -0
  93. clm/layer0/model/validators/base_validator.py +44 -0
  94. clm/layer0/model/validators/binary_validator.py +66 -0
  95. clm/layer0/model/validators/text_validator.py +82 -0
  96. clm/layer0/model/validators/validation_registry.py +49 -0
  97. clm/layer0/model/vcard.py +823 -0
  98. clm/layer0/model/vcard_ext/__init__.py +39 -0
  99. clm/layer0/model/vcard_ext/core.py +60 -0
  100. clm/layer0/model/vcard_ext/network.py +23 -0
  101. clm/layer0/model/vcard_ext/observability.py +63 -0
  102. clm/layer0/model/vcard_ext/storage.py +60 -0
  103. clm/layer0/model/vcard_ext/vendors.py +211 -0
  104. clm/layer0/model/vcard_sandwich.py +119 -0
  105. clm/layer0/model/vcard_vocabulary.py +463 -0
  106. clm/layer0/model/workflow.py +274 -0
  107. clm/layer0/narrative.py +431 -0
  108. clm/layer0/ontology/collection.py +125 -0
  109. clm/layer0/parser.py +429 -0
  110. clm/layer0/relations.py +73 -0
  111. clm/layer0/rule_evaluator.py +251 -0
  112. clm/layer0/schema/__init__.py +38 -0
  113. clm/layer0/schema/ddl.py +97 -0
  114. clm/layer0/templates/abstract.yaml +99 -0
  115. clm/layer0/templates/balanced.yaml +253 -0
  116. clm/layer0/templates/concrete.yaml +172 -0
  117. clm/layer0/type_registry.py +223 -0
  118. clm/layer0/types.py +204 -0
  119. clm/layer0/utils.py +886 -0
  120. clm/layer0/verifier_core.py +262 -0
  121. clm/layer1/__init__.py +31 -0
  122. clm/layer1/action_dispatcher.py +275 -0
  123. clm/layer1/adapter_registry.py +233 -0
  124. clm/layer1/algebra_baldwin_generators.py +192 -0
  125. clm/layer1/arrow_compiler.py +525 -0
  126. clm/layer1/batch_processor.py +152 -0
  127. clm/layer1/cel/__init__.py +27 -0
  128. clm/layer1/cel/builder.py +173 -0
  129. clm/layer1/engine.py +759 -0
  130. clm/layer1/engine_async.py +89 -0
  131. clm/layer1/eval_callback.py +49 -0
  132. clm/layer1/gate_composer.py +229 -0
  133. clm/layer1/hoare_sandwich.py +298 -0
  134. clm/layer1/identity_guard.py +348 -0
  135. clm/layer1/matrix.py +138 -0
  136. clm/layer1/neural_runtime.py +221 -0
  137. clm/layer1/operations/__init__.py +123 -0
  138. clm/layer1/operations/augment.py +156 -0
  139. clm/layer1/operations/base.py +109 -0
  140. clm/layer1/operations/builtins.py +338 -0
  141. clm/layer1/operations/dispatch.py +144 -0
  142. clm/layer1/operations/exclude.py +107 -0
  143. clm/layer1/operations/handle.py +197 -0
  144. clm/layer1/operations/identity.py +139 -0
  145. clm/layer1/operations/invert.py +66 -0
  146. clm/layer1/operations/loader.py +116 -0
  147. clm/layer1/operations/manipulators/__init__.py +23 -0
  148. clm/layer1/operations/manipulators/document.py +211 -0
  149. clm/layer1/operations/manipulators/media.py +134 -0
  150. clm/layer1/operations/manipulators/structured.py +159 -0
  151. clm/layer1/operations/manipulators/tabular.py +334 -0
  152. clm/layer1/operations/port.py +65 -0
  153. clm/layer1/operations/services.py +529 -0
  154. clm/layer1/operations/split.py +117 -0
  155. clm/layer1/operations/substitute.py +75 -0
  156. clm/layer1/petri.py +1052 -0
  157. clm/layer1/pocketflow_orchestrator.py +408 -0
  158. clm/layer1/pocketflow_scheduler.py +519 -0
  159. clm/layer1/protocols.py +197 -0
  160. clm/layer1/runtime_adapter.py +718 -0
  161. clm/layer1/runtimes/__init__.py +71 -0
  162. clm/layer1/runtimes/_generated_assertions.py +125 -0
  163. clm/layer1/runtimes/_generated_types.py +42 -0
  164. clm/layer1/runtimes/base.py +265 -0
  165. clm/layer1/runtimes/binary.py +101 -0
  166. clm/layer1/runtimes/factory.py +203 -0
  167. clm/layer1/runtimes/javascript.py +321 -0
  168. clm/layer1/runtimes/javascript_runtime.js +33 -0
  169. clm/layer1/runtimes/js_scripts/isomorphism.mjs +22 -0
  170. clm/layer1/runtimes/js_scripts/loader.mjs +52 -0
  171. clm/layer1/runtimes/lambda_calc.py +126 -0
  172. clm/layer1/runtimes/python.py +288 -0
  173. clm/layer1/runtimes/python_runtime.py +41 -0
  174. clm/layer1/runtimes/script.py +114 -0
  175. clm/layer1/sandbox.py +334 -0
  176. clm/layer1/savepoint_guard.py +136 -0
  177. clm/layer1/sparse_net.py +122 -0
  178. clm/layer1/spec_tester.py +165 -0
  179. clm/layer1/store.py +295 -0
  180. clm/layer1/test_runner.py +498 -0
  181. clm/layer1/type_inspector.py +166 -0
  182. clm/layer1/verifier.py +772 -0
  183. clm/layer1/vm.py +91 -0
  184. clm/layer2/__init__.py +78 -0
  185. clm/layer2/card_collection.py +678 -0
  186. clm/layer2/classifier.py +479 -0
  187. clm/layer2/engine/__init__.py +1 -0
  188. clm/layer2/engine/abstract_sql_engine.py +320 -0
  189. clm/layer2/engine/base.py +193 -0
  190. clm/layer2/engine/duckdb_engine.py +576 -0
  191. clm/layer2/engine/sqlite_engine.py +518 -0
  192. clm/layer2/fiber/__init__.py +31 -0
  193. clm/layer2/fiber/context.py +89 -0
  194. clm/layer2/fiber/disposable.py +163 -0
  195. clm/layer2/fiber/fiber.py +125 -0
  196. clm/layer2/fiber/hoare.py +191 -0
  197. clm/layer2/file_io.py +376 -0
  198. clm/layer2/file_registrar.py +77 -0
  199. clm/layer2/ingest.py +202 -0
  200. clm/layer2/lineage.py +322 -0
  201. clm/layer2/mcard_fs.py +262 -0
  202. clm/layer2/merkle.py +11 -0
  203. clm/layer2/mime.py +244 -0
  204. clm/layer2/mime_detector.py +245 -0
  205. clm/layer2/private_collection.py +118 -0
  206. clm/layer2/shared_store.py +11 -0
  207. clm/layer2/storage/__init__.py +190 -0
  208. clm/layer2/storage/db_bitemporal.py +141 -0
  209. clm/layer2/storage/db_driver.py +331 -0
  210. clm/layer2/storage/db_hyperlinks.py +214 -0
  211. clm/layer2/storage/db_pool.py +139 -0
  212. clm/layer2/storage/db_repository.py +229 -0
  213. clm/layer2/storage/savepoint.py +78 -0
  214. clm/layer2/storage/sqlite_wal.py +74 -0
  215. clm/layer2/tridb.py +245 -0
  216. clm/layer2/vcard_receipt.py +71 -0
  217. clm/layer2/vfs.py +17 -0
  218. clm/layer3/__init__.py +141 -0
  219. clm/layer3/agency/__init__.py +19 -0
  220. clm/layer3/agency/config.py +220 -0
  221. clm/layer3/agency/providers/__init__.py +15 -0
  222. clm/layer3/agency/providers/base.py +91 -0
  223. clm/layer3/agency/providers/mlc_llm.py +169 -0
  224. clm/layer3/agency/providers/ollama.py +203 -0
  225. clm/layer3/agency/router.py +71 -0
  226. clm/layer3/agency/runtime.py +524 -0
  227. clm/layer3/gateway.py +353 -0
  228. clm/layer3/open_interpreter_adapter.py +159 -0
  229. clm/layer3/rag/__init__.py +70 -0
  230. clm/layer3/rag/cli.py +228 -0
  231. clm/layer3/rag/config.py +153 -0
  232. clm/layer3/rag/embeddings/__init__.py +16 -0
  233. clm/layer3/rag/embeddings/base.py +79 -0
  234. clm/layer3/rag/embeddings/ollama.py +211 -0
  235. clm/layer3/rag/embeddings/vision.py +290 -0
  236. clm/layer3/rag/engine.py +276 -0
  237. clm/layer3/rag/graph/__init__.py +22 -0
  238. clm/layer3/rag/graph/community.py +198 -0
  239. clm/layer3/rag/graph/engine.py +433 -0
  240. clm/layer3/rag/graph/extractor.py +255 -0
  241. clm/layer3/rag/graph/schema.py +115 -0
  242. clm/layer3/rag/graph/store.py +641 -0
  243. clm/layer3/rag/indexer.py +333 -0
  244. clm/layer3/rag/llm_providers.json +52 -0
  245. clm/layer3/rag/semantic_versioning.py +313 -0
  246. clm/layer3/rag/vector/__init__.py +28 -0
  247. clm/layer3/rag/vector/handle_vector_store.py +749 -0
  248. clm/layer3/rag/vector/schema.py +151 -0
  249. clm/layer3/rag/vector/store.py +632 -0
  250. clm/layer3/reticulum/__init__.py +55 -0
  251. clm/layer3/reticulum/bridge.py +74 -0
  252. clm/layer3/reticulum/daemon.py +88 -0
  253. clm/layer3/reticulum/discovery.py +164 -0
  254. clm/layer3/reticulum/identity.py +107 -0
  255. clm/layer3/reticulum/media.py +148 -0
  256. clm/layer3/reticulum/transport.py +133 -0
  257. clm/layer3/satori/__init__.py +209 -0
  258. clm/layer3/satori/alpha_conversion.py +168 -0
  259. clm/layer3/satori/beta_reduction.py +359 -0
  260. clm/layer3/satori/continuation.py +38 -0
  261. clm/layer3/satori/eta_conversion.py +205 -0
  262. clm/layer3/satori/free_variables.py +163 -0
  263. clm/layer3/satori/io_effects.py +370 -0
  264. clm/layer3/satori/lambda_runtime.py +726 -0
  265. clm/layer3/satori/lambda_term.py +230 -0
  266. clm/layer3/satori/sheaf_audit.py +261 -0
  267. clm/layer3/satori/speech_act.py +279 -0
  268. clm/layer4/README.md +9 -0
  269. clm/layer4/__init__.py +67 -0
  270. clm/layer4/_sovereign_executor.py +580 -0
  271. clm/layer4/action_commands.py +719 -0
  272. clm/layer4/api.py +236 -0
  273. clm/layer4/bootstrap/__init__.py +13 -0
  274. clm/layer4/bootstrap/bootstrapper.py +118 -0
  275. clm/layer4/bootstrap/cleanup.py +44 -0
  276. clm/layer4/bootstrap/clm_hooks.py +49 -0
  277. clm/layer4/bootstrap/genesis.py +77 -0
  278. clm/layer4/bootstrap/injection.py +125 -0
  279. clm/layer4/cli.py +549 -0
  280. clm/layer4/collection_manager.py +553 -0
  281. clm/layer4/commands/__init__.py +81 -0
  282. clm/layer4/commands/action_cmd.py +42 -0
  283. clm/layer4/commands/check_cmd.py +82 -0
  284. clm/layer4/commands/envelope.py +73 -0
  285. clm/layer4/commands/evaluate_cmd.py +224 -0
  286. clm/layer4/commands/mcard_cmd.py +24 -0
  287. clm/layer4/commands/petri_cmd.py +92 -0
  288. clm/layer4/commands/tridb_cmd.py +319 -0
  289. clm/layer4/commands/version_cmd.py +27 -0
  290. clm/layer4/diff_commands.py +167 -0
  291. clm/layer4/eoa_sponsor.py +232 -0
  292. clm/layer4/events.py +69 -0
  293. clm/layer4/flux_gateway.py +133 -0
  294. clm/layer4/gateway.py +91 -0
  295. clm/layer4/loader.py +307 -0
  296. clm/layer4/mcard_commands.py +166 -0
  297. clm/layer4/membrane.py +273 -0
  298. clm/layer4/navigation.py +50 -0
  299. clm/layer4/protocol/protocol_entry_python.py +108 -0
  300. clm/layer4/protocol/python_sync.py +126 -0
  301. clm/layer4/runner.py +150 -0
  302. clm/layer4/satori.py +262 -0
  303. clm/layer4/server/python_sync_client.py +150 -0
  304. clm/layer4/server/python_sync_server.py +139 -0
  305. clm/layer4/server/service_api.py +315 -0
  306. clm/layer4/server/start_servers.py +107 -0
  307. clm/layer4/server/stop_servers.py +24 -0
  308. clm/layer4/simulated_optimization_fix.py +0 -0
  309. clm/layer4/storage.py +463 -0
  310. clm/layer4/tridb_admin.py +268 -0
  311. clm/layer4/websocket/test_ws_client.py +104 -0
  312. clm/layer4/websocket/test_ws_server.py +138 -0
  313. clm/layer4/websocket/ws_server_local.py +160 -0
  314. clm/layer5/__init__.py +51 -0
  315. clm/layer5/async_batch_writer.py +133 -0
  316. clm/layer5/learning.py +276 -0
  317. clm/layer5/telemetry_hook.py +107 -0
  318. clm/layer5/type_lattice.py +238 -0
  319. clm/py.typed +0 -0
  320. clm/schemas/__init__.py +652 -0
  321. clm/schemas/abstract_face_schema.yaml +77 -0
  322. clm/schemas/cel_schema.yaml +416 -0
  323. clm/schemas/lifecycle/__init__.py +45 -0
  324. clm/schemas/lifecycle/models.py +123 -0
  325. clm/schemas/lifecycle/service.py +364 -0
  326. clm/schemas/mcard_schema.sql +192 -0
  327. clm/schemas/mcard_vector_schema.sql +283 -0
  328. clm/schemas/mlp-context-v1.json +91 -0
  329. clm_kernel-0.0.0.dist-info/METADATA +121 -0
  330. clm_kernel-0.0.0.dist-info/RECORD +333 -0
  331. clm_kernel-0.0.0.dist-info/WHEEL +4 -0
  332. clm_kernel-0.0.0.dist-info/entry_points.txt +3 -0
  333. clm_kernel-0.0.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,378 @@
1
+ """
2
+ MCard Unified Logging Configuration
3
+ ====================================
4
+
5
+ This module provides the canonical logging configuration for MCard.
6
+ It consolidates previous separate logging modules into a single, maintainable source.
7
+
8
+ Features:
9
+ - Structured logging with multiple formatters (simple, detailed, JSON, performance)
10
+ - Rotating file handlers for general, error, and performance logs
11
+ - Specialized loggers for API, database, performance, and security
12
+ - Context managers for performance timing and security auditing
13
+ - Backward compatible with previous logging APIs
14
+
15
+ Usage:
16
+ from clm.cross_cutting.config.logging import setup_logging, get_logger
17
+
18
+ setup_logging()
19
+ logger = get_logger(__name__)
20
+ logger.info("Application started")
21
+
22
+ # Performance timing
23
+ from clm.cross_cutting.config.logging import PerformanceTimer
24
+ with PerformanceTimer("database_query"):
25
+ result = db.query(...)
26
+
27
+ # Security auditing
28
+ from clm.cross_cutting.config.logging import SecurityAuditLogger
29
+ audit = SecurityAuditLogger()
30
+ audit.log_access_attempt(user_id="123", resource="/api/cards", success=True)
31
+ """
32
+
33
+ import logging
34
+ from datetime import datetime
35
+ from pathlib import Path
36
+ from typing import Any
37
+
38
+ from .config_constants import LOG_DIRECTORY, LOG_FILENAME, _find_project_root
39
+ from .settings import settings
40
+
41
+ # ─────────────────────────────────────────────────────────────────────────────
42
+ # Module State
43
+ # ─────────────────────────────────────────────────────────────────────────────
44
+
45
+ _logging_initialized = False
46
+ _project_root: Path | None = None
47
+ _logs_dir: Path | None = None
48
+
49
+
50
+ def _get_project_root() -> Path:
51
+ """Get the project root directory."""
52
+ global _project_root
53
+ if _project_root is None:
54
+ _project_root = _find_project_root()
55
+ return _project_root
56
+
57
+
58
+ def _get_logs_dir() -> Path:
59
+ """Get the logs directory, creating it if necessary."""
60
+ global _logs_dir
61
+ if _logs_dir is None:
62
+ _logs_dir = _get_project_root() / LOG_DIRECTORY
63
+ _logs_dir.mkdir(parents=True, exist_ok=True)
64
+ return _logs_dir
65
+
66
+
67
+ # ─────────────────────────────────────────────────────────────────────────────
68
+ # Configuration Factory
69
+ # ─────────────────────────────────────────────────────────────────────────────
70
+
71
+
72
+ def get_logging_config() -> dict[str, Any]:
73
+ """
74
+ Generate the logging configuration dictionary.
75
+
76
+ Returns:
77
+ dict: A logging.config.dictConfig compatible configuration.
78
+ """
79
+ log_level = settings.logging.level
80
+ logs_dir = _get_logs_dir()
81
+
82
+ log_file = str(logs_dir / LOG_FILENAME)
83
+ error_log_file = str(logs_dir / "mcard.error.log")
84
+ performance_log_file = str(logs_dir / "mcard.performance.log")
85
+
86
+ return {
87
+ "version": 1,
88
+ "disable_existing_loggers": False,
89
+ "formatters": {
90
+ # Simple format for console output
91
+ "simple": {
92
+ "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
93
+ "datefmt": "%Y-%m-%d %H:%M:%S",
94
+ },
95
+ # Detailed format for file output
96
+ "detailed": {
97
+ "format": "%(asctime)s | %(name)-25s | %(levelname)-8s | %(funcName)-20s:%(lineno)-4d | %(message)s",
98
+ "datefmt": "%Y-%m-%d %H:%M:%S",
99
+ },
100
+ # JSON format for structured logging
101
+ "json": {
102
+ "format": '{"timestamp": "%(asctime)s", "level": "%(levelname)s", "logger": "%(name)s", "function": "%(funcName)s", "line": %(lineno)d, "message": "%(message)s"}',
103
+ "datefmt": "%Y-%m-%dT%H:%M:%S",
104
+ },
105
+ # Performance format
106
+ "performance": {
107
+ "format": "%(asctime)s | PERF | %(name)s | %(message)s",
108
+ "datefmt": "%Y-%m-%d %H:%M:%S",
109
+ },
110
+ },
111
+ "handlers": {
112
+ # Console handler - outputs to stderr
113
+ "console": {
114
+ "class": "logging.StreamHandler",
115
+ "level": log_level,
116
+ "formatter": "simple",
117
+ "stream": "ext://sys.stderr",
118
+ },
119
+ # Main file handler - rotating, detailed format
120
+ "file": {
121
+ "class": "logging.handlers.RotatingFileHandler",
122
+ "level": "DEBUG",
123
+ "formatter": "detailed",
124
+ "filename": log_file,
125
+ "maxBytes": 50_000_000, # 50MB
126
+ "backupCount": 10,
127
+ "encoding": "utf-8",
128
+ },
129
+ # Error file handler - only ERROR and above
130
+ "error_file": {
131
+ "class": "logging.handlers.RotatingFileHandler",
132
+ "level": "ERROR",
133
+ "formatter": "detailed",
134
+ "filename": error_log_file,
135
+ "maxBytes": 10_000_000, # 10MB
136
+ "backupCount": 5,
137
+ "encoding": "utf-8",
138
+ },
139
+ # Performance file handler
140
+ "performance_file": {
141
+ "class": "logging.handlers.RotatingFileHandler",
142
+ "level": "INFO",
143
+ "formatter": "performance",
144
+ "filename": performance_log_file,
145
+ "maxBytes": 10_000_000, # 10MB
146
+ "backupCount": 3,
147
+ "encoding": "utf-8",
148
+ },
149
+ },
150
+ "loggers": {
151
+ # Main MCard logger
152
+ "mcard": {
153
+ "level": "DEBUG",
154
+ "handlers": ["console", "file", "error_file"],
155
+ "propagate": False,
156
+ },
157
+ # API logger
158
+ "mcard.api": {
159
+ "level": "INFO",
160
+ "handlers": ["console", "file"],
161
+ "propagate": False,
162
+ },
163
+ # Performance metrics logger
164
+ "mcard.performance": {
165
+ "level": "INFO",
166
+ "handlers": ["performance_file"],
167
+ "propagate": False,
168
+ },
169
+ # Security events logger
170
+ "mcard.security": {
171
+ "level": "WARNING",
172
+ "handlers": ["console", "file", "error_file"],
173
+ "propagate": False,
174
+ },
175
+ # Database operations logger
176
+ "mcard.database": {
177
+ "level": "INFO",
178
+ "handlers": ["file"],
179
+ "propagate": False,
180
+ },
181
+ # Third-party loggers
182
+ "uvicorn": {
183
+ "level": "INFO",
184
+ "handlers": ["file"],
185
+ "propagate": False,
186
+ },
187
+ "fastapi": {
188
+ "level": "INFO",
189
+ "handlers": ["file"],
190
+ "propagate": False,
191
+ },
192
+ "sqlalchemy": {
193
+ "level": "WARNING",
194
+ "handlers": ["file"],
195
+ "propagate": False,
196
+ },
197
+ },
198
+ "root": {
199
+ "level": "WARNING",
200
+ "handlers": ["console", "file"],
201
+ },
202
+ }
203
+
204
+
205
+ # ─────────────────────────────────────────────────────────────────────────────
206
+ # Setup Functions
207
+ # ─────────────────────────────────────────────────────────────────────────────
208
+
209
+
210
+ def setup_logging(force_reinit: bool = False) -> None:
211
+ """
212
+ Set up the MCard logging configuration.
213
+
214
+ This function is idempotent - it will only initialize logging once unless
215
+ force_reinit is True.
216
+
217
+ Args:
218
+ force_reinit: If True, reinitialize logging even if already set up.
219
+ """
220
+ global _logging_initialized
221
+
222
+ if _logging_initialized and not force_reinit:
223
+ return
224
+
225
+ try:
226
+ import logging.config
227
+ config = get_logging_config()
228
+ logging.config.dictConfig(config)
229
+
230
+ logger = logging.getLogger("mcard.logging")
231
+ logger.info(
232
+ "Logging configuration initialized",
233
+ extra={"log_level": config["loggers"]["mcard"]["level"]},
234
+ )
235
+
236
+ _logging_initialized = True
237
+
238
+ except Exception as e:
239
+ # Fallback to basic logging if setup fails
240
+ logging.basicConfig(
241
+ level=logging.INFO,
242
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
243
+ )
244
+ logger = logging.getLogger("mcard.logging")
245
+ logger.error(
246
+ f"Failed to setup logging, using basic configuration: {e}", exc_info=True
247
+ )
248
+
249
+
250
+ # Backward compatibility alias
251
+ setup_improved_logging = setup_logging
252
+
253
+
254
+ # ─────────────────────────────────────────────────────────────────────────────
255
+ # Logger Factory Functions
256
+ # ─────────────────────────────────────────────────────────────────────────────
257
+
258
+
259
+ def get_logger(name: str) -> logging.Logger:
260
+ """
261
+ Get a logger with the specified name.
262
+
263
+ Args:
264
+ name: The logger name (typically __name__).
265
+
266
+ Returns:
267
+ logging.Logger: The configured logger.
268
+ """
269
+ return logging.getLogger(name)
270
+
271
+
272
+ def get_performance_logger() -> logging.Logger:
273
+ """Get a specialized logger for performance metrics."""
274
+ return logging.getLogger("mcard.performance")
275
+
276
+
277
+ def get_security_logger() -> logging.Logger:
278
+ """Get a specialized logger for security events."""
279
+ return logging.getLogger("mcard.security")
280
+
281
+
282
+ def get_database_logger() -> logging.Logger:
283
+ """Get a specialized logger for database operations."""
284
+ return logging.getLogger("mcard.database")
285
+
286
+
287
+ def get_api_logger() -> logging.Logger:
288
+ """Get a specialized logger for API operations."""
289
+ return logging.getLogger("mcard.api")
290
+
291
+
292
+ # ─────────────────────────────────────────────────────────────────────────────
293
+ # Context Managers
294
+ # ─────────────────────────────────────────────────────────────────────────────
295
+
296
+
297
+ class PerformanceTimer:
298
+ """
299
+ Context manager for timing operations and logging performance metrics.
300
+
301
+ Usage:
302
+ with PerformanceTimer("database_query"):
303
+ result = db.query(...)
304
+ """
305
+
306
+ def __init__(self, operation: str, logger: logging.Logger | None = None):
307
+ self.operation = operation
308
+ self.logger = logger or get_performance_logger()
309
+ self.start_time: datetime | None = None
310
+
311
+ def __enter__(self) -> "PerformanceTimer":
312
+ self.start_time = datetime.now()
313
+ return self
314
+
315
+ def __exit__(self, exc_type, exc_val, _exc_tb) -> None:
316
+ if self.start_time:
317
+ duration = (datetime.now() - self.start_time).total_seconds() * 1000
318
+ if exc_type:
319
+ self.logger.error(
320
+ f"Operation '{self.operation}' failed after {duration:.2f}ms: {exc_val}"
321
+ )
322
+ else:
323
+ self.logger.info(
324
+ f"Operation '{self.operation}' completed in {duration:.2f}ms"
325
+ )
326
+
327
+
328
+ # ─────────────────────────────────────────────────────────────────────────────
329
+ # Security Audit Helpers
330
+ # ─────────────────────────────────────────────────────────────────────────────
331
+
332
+
333
+ class SecurityAuditLogger:
334
+ """
335
+ Helper class for logging security-related events.
336
+
337
+ Usage:
338
+ audit = SecurityAuditLogger()
339
+ audit.log_access_attempt("user123", "/api/cards", success=True)
340
+ """
341
+
342
+ def __init__(self):
343
+ self.logger = get_security_logger()
344
+
345
+ def log_access_attempt(self, user_id: str, resource: str, success: bool) -> None:
346
+ """Log access attempts."""
347
+ status = "SUCCESS" if success else "FAILED"
348
+ self.logger.warning(f"Access {status}: user={user_id}, resource={resource}")
349
+
350
+ def log_authentication(self, user_id: str, method: str, success: bool) -> None:
351
+ """Log authentication events."""
352
+ status = "SUCCESS" if success else "FAILED"
353
+ self.logger.warning(f"Auth {status}: user={user_id}, method={method}")
354
+
355
+ def log_suspicious_activity(self, activity: str, details: str) -> None:
356
+ """Log suspicious activities."""
357
+ self.logger.error(f"SUSPICIOUS: {activity} - {details}")
358
+
359
+
360
+ # ─────────────────────────────────────────────────────────────────────────────
361
+ # Module Exports
362
+ # ─────────────────────────────────────────────────────────────────────────────
363
+
364
+ __all__ = [
365
+ # Setup functions
366
+ "setup_logging",
367
+ "setup_improved_logging", # Backward compatibility alias
368
+ "get_logging_config",
369
+ # Logger factories
370
+ "get_logger",
371
+ "get_performance_logger",
372
+ "get_security_logger",
373
+ "get_database_logger",
374
+ "get_api_logger",
375
+ # Context managers and helpers
376
+ "PerformanceTimer",
377
+ "SecurityAuditLogger",
378
+ ]