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.
- clm/__init__.py +230 -0
- clm/__main__.py +25 -0
- clm/cross_cutting/__init__.py +50 -0
- clm/cross_cutting/_test_runner.py +36 -0
- clm/cross_cutting/async_utils.py +25 -0
- clm/cross_cutting/cel_builder.py +123 -0
- clm/cross_cutting/cel_converter.py +697 -0
- clm/cross_cutting/cel_engine.py +252 -0
- clm/cross_cutting/cel_ops.py +72 -0
- clm/cross_cutting/cel_ops_db.py +157 -0
- clm/cross_cutting/cel_ops_files.py +99 -0
- clm/cross_cutting/cel_ops_state.py +71 -0
- clm/cross_cutting/cel_ops_strings.py +64 -0
- clm/cross_cutting/cel_resolver.py +63 -0
- clm/cross_cutting/cel_slices.py +56 -0
- clm/cross_cutting/cel_store.py +330 -0
- clm/cross_cutting/clm_logger.py +140 -0
- clm/cross_cutting/config/__init__.py +155 -0
- clm/cross_cutting/config/config_constants.py +392 -0
- clm/cross_cutting/config/env_parameters.py +90 -0
- clm/cross_cutting/config/logging.py +378 -0
- clm/cross_cutting/config/settings.py +504 -0
- clm/cross_cutting/context.py +5 -0
- clm/cross_cutting/domain_models.py +55 -0
- clm/cross_cutting/domain_types.py +61 -0
- clm/cross_cutting/effects.py +67 -0
- clm/cross_cutting/errors.py +153 -0
- clm/cross_cutting/governance.py +331 -0
- clm/cross_cutting/guards.py +41 -0
- clm/cross_cutting/mcard.py +321 -0
- clm/cross_cutting/native.py +185 -0
- clm/cross_cutting/observability.py +289 -0
- clm/cross_cutting/pcard.py +434 -0
- clm/cross_cutting/registry.py +71 -0
- clm/cross_cutting/resources.py +84 -0
- clm/cross_cutting/secrets.py +44 -0
- clm/cross_cutting/subprocess_utils.py +118 -0
- clm/cross_cutting/telemetry.py +164 -0
- clm/cross_cutting/testing/__init__.py +8 -0
- clm/cross_cutting/testing/comparator.py +187 -0
- clm/cross_cutting/testing/datasets.py +87 -0
- clm/cross_cutting/timeutil.py +20 -0
- clm/cross_cutting/types/new_type_check.py +0 -0
- clm/cross_cutting/utils/__init__.py +1 -0
- clm/cross_cutting/utils/url_safety.py +50 -0
- clm/cross_cutting/vcard.py +560 -0
- clm/cross_cutting/writer.py +118 -0
- clm/layer0/README.md +50 -0
- clm/layer0/__init__.py +223 -0
- clm/layer0/algebra.py +60 -0
- clm/layer0/algebra_baldwin.py +133 -0
- clm/layer0/algebra_baldwin_generators.py +36 -0
- clm/layer0/algebra_equivalence.py +262 -0
- clm/layer0/algebra_ingest.py +306 -0
- clm/layer0/algebra_manifest_io.py +156 -0
- clm/layer0/assembler.py +481 -0
- clm/layer0/cel/__init__.py +23 -0
- clm/layer0/cel_eval.py +491 -0
- clm/layer0/codec.py +106 -0
- clm/layer0/context.py +122 -0
- clm/layer0/db.py +160 -0
- clm/layer0/exceptions.py +73 -0
- clm/layer0/fibration.py +106 -0
- clm/layer0/gates.py +50 -0
- clm/layer0/hash.py +80 -0
- clm/layer0/loader.py +826 -0
- clm/layer0/math_utils.py +163 -0
- clm/layer0/mcard.py +96 -0
- clm/layer0/model/__init__.py +0 -0
- clm/layer0/model/action.py +223 -0
- clm/layer0/model/card.py +280 -0
- clm/layer0/model/card_triad.py +427 -0
- clm/layer0/model/compatibility.py +60 -0
- clm/layer0/model/dictionary.py +46 -0
- clm/layer0/model/dots.py +331 -0
- clm/layer0/model/event_producer.py +88 -0
- clm/layer0/model/g_time.py +89 -0
- clm/layer0/model/handle.py +163 -0
- clm/layer0/model/hash/__init__.py +6 -0
- clm/layer0/model/hash/algorithms/__init__.py +3 -0
- clm/layer0/model/hash/algorithms/custom_hash.py +7 -0
- clm/layer0/model/hash/algorithms/local_sha256.py +178 -0
- clm/layer0/model/hash/constants.py +53 -0
- clm/layer0/model/hash/enums.py +60 -0
- clm/layer0/model/hash/validator.py +307 -0
- clm/layer0/model/interpreter.py +275 -0
- clm/layer0/model/pagination.py +45 -0
- clm/layer0/model/pcard.py +716 -0
- clm/layer0/model/schema.py +44 -0
- clm/layer0/model/utils/__init__.py +1 -0
- clm/layer0/model/utils/content_analyzer.py +152 -0
- clm/layer0/model/validators/__init__.py +1 -0
- clm/layer0/model/validators/base_validator.py +44 -0
- clm/layer0/model/validators/binary_validator.py +66 -0
- clm/layer0/model/validators/text_validator.py +82 -0
- clm/layer0/model/validators/validation_registry.py +49 -0
- clm/layer0/model/vcard.py +823 -0
- clm/layer0/model/vcard_ext/__init__.py +39 -0
- clm/layer0/model/vcard_ext/core.py +60 -0
- clm/layer0/model/vcard_ext/network.py +23 -0
- clm/layer0/model/vcard_ext/observability.py +63 -0
- clm/layer0/model/vcard_ext/storage.py +60 -0
- clm/layer0/model/vcard_ext/vendors.py +211 -0
- clm/layer0/model/vcard_sandwich.py +119 -0
- clm/layer0/model/vcard_vocabulary.py +463 -0
- clm/layer0/model/workflow.py +274 -0
- clm/layer0/narrative.py +431 -0
- clm/layer0/ontology/collection.py +125 -0
- clm/layer0/parser.py +429 -0
- clm/layer0/relations.py +73 -0
- clm/layer0/rule_evaluator.py +251 -0
- clm/layer0/schema/__init__.py +38 -0
- clm/layer0/schema/ddl.py +97 -0
- clm/layer0/templates/abstract.yaml +99 -0
- clm/layer0/templates/balanced.yaml +253 -0
- clm/layer0/templates/concrete.yaml +172 -0
- clm/layer0/type_registry.py +223 -0
- clm/layer0/types.py +204 -0
- clm/layer0/utils.py +886 -0
- clm/layer0/verifier_core.py +262 -0
- clm/layer1/__init__.py +31 -0
- clm/layer1/action_dispatcher.py +275 -0
- clm/layer1/adapter_registry.py +233 -0
- clm/layer1/algebra_baldwin_generators.py +192 -0
- clm/layer1/arrow_compiler.py +525 -0
- clm/layer1/batch_processor.py +152 -0
- clm/layer1/cel/__init__.py +27 -0
- clm/layer1/cel/builder.py +173 -0
- clm/layer1/engine.py +759 -0
- clm/layer1/engine_async.py +89 -0
- clm/layer1/eval_callback.py +49 -0
- clm/layer1/gate_composer.py +229 -0
- clm/layer1/hoare_sandwich.py +298 -0
- clm/layer1/identity_guard.py +348 -0
- clm/layer1/matrix.py +138 -0
- clm/layer1/neural_runtime.py +221 -0
- clm/layer1/operations/__init__.py +123 -0
- clm/layer1/operations/augment.py +156 -0
- clm/layer1/operations/base.py +109 -0
- clm/layer1/operations/builtins.py +338 -0
- clm/layer1/operations/dispatch.py +144 -0
- clm/layer1/operations/exclude.py +107 -0
- clm/layer1/operations/handle.py +197 -0
- clm/layer1/operations/identity.py +139 -0
- clm/layer1/operations/invert.py +66 -0
- clm/layer1/operations/loader.py +116 -0
- clm/layer1/operations/manipulators/__init__.py +23 -0
- clm/layer1/operations/manipulators/document.py +211 -0
- clm/layer1/operations/manipulators/media.py +134 -0
- clm/layer1/operations/manipulators/structured.py +159 -0
- clm/layer1/operations/manipulators/tabular.py +334 -0
- clm/layer1/operations/port.py +65 -0
- clm/layer1/operations/services.py +529 -0
- clm/layer1/operations/split.py +117 -0
- clm/layer1/operations/substitute.py +75 -0
- clm/layer1/petri.py +1052 -0
- clm/layer1/pocketflow_orchestrator.py +408 -0
- clm/layer1/pocketflow_scheduler.py +519 -0
- clm/layer1/protocols.py +197 -0
- clm/layer1/runtime_adapter.py +718 -0
- clm/layer1/runtimes/__init__.py +71 -0
- clm/layer1/runtimes/_generated_assertions.py +125 -0
- clm/layer1/runtimes/_generated_types.py +42 -0
- clm/layer1/runtimes/base.py +265 -0
- clm/layer1/runtimes/binary.py +101 -0
- clm/layer1/runtimes/factory.py +203 -0
- clm/layer1/runtimes/javascript.py +321 -0
- clm/layer1/runtimes/javascript_runtime.js +33 -0
- clm/layer1/runtimes/js_scripts/isomorphism.mjs +22 -0
- clm/layer1/runtimes/js_scripts/loader.mjs +52 -0
- clm/layer1/runtimes/lambda_calc.py +126 -0
- clm/layer1/runtimes/python.py +288 -0
- clm/layer1/runtimes/python_runtime.py +41 -0
- clm/layer1/runtimes/script.py +114 -0
- clm/layer1/sandbox.py +334 -0
- clm/layer1/savepoint_guard.py +136 -0
- clm/layer1/sparse_net.py +122 -0
- clm/layer1/spec_tester.py +165 -0
- clm/layer1/store.py +295 -0
- clm/layer1/test_runner.py +498 -0
- clm/layer1/type_inspector.py +166 -0
- clm/layer1/verifier.py +772 -0
- clm/layer1/vm.py +91 -0
- clm/layer2/__init__.py +78 -0
- clm/layer2/card_collection.py +678 -0
- clm/layer2/classifier.py +479 -0
- clm/layer2/engine/__init__.py +1 -0
- clm/layer2/engine/abstract_sql_engine.py +320 -0
- clm/layer2/engine/base.py +193 -0
- clm/layer2/engine/duckdb_engine.py +576 -0
- clm/layer2/engine/sqlite_engine.py +518 -0
- clm/layer2/fiber/__init__.py +31 -0
- clm/layer2/fiber/context.py +89 -0
- clm/layer2/fiber/disposable.py +163 -0
- clm/layer2/fiber/fiber.py +125 -0
- clm/layer2/fiber/hoare.py +191 -0
- clm/layer2/file_io.py +376 -0
- clm/layer2/file_registrar.py +77 -0
- clm/layer2/ingest.py +202 -0
- clm/layer2/lineage.py +322 -0
- clm/layer2/mcard_fs.py +262 -0
- clm/layer2/merkle.py +11 -0
- clm/layer2/mime.py +244 -0
- clm/layer2/mime_detector.py +245 -0
- clm/layer2/private_collection.py +118 -0
- clm/layer2/shared_store.py +11 -0
- clm/layer2/storage/__init__.py +190 -0
- clm/layer2/storage/db_bitemporal.py +141 -0
- clm/layer2/storage/db_driver.py +331 -0
- clm/layer2/storage/db_hyperlinks.py +214 -0
- clm/layer2/storage/db_pool.py +139 -0
- clm/layer2/storage/db_repository.py +229 -0
- clm/layer2/storage/savepoint.py +78 -0
- clm/layer2/storage/sqlite_wal.py +74 -0
- clm/layer2/tridb.py +245 -0
- clm/layer2/vcard_receipt.py +71 -0
- clm/layer2/vfs.py +17 -0
- clm/layer3/__init__.py +141 -0
- clm/layer3/agency/__init__.py +19 -0
- clm/layer3/agency/config.py +220 -0
- clm/layer3/agency/providers/__init__.py +15 -0
- clm/layer3/agency/providers/base.py +91 -0
- clm/layer3/agency/providers/mlc_llm.py +169 -0
- clm/layer3/agency/providers/ollama.py +203 -0
- clm/layer3/agency/router.py +71 -0
- clm/layer3/agency/runtime.py +524 -0
- clm/layer3/gateway.py +353 -0
- clm/layer3/open_interpreter_adapter.py +159 -0
- clm/layer3/rag/__init__.py +70 -0
- clm/layer3/rag/cli.py +228 -0
- clm/layer3/rag/config.py +153 -0
- clm/layer3/rag/embeddings/__init__.py +16 -0
- clm/layer3/rag/embeddings/base.py +79 -0
- clm/layer3/rag/embeddings/ollama.py +211 -0
- clm/layer3/rag/embeddings/vision.py +290 -0
- clm/layer3/rag/engine.py +276 -0
- clm/layer3/rag/graph/__init__.py +22 -0
- clm/layer3/rag/graph/community.py +198 -0
- clm/layer3/rag/graph/engine.py +433 -0
- clm/layer3/rag/graph/extractor.py +255 -0
- clm/layer3/rag/graph/schema.py +115 -0
- clm/layer3/rag/graph/store.py +641 -0
- clm/layer3/rag/indexer.py +333 -0
- clm/layer3/rag/llm_providers.json +52 -0
- clm/layer3/rag/semantic_versioning.py +313 -0
- clm/layer3/rag/vector/__init__.py +28 -0
- clm/layer3/rag/vector/handle_vector_store.py +749 -0
- clm/layer3/rag/vector/schema.py +151 -0
- clm/layer3/rag/vector/store.py +632 -0
- clm/layer3/reticulum/__init__.py +55 -0
- clm/layer3/reticulum/bridge.py +74 -0
- clm/layer3/reticulum/daemon.py +88 -0
- clm/layer3/reticulum/discovery.py +164 -0
- clm/layer3/reticulum/identity.py +107 -0
- clm/layer3/reticulum/media.py +148 -0
- clm/layer3/reticulum/transport.py +133 -0
- clm/layer3/satori/__init__.py +209 -0
- clm/layer3/satori/alpha_conversion.py +168 -0
- clm/layer3/satori/beta_reduction.py +359 -0
- clm/layer3/satori/continuation.py +38 -0
- clm/layer3/satori/eta_conversion.py +205 -0
- clm/layer3/satori/free_variables.py +163 -0
- clm/layer3/satori/io_effects.py +370 -0
- clm/layer3/satori/lambda_runtime.py +726 -0
- clm/layer3/satori/lambda_term.py +230 -0
- clm/layer3/satori/sheaf_audit.py +261 -0
- clm/layer3/satori/speech_act.py +279 -0
- clm/layer4/README.md +9 -0
- clm/layer4/__init__.py +67 -0
- clm/layer4/_sovereign_executor.py +580 -0
- clm/layer4/action_commands.py +719 -0
- clm/layer4/api.py +236 -0
- clm/layer4/bootstrap/__init__.py +13 -0
- clm/layer4/bootstrap/bootstrapper.py +118 -0
- clm/layer4/bootstrap/cleanup.py +44 -0
- clm/layer4/bootstrap/clm_hooks.py +49 -0
- clm/layer4/bootstrap/genesis.py +77 -0
- clm/layer4/bootstrap/injection.py +125 -0
- clm/layer4/cli.py +549 -0
- clm/layer4/collection_manager.py +553 -0
- clm/layer4/commands/__init__.py +81 -0
- clm/layer4/commands/action_cmd.py +42 -0
- clm/layer4/commands/check_cmd.py +82 -0
- clm/layer4/commands/envelope.py +73 -0
- clm/layer4/commands/evaluate_cmd.py +224 -0
- clm/layer4/commands/mcard_cmd.py +24 -0
- clm/layer4/commands/petri_cmd.py +92 -0
- clm/layer4/commands/tridb_cmd.py +319 -0
- clm/layer4/commands/version_cmd.py +27 -0
- clm/layer4/diff_commands.py +167 -0
- clm/layer4/eoa_sponsor.py +232 -0
- clm/layer4/events.py +69 -0
- clm/layer4/flux_gateway.py +133 -0
- clm/layer4/gateway.py +91 -0
- clm/layer4/loader.py +307 -0
- clm/layer4/mcard_commands.py +166 -0
- clm/layer4/membrane.py +273 -0
- clm/layer4/navigation.py +50 -0
- clm/layer4/protocol/protocol_entry_python.py +108 -0
- clm/layer4/protocol/python_sync.py +126 -0
- clm/layer4/runner.py +150 -0
- clm/layer4/satori.py +262 -0
- clm/layer4/server/python_sync_client.py +150 -0
- clm/layer4/server/python_sync_server.py +139 -0
- clm/layer4/server/service_api.py +315 -0
- clm/layer4/server/start_servers.py +107 -0
- clm/layer4/server/stop_servers.py +24 -0
- clm/layer4/simulated_optimization_fix.py +0 -0
- clm/layer4/storage.py +463 -0
- clm/layer4/tridb_admin.py +268 -0
- clm/layer4/websocket/test_ws_client.py +104 -0
- clm/layer4/websocket/test_ws_server.py +138 -0
- clm/layer4/websocket/ws_server_local.py +160 -0
- clm/layer5/__init__.py +51 -0
- clm/layer5/async_batch_writer.py +133 -0
- clm/layer5/learning.py +276 -0
- clm/layer5/telemetry_hook.py +107 -0
- clm/layer5/type_lattice.py +238 -0
- clm/py.typed +0 -0
- clm/schemas/__init__.py +652 -0
- clm/schemas/abstract_face_schema.yaml +77 -0
- clm/schemas/cel_schema.yaml +416 -0
- clm/schemas/lifecycle/__init__.py +45 -0
- clm/schemas/lifecycle/models.py +123 -0
- clm/schemas/lifecycle/service.py +364 -0
- clm/schemas/mcard_schema.sql +192 -0
- clm/schemas/mcard_vector_schema.sql +283 -0
- clm/schemas/mlp-context-v1.json +91 -0
- clm_kernel-0.0.0.dist-info/METADATA +121 -0
- clm_kernel-0.0.0.dist-info/RECORD +333 -0
- clm_kernel-0.0.0.dist-info/WHEEL +4 -0
- clm_kernel-0.0.0.dist-info/entry_points.txt +3 -0
- 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
|
+
]
|