D-SafeLogger 0.2.0__tar.gz → 0.2.2__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 (171) hide show
  1. d_safelogger-0.2.2/CHANGELOG.md +118 -0
  2. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/CONTRIBUTING.md +8 -2
  3. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/PKG-INFO +13 -8
  4. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/README.md +12 -7
  5. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/README_ja.md +10 -5
  6. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/TESTING.md +73 -6
  7. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__async.md +1 -0
  8. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__color.md +1 -1
  9. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__formatter.md +1 -1
  10. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__handler.md +12 -0
  11. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__mp_attach.md +1 -1
  12. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__pipeline.md +7 -1
  13. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/design/D-SafeLogger_DetailedDesign_v23j.md +5 -4
  14. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/design/D-SafeLogger_TestDesign_v23j.md +24 -2
  15. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/design/D-SafeLogger_v23j_WhitePaper.md +20 -18
  16. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/design/D-SafeLogger_v23j_WhitePaper_en.md +23 -21
  17. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/design/D_SafeLogger_Specification_v23j_full.md +5 -1
  18. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/design/D_SafeLogger_Specification_v23j_full_en.md +5 -1
  19. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/examples/06_web_api_logging.md +2 -2
  20. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/pyproject.toml +10 -1
  21. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/D_SafeLogger.egg-info/PKG-INFO +13 -8
  22. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/D_SafeLogger.egg-info/SOURCES.txt +3 -1
  23. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/__init__.py +12 -6
  24. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_async.py +19 -9
  25. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_cli.py +1 -0
  26. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_color.py +2 -1
  27. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_constants.py +1 -0
  28. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_formatter.py +23 -7
  29. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_handler.py +18 -4
  30. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_levels.py +3 -2
  31. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_mp_attach.py +18 -8
  32. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_mp_protocol.py +9 -9
  33. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_mp_queue.py +10 -7
  34. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_mp_runtime.py +3 -1
  35. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_pipeline.py +20 -6
  36. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_routing.py +1 -1
  37. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_transport.py +2 -2
  38. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_writer_formatter.py +1 -1
  39. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/mp/__init__.py +2 -2
  40. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/examples/test_03_migration_from_stdlib.py +2 -2
  41. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/examples/test_06_web_api_logging.py +16 -6
  42. d_safelogger-0.2.2/tests/examples/test_07_long_running_service.py +35 -0
  43. d_safelogger-0.2.2/tests/examples/test_08_compliance_audit.py +64 -0
  44. d_safelogger-0.2.2/tests/examples/test_09_debugging_production.py +52 -0
  45. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/examples/test_11_async_performance.py +15 -15
  46. d_safelogger-0.2.2/tests/examples/test_12_multiprocess_logging.py +68 -0
  47. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/examples/test_14_cli_operations.py +14 -3
  48. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/examples/test_15_opentelemetry_logging.py +7 -2
  49. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/examples/test_16_structlog_coexistence.py +11 -6
  50. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/examples/test_17_container_collector_coexistence.py +2 -1
  51. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_async.py +31 -0
  52. d_safelogger-0.2.2/tests/test_diagnose.py +188 -0
  53. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_mp_configure.py +16 -0
  54. d_safelogger-0.2.2/tests/typing_smoke/__init__.py +0 -0
  55. d_safelogger-0.2.2/tests/typing_smoke/public_api_smoke.py +35 -0
  56. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/uv.lock +213 -1
  57. d_safelogger-0.2.0/CHANGELOG.md +0 -68
  58. d_safelogger-0.2.0/tests/examples/test_07_long_running_service.py +0 -31
  59. d_safelogger-0.2.0/tests/examples/test_08_compliance_audit.py +0 -46
  60. d_safelogger-0.2.0/tests/examples/test_09_debugging_production.py +0 -46
  61. d_safelogger-0.2.0/tests/examples/test_12_multiprocess_logging.py +0 -58
  62. d_safelogger-0.2.0/tests/test_diagnose.py +0 -66
  63. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/BENCHMARK.md +0 -0
  64. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/LICENSE +0 -0
  65. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/MANIFEST.in +0 -0
  66. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/SECURITY.md +0 -0
  67. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/benchmarks/_benchmark_report.py +0 -0
  68. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/benchmarks/results/benchmark_20260506_180018/summary.json +0 -0
  69. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/benchmarks/results/benchmark_20260506_180018/summary.md +0 -0
  70. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/benchmarks/results/benchmarks_multi_integ_20260506_185947/summary.json +0 -0
  71. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/benchmarks/results/benchmarks_multi_integ_20260506_185947/summary.md +0 -0
  72. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/benchmarks/results/benchmarks_multi_perf_20260506_190518/summary.json +0 -0
  73. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/benchmarks/results/benchmarks_multi_perf_20260506_190518/summary.md +0 -0
  74. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/benchmarks/results/benchmarks_multi_resilience_20260506_211129/summary.json +0 -0
  75. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/benchmarks/results/benchmarks_multi_resilience_20260506_211129/summary.md +0 -0
  76. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/benchmarks/summary/index.md +0 -0
  77. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/benchmarks/summary/manifest.json +0 -0
  78. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/benchmarks/summary/multiprocess_integrity.md +0 -0
  79. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/benchmarks/summary/multiprocess_performance.md +0 -0
  80. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/benchmarks/summary/multiprocess_resilience.md +0 -0
  81. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/benchmarks/summary/single_process.md +0 -0
  82. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/benchmarks/update_summary.py +0 -0
  83. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger.md +0 -0
  84. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__cli.md +0 -0
  85. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__config_validation.md +0 -0
  86. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__constants.md +0 -0
  87. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__context.md +0 -0
  88. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__env_parser.md +0 -0
  89. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__ini_loader.md +0 -0
  90. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__integrity.md +0 -0
  91. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__levels.md +0 -0
  92. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__logger.md +0 -0
  93. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__mp.md +0 -0
  94. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__mp_control.md +0 -0
  95. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__mp_protocol.md +0 -0
  96. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__mp_queue.md +0 -0
  97. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__mp_runtime.md +0 -0
  98. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__purge.md +0 -0
  99. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__routing.md +0 -0
  100. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__sink.md +0 -0
  101. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__transport.md +0 -0
  102. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__validator.md +0 -0
  103. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/dsafelogger__writer_formatter.md +0 -0
  104. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/docs/api/index.md +0 -0
  105. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/examples/01_quick_start.md +0 -0
  106. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/examples/02_configuration_guide.md +0 -0
  107. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/examples/03_migration_from_stdlib.md +0 -0
  108. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/examples/04_stdlib_ecosystem_coexistence.md +0 -0
  109. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/examples/05_windows_service_and_scheduled_batch.md +0 -0
  110. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/examples/07_long_running_service.md +0 -0
  111. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/examples/08_compliance_audit.md +0 -0
  112. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/examples/09_debugging_production.md +0 -0
  113. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/examples/10_incident_response_bundle.md +0 -0
  114. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/examples/11_async_performance.md +0 -0
  115. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/examples/12_multiprocess_logging.md +0 -0
  116. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/examples/13_external_rotation_reopen.md +0 -0
  117. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/examples/14_cli_operations.md +0 -0
  118. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/examples/15_opentelemetry_logging.md +0 -0
  119. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/examples/16_structlog_coexistence.md +0 -0
  120. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/examples/17_container_collector_coexistence.md +0 -0
  121. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/setup.cfg +0 -0
  122. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/D_SafeLogger.egg-info/dependency_links.txt +0 -0
  123. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/D_SafeLogger.egg-info/entry_points.txt +0 -0
  124. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/D_SafeLogger.egg-info/top_level.txt +0 -0
  125. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_config_validation.py +0 -0
  126. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_context.py +0 -0
  127. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_env_parser.py +0 -0
  128. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_ini_loader.py +0 -0
  129. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_integrity.py +0 -0
  130. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_logger.py +0 -0
  131. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_mp_control.py +0 -0
  132. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_purge.py +0 -0
  133. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_sink.py +0 -0
  134. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/_validator.py +0 -0
  135. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/src/dsafelogger/py.typed +0 -0
  136. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/conftest.py +0 -0
  137. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/examples/test_04_stdlib_ecosystem_coexistence.py +0 -0
  138. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/examples/test_05_windows_service_and_scheduled_batch.py +0 -0
  139. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/examples/test_10_incident_response_bundle.py +0 -0
  140. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/examples/test_13_external_rotation_reopen.py +0 -0
  141. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_cli.py +0 -0
  142. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_color.py +0 -0
  143. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_configure.py +0 -0
  144. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_context.py +0 -0
  145. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_coverage_boost.py +0 -0
  146. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_env_parser.py +0 -0
  147. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_formatter.py +0 -0
  148. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_getlogger.py +0 -0
  149. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_handler.py +0 -0
  150. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_ini_loader.py +0 -0
  151. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_integration.py +0 -0
  152. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_integrity.py +0 -0
  153. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_levels.py +0 -0
  154. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_logger.py +0 -0
  155. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_merge.py +0 -0
  156. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_mp_attach.py +0 -0
  157. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_mp_control.py +0 -0
  158. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_mp_fork.py +0 -0
  159. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_mp_formatter.py +0 -0
  160. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_mp_integration.py +0 -0
  161. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_mp_runtime.py +0 -0
  162. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_mp_spawn_windows.py +0 -0
  163. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_opentelemetry.py +0 -0
  164. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_pipeline.py +0 -0
  165. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_purge.py +0 -0
  166. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_reopen.py +0 -0
  167. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_routing.py +0 -0
  168. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_structlog.py +0 -0
  169. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_transport.py +0 -0
  170. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_validator.py +0 -0
  171. {d_safelogger-0.2.0 → d_safelogger-0.2.2}/tests/test_version.py +0 -0
@@ -0,0 +1,118 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.2.2] - 2026-05-21
11
+
12
+ ### Added
13
+ - Type validation as a CI quality gate: `mypy` and `pyright` are now required dev dependencies; `publication-checks` runs `uv run mypy src` and `uv run pyright src` on every push.
14
+ - `scripts/install_built_wheel.py` — helper for installing the freshly built wheel into the uv-managed venv before running `pyright --verifytypes` against the packaged module (rather than the editable source tree).
15
+ - `scripts/check_type_completeness.py` — threshold gate for `pyright --verifytypes dsafelogger --ignoreexternal`; CI now requires 100% public type completeness from the built wheel.
16
+ - `scripts/check_distribution_contents.py` — standalone script replacing the inline heredoc in `publish.yml`; adds `dsafelogger/py.typed` (wheel) and `src/dsafelogger/py.typed` (sdist) to required-path checks. Also wired into `ci.yml` `publication-checks`.
17
+ - `tests/typing_smoke/public_api_smoke.py` — pyright-only smoke test covering `ConfigureLogger`, `GetLogger`, `contextualize`, and `mp.ConfigureLogger` / `mp.GetWorkerInitializer` from a user import perspective. The directory is named `typing_smoke` (not `typing`) to avoid shadowing the stdlib `typing` module in spawn child processes. Not collected by pytest (filename does not match `test_*.py`); checked by `uv run pyright tests/typing_smoke` in `publication-checks`.
18
+ - `dsafelogger._handler.ReopenableHandler` — `@runtime_checkable` Protocol that narrows `logging.Handler` references to those exposing `reopen()`; replaces internal `hasattr(h, 'reopen')` checks for static type checking.
19
+
20
+ ### Changed
21
+ - `dsafelogger._pipeline.ResolvedConfig.sensitive_keywords` now defaults to `BUILTIN_SENSITIVE_KEYWORDS` directly (previously `field(default_factory=frozenset)`). Behaviour is preserved by the existing `or BUILTIN_SENSITIVE_KEYWORDS` consumer fallback; the API docs now show the concrete default value rather than `<factory>`.
22
+ - `dsafelogger._mp_protocol.LogEvent` TypedDict fields `process`, `processName`, `thread`, `threadName` are now `int | None` / `str | None`, aligning with stdlib `logging.LogRecord` semantics (None is a legal value for these attributes).
23
+ - `dsafelogger._formatter.DSafeFormatter.__init__` `style` parameter is now typed `Literal['%', '{', '$']` instead of `str`, matching `logging.Formatter`.
24
+
25
+ ### Fixed
26
+ - `dsafelogger._routing.NoneStrategy.advance()` now returns the current path instead of implicitly returning `None`, satisfying its `Path` return-type contract (no observable behaviour change; `should_switch()` always returns `False` so the method is unreachable in production).
27
+ - `dsafelogger._cli` tail follow loop asserts that the open file handle is non-`None` before reuse (defensive narrowing; the assert is unreachable in normal execution).
28
+ - `dsafelogger._shutdown()` acquires the root logger reference before the `try` block so the `finally` block always has it available, even if an exception is raised before the original assignment site.
29
+
30
+ ### Internal
31
+ - Removed 19 stale `# type: ignore[...]` comments that mypy 2.1 no longer requires.
32
+ - Annotated 4 previously untyped functions (`_levels._make_log_method`, `_color.ColorStreamHandler.__init__`, `_transport.TransportFactory.create`).
33
+ - `dsafelogger._mp_queue.TrackedQueue.__getstate__` / `__setstate__` are now explicitly marked `# type: ignore[override]` with a comment documenting the intentional `_QueueState` extension; cross-platform `qsize()` and `empty()` are coerced via `int(...)` / `bool(...)` to satisfy `warn_return_any`.
34
+ - `dsafelogger._mp_attach._validate_attach_ack` and `dsafelogger.mp._validate_bootstrap_ready_ack` now accept `ControlAck` TypedDict directly (previously `dict[str, Any]` / `dict[str, object]`).
35
+ - `pyproject.toml` adds `[tool.pyright]` (basic mode, `include = ["src"]`).
36
+ - `TESTING.md` gains a Type Validation section describing the local-green-before-push policy, recorded versions, and the private module surface rule.
37
+ - `README.md` / `README_ja.md` typing bullet updated to mention the CI type-check gate.
38
+ - `CONTRIBUTING.md` adds `uv run mypy src` / `uv run pyright src` to the required PR pre-flight commands and documents the private module surface policy.
39
+ - Public v23j design documents now describe the 0.2.2 type-validation gate, including source typing, `tests/typing_smoke`, built-wheel verifytypes, and the stdlib `typing` shadowing guard.
40
+ - API docs regenerated for `_color`, `_formatter`, `_handler`, `_mp_attach`, `_pipeline`.
41
+
42
+ ## [0.2.1] - 2026-05-20
43
+
44
+ ### Fixed
45
+ - Apply resolved `sens_kws` / `sens_kws_replace` to diagnostic local-variable snapshots across sync text, sync structured, async snapshot, and multiprocess Writer formatter paths.
46
+ - Preserve async producer-side diagnostic frame snapshots in text diagnostic output.
47
+ - Align daily routing examples with the implemented `YYYYMMDD` filename suffix.
48
+
49
+ ### Changed
50
+ - Updated example tests to match the documented runnable examples for migration, web API, long-running service, compliance audit, production debugging, async performance, multiprocess logging, CLI operations, OpenTelemetry, structlog, and container collector coexistence scenarios.
51
+ - Updated public docs, API docs, and test/coverage baselines for the 0.2.1 patch release.
52
+
53
+ ### Verified
54
+ - Full local validation on Python 3.14.3 / Windows: `658 passed, 3 skipped` (`661` collected).
55
+ - Coverage validation regenerated `coverage.xml`: terminal total `87%`, line-rate `88.97%`, branch-rate `81.46%`.
56
+ - API docs, design-doc sync, and whitespace checks pass; `git diff --check` reports only CRLF/LF warnings.
57
+
58
+ ## [0.2.0] - 2026-05-05
59
+
60
+ ### Added
61
+ - Formal multiprocess public API under `dsafelogger.mp`, including `ConfigureLogger`, `AttachCurrentProcess`, `DetachCurrentProcess`, `GetLogger`, `GetWorkerInitializer`, and `ReopenLogFiles`.
62
+ - Writer-runtime multiprocess architecture with separate log plane and control plane, CloseMarker-based drain, explicit attach/detach, and bounded shutdown behavior.
63
+ - Classified multiprocess delivery-state counters for route/reconstruct/close-marker/sink/policy rejects, partial delivery, best-effort failures, timeout drops, overload shed, and drain-deadline loss.
64
+ - `TrackedQueue` for qsize-visible multiprocess log queues with platform fallback.
65
+ - Multiprocess comparison benchmark runner at `benchmarks/run_multiprocess_compare_v23a.py` with integrity, performance, overload, and resilience profiles.
66
+ - Benchmark summary manifest workflow via `benchmarks/summary/manifest.json` and `benchmarks/update_summary.py`.
67
+ - Generated benchmark summary documents under `benchmarks/summary/` while keeping `BENCHMARK.md` manually edited.
68
+ - `optional_integration` pytest marker for OpenTelemetry and structlog coexistence tests while keeping them in the official full test run.
69
+ - v23j public design documents under `docs/design/` reflecting formal MP, dev full-test policy, manifest-based benchmark publication, and strict invalid-configuration handling.
70
+ - Shared v23j configuration validation for single-process, module-specific, and multiprocess file sinks.
71
+ - Generated API documentation under `docs/api/` with `scripts/generate_api_docs.py --check`.
72
+ - Public design-document readiness check via `scripts/check_design_docs_sync.py`.
73
+ - Multiprocess and external-rotation tutorials covering `dsafelogger.mp` and `ReopenLogFiles()`.
74
+
75
+ ### Changed
76
+ - Updated `README.md`, `README_ja.md`, `TESTING.md`, and `BENCHMARK.md` to describe the current v23j design, test policy, benchmark interpretation, and formal multiprocess support.
77
+ - Invalid routing/generation/hash combinations are now fail-fast `ValueError` cases instead of warnings or silent no-ops.
78
+ - `structured=True` is mutually exclusive with `fmt`, `file_fmt`, and `console_fmt` after all config layers are merged.
79
+ - `file_fmt` and `console_fmt` are now accepted by the single-process API and INI/config_dict loader, matching the public design docs.
80
+ - Multiprocess module-specific levels are propagated to attached worker loggers.
81
+ - Multiprocess spawn integration tests now use the same multiprocessing context for Writer IPC primitives and worker process creation.
82
+ - Multiprocess log queue creation now classifies platform-rejected `ipc_log_queue_maxsize` values as `ValueError` before Writer sinks are started, while preserving runtime errors for non-validation OS failures.
83
+ - Tests no longer depend on `multiprocessing.Queue.empty()` for correctness.
84
+ - Benchmark runners now write session artifacts only; they no longer regenerate top-level `BENCHMARK.md`.
85
+ - Official testing policy is now `uv sync --group dev` followed by the full `uv run pytest tests -v` run.
86
+ - Package metadata version and public `dsafelogger.__version__` are both `0.2.0`; project classifier is now Beta.
87
+ - Package license metadata now uses SPDX `license = "Apache-2.0"` and `license-files = ["LICENSE"]`.
88
+ - GitHub CI now checks generated API docs, design-document sync, benchmark summaries, and package build output.
89
+ - PyPI publish workflow now verifies tag/version consistency and repeats publication preflight checks before publishing.
90
+ - GitHub CI now includes Ubuntu free-threaded CPython `3.13t` and `3.14t` test jobs with `PYTHON_GIL=0`.
91
+
92
+ ### Verified
93
+ - Full local v23j validation on Python 3.14.3 / Windows: `651 passed, 3 skipped` (`654` collected). Skip counts can vary by platform because fork tests are POSIX-only and Windows spawn tests are Windows-only.
94
+ - Targeted v23j configuration validation: `256 passed` across configure, routing, INI, reopen, and MP integration tests.
95
+ - Coverage validation regenerated `coverage.xml`: terminal total `86%`, line-rate `88.49%`, branch-rate `80.53%`.
96
+ - Targeted regression validation for MP runtime, MP integration, OpenTelemetry, and structlog tests: `91 passed`.
97
+ - Benchmark summary manifest generation and `--check` verification pass.
98
+
99
+ ## [0.1.0] - 2026-04-03
100
+
101
+ ### Added
102
+ - Initial release
103
+ - 3-layer configuration pipeline (Environment → INI/Dict → Arguments)
104
+ - 9 routing strategies (none, daily, hourly, min_interval, startup_interval, size, count, cyclic_weekday, cyclic_month)
105
+ - Append-only file handler (Windows lock-safe)
106
+ - SHA-256 integrity verification with sidecar files and manifest
107
+ - Structured JSON Lines output
108
+ - Diagnostic formatter with f_locals expansion and sensitive data masking
109
+ - ANSI color console output with customizable palette
110
+ - Async logging mode with context-preserving QueueHandler
111
+ - Custom log level registration with `register_level()`
112
+ - `contextualize()` context manager for structured log context
113
+ - CLI tool (`dsafelogger init/ls/tail -f`)
114
+ - Free-threaded Python (3.13t/3.14t) support with explicit locks
115
+ - Per-module log level and file routing
116
+ - INI file and dict-based configuration
117
+ - Safe shutdown with worker thread join
118
+ - Complete standard library `logging` compatibility
@@ -51,6 +51,9 @@ cd D-SafeLogger
51
51
  uv sync --group dev
52
52
  uv run pytest tests/ -v
53
53
  uv run ruff check src/ tests/
54
+ uv run mypy src
55
+ uv run pyright src
56
+ uv run pyright tests/typing_smoke
54
57
  ```
55
58
 
56
59
  ## 6. Code Style
@@ -58,14 +61,17 @@ uv run ruff check src/ tests/
58
61
  - **PEP 8**, max **100** characters per line.
59
62
  - **ruff** for linting (`uv run ruff check src/ tests/`).
60
63
  - **Type hints required** — use Python 3.11+ `X | Y` union syntax.
64
+ - **Typing must stay green**: `uv run mypy src`, `uv run pyright src`, and `uv run pyright tests/typing_smoke` must report `0 errors` locally before opening a PR. CI also enforces 100% public type completeness with `pyright --verifytypes` against the built wheel.
65
+ - Private module surface (names starting with `_`, e.g. `dsafelogger._constants.MASK_STRING`) is **not** part of the public API even though `py.typed` exposes it to user type checkers. Do not encourage external dependence on these names; rename / reshape freely as needed.
61
66
 
62
67
  ## 7. Pull Request Process
63
68
 
64
69
  1. Create a feature branch from `main`.
65
70
  2. Add tests for new functionality.
66
71
  3. Ensure **all** tests pass: `uv run pytest tests/ -v`.
67
- 4. Update documentation if needed.
68
- 5. Submit a PR with a clear description referencing the accepted issue.
72
+ 4. Verify type checks pass: `uv run mypy src`, `uv run pyright src`, and `uv run pyright tests/typing_smoke` (all must report `0 errors`).
73
+ 5. Update documentation if needed.
74
+ 6. Submit a PR with a clear description referencing the accepted issue.
69
75
 
70
76
  ## License
71
77
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: D-SafeLogger
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Zero-dependency, thread-safe, append-only logging library for Python with 3-layer config pipeline
5
5
  Author: D
6
6
  License-Expression: Apache-2.0
@@ -28,8 +28,8 @@ Dynamic: license-file
28
28
  # D-SafeLogger
29
29
 
30
30
  [![CI](https://github.com/nightmarewalker/D-SafeLogger/actions/workflows/ci.yml/badge.svg)](https://github.com/nightmarewalker/D-SafeLogger/actions/workflows/ci.yml)
31
- [![PyPI version](https://img.shields.io/pypi/v/d-safelogger.svg)](https://pypi.org/project/d-safelogger/)
32
- [![Python](https://img.shields.io/pypi/pyversions/d-safelogger.svg)](https://pypi.org/project/d-safelogger/)
31
+ [![PyPI version](https://img.shields.io/pypi/v/d-safelogger.svg?cacheSeconds=3600)](https://pypi.org/project/d-safelogger/)
32
+ [![Python](https://img.shields.io/pypi/pyversions/d-safelogger.svg?cacheSeconds=3600)](https://pypi.org/project/d-safelogger/)
33
33
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
34
34
  [![Zero Dependencies](https://img.shields.io/badge/dependencies-zero-brightgreen.svg)](#main-features)
35
35
 
@@ -66,7 +66,7 @@ logger = GetLogger(__name__)
66
66
  logger.info("Application started")
67
67
  ```
68
68
 
69
- `pg_name` is the application name used as the prefix of routed log file names, for example `MyApp_2026-04-03.log`.
69
+ `pg_name` is the application name used as the prefix of routed log file names, for example `MyApp_20260403.log`.
70
70
 
71
71
  Typical text output:
72
72
 
@@ -122,7 +122,7 @@ The "Safe" in the name is a design stance that runs across several dimensions of
122
122
 
123
123
  - **Startup safety:** invalid settings, inconsistent options, and unwritable destinations fail during setup. D-SafeLogger stops a broken logging configuration before the application starts doing real work, instead of silently degrading later.
124
124
  - **File safety:** the routing layer opens the next destination instead of renaming or truncating the active log file, which avoids the common Windows failure mode where active log files cannot be renamed. It also avoids the POSIX case where a successful rename leaves the writer appending to the previous file. Routed files can be paired with SHA-256 sidecars and an optional manifest, so log content is verifiable after the fact.
125
- - **Record and context safety:** request IDs, user IDs, job IDs, and other context are snapshotted on the producer side at hand-off, so listeners and Writers do not depend on live `contextvars`. Sensitive-keyword masking is applied on the Writer side using the keyword set established at configure time.
125
+ - **Record and context safety:** request IDs, user IDs, job IDs, and other context are snapshotted on the producer side at hand-off, so listeners and Writers do not depend on live `contextvars`. Diagnostic local-variable snapshots and Writer-side formatting use the sensitive-keyword set established at configure time.
126
126
  - **Operational control:** environment variables provide explicit runtime overrides for diagnostics, routing, hashing, log levels, and queue/timeout behavior without rebuilding or editing application code.
127
127
  - **Concurrency and multiprocess safety:** multiprocess workers do not open the shared log files themselves. A parent-side Writer owns the sinks and accepts records over IPC, with bounded queues and explicit timeouts that keep the host process from unbounded waits.
128
128
  - **Failure observability:** when records cannot be delivered, the runtime classifies the outcome where it can: `KnownRejected`, `KnownDropped`, or `UnexplainedLost`. Counters and shutdown summaries make abnormal scenarios describable rather than silent.
@@ -182,11 +182,12 @@ Notes:
182
182
  - **Centralized setup:** replace common `basicConfig()`, `dictConfig()`, formatter, handler, and rotating-file boilerplate with `ConfigureLogger()`.
183
183
  - **Fail-fast initialization:** invalid configuration and unwritable log destinations fail during setup instead of degrading silently.
184
184
  - **Append-only file routing:** the routing layer opens the next destination instead of renaming or truncating the active log file. This avoids the common Windows failure mode where active log files cannot be renamed, and it avoids the POSIX case where a writer may continue writing to the previous file after a successful rename.
185
+ - **Retention for routed files:** routed files can be kept by `backup_count`; older files can be deleted by the purge worker or ZIP-archived with `archive_mode=True`.
185
186
  - **Classified delivery state:** loss, reject, and drop events are not treated as invisible file gaps. When records cannot be delivered, the runtime classifies the outcome as known-rejected, known-dropped, or unexplained-lost where applicable.
186
187
  - **Bounded logging path:** D-SafeLogger uses bounded queues, explicit timeouts, and explicit rejection paths to avoid unbounded logging-side waits in the host process.
187
188
  - **Structured JSON Lines:** emit log records as JSON fields for log collectors and observability pipelines.
188
189
  - **Contextual logging:** attach request IDs, user IDs, job IDs, or other context with thread-safe and async-safe propagation. Producer-side context snapshots are taken at hand-off so listeners and Writers do not look up live `contextvars`.
189
- - **Integrity sidecars:** generate SHA-256 sidecars and optional manifest entries for routed log files.
190
+ - **Integrity sidecars:** generate SHA-256 sidecars and optional manifest entries for routed log files. This is tamper-evidence for closed files, not an access-control or compliance system.
190
191
  - **Operational overrides:** change log level, module routing, console output, color, hashing, config file path, and queue/timeout parameters through environment variables, typically to raise diagnostics in production without code changes.
191
192
  - **Environment-only diagnostic mode:** opt in via `D_LOG_DIAGNOSE=1` for `f_locals` expansion of selected frames; deliberately not exposed through INI or arguments, so it cannot be enabled by an unowned configuration file.
192
193
  - **Async transport:** opt in to queue-backed logging when application threads should avoid direct sink writes.
@@ -200,6 +201,8 @@ Notes:
200
201
 
201
202
  In this mode, a parent-side Writer owns the file sinks. Workers attach to the Writer and submit log records through IPC. This centralizes file ownership and exposes delivery-state counters such as accepted, delivered, rejected, dropped, and unexplained-lost.
202
203
 
204
+ The Writer shutdown path is bounded: it attempts to drain and join within a timeout, emits a visible warning if drain is incomplete, and avoids hanging the host process indefinitely.
205
+
203
206
  For setup code, the `multiprocessing` context rules, pool initializer, `ProcessPoolExecutor` integration, Windows spawn caveats, custom log levels, attach/detach lifecycle, environment-variable knobs, and shutdown handling, see [`examples/12_multiprocess_logging.md`](examples/12_multiprocess_logging.md).
204
207
 
205
208
  Public API in `dsafelogger.mp`: `ConfigureLogger`, `AttachCurrentProcess`, `DetachCurrentProcess`, `GetLogger`, `GetWorkerInitializer`, `ReopenLogFiles`.
@@ -256,11 +259,13 @@ Suggested reading paths:
256
259
 
257
260
  D-SafeLogger is competitive in the selected single-process async benchmark runs. In multiprocess benchmarks, raw throughput is not the differentiator; parent-side file output and classified delivery-state accounting are.
258
261
 
262
+ The benchmark suite also includes multiprocess resilience profiles, such as sink-unavailable, burst backpressure, worker crash, mixed worker behavior, and shutdown behavior. These runs are not throughput claims; they check whether attempted records can be accounted for as delivered, known-rejected, known-dropped, or unexplained-lost.
263
+
259
264
  See [BENCHMARK.md](BENCHMARK.md) for the selected runs, methodology, and the explicit "what to claim / what not to claim" boundaries, and [`benchmarks/summary/`](benchmarks/summary/) for the published summaries.
260
265
 
261
266
  ## Testing / Quality
262
267
 
263
- The release gate runs the full dev test suite across Windows, macOS, and Linux on Python 3.11-3.14. Publication checks also verify generated API docs, public design documents, benchmark summaries, and package build output.
268
+ The release gate runs the full dev test suite across Windows, macOS, and Linux on Python 3.11-3.14. CI also runs Ubuntu free-threaded CPython `3.13t` and `3.14t` compatibility jobs with `PYTHON_GIL=0`. Publication checks also verify generated API docs, public design documents, benchmark summaries, and package build output.
264
269
 
265
270
  See [TESTING.md](TESTING.md) for details.
266
271
 
@@ -269,7 +274,7 @@ See [TESTING.md](TESTING.md) for details.
269
274
  - Python: 3.11 or newer.
270
275
  - OS: Windows, macOS, and Linux.
271
276
  - Runtime dependencies: none.
272
- - Typing: includes `py.typed`.
277
+ - Typing: includes `py.typed`; CI checks `mypy`, `pyright`, typing smoke tests, and 100% public type completeness with `pyright --verifytypes`. See [TESTING.md](TESTING.md).
273
278
  - API docs: [`docs/api/`](docs/api/).
274
279
  - Design docs: [`docs/design/`](docs/design/).
275
280
  - Distribution name is `d-safelogger` (with hyphen); import name is `dsafelogger` (no separator).
@@ -1,8 +1,8 @@
1
1
  # D-SafeLogger
2
2
 
3
3
  [![CI](https://github.com/nightmarewalker/D-SafeLogger/actions/workflows/ci.yml/badge.svg)](https://github.com/nightmarewalker/D-SafeLogger/actions/workflows/ci.yml)
4
- [![PyPI version](https://img.shields.io/pypi/v/d-safelogger.svg)](https://pypi.org/project/d-safelogger/)
5
- [![Python](https://img.shields.io/pypi/pyversions/d-safelogger.svg)](https://pypi.org/project/d-safelogger/)
4
+ [![PyPI version](https://img.shields.io/pypi/v/d-safelogger.svg?cacheSeconds=3600)](https://pypi.org/project/d-safelogger/)
5
+ [![Python](https://img.shields.io/pypi/pyversions/d-safelogger.svg?cacheSeconds=3600)](https://pypi.org/project/d-safelogger/)
6
6
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
7
7
  [![Zero Dependencies](https://img.shields.io/badge/dependencies-zero-brightgreen.svg)](#main-features)
8
8
 
@@ -39,7 +39,7 @@ logger = GetLogger(__name__)
39
39
  logger.info("Application started")
40
40
  ```
41
41
 
42
- `pg_name` is the application name used as the prefix of routed log file names, for example `MyApp_2026-04-03.log`.
42
+ `pg_name` is the application name used as the prefix of routed log file names, for example `MyApp_20260403.log`.
43
43
 
44
44
  Typical text output:
45
45
 
@@ -95,7 +95,7 @@ The "Safe" in the name is a design stance that runs across several dimensions of
95
95
 
96
96
  - **Startup safety:** invalid settings, inconsistent options, and unwritable destinations fail during setup. D-SafeLogger stops a broken logging configuration before the application starts doing real work, instead of silently degrading later.
97
97
  - **File safety:** the routing layer opens the next destination instead of renaming or truncating the active log file, which avoids the common Windows failure mode where active log files cannot be renamed. It also avoids the POSIX case where a successful rename leaves the writer appending to the previous file. Routed files can be paired with SHA-256 sidecars and an optional manifest, so log content is verifiable after the fact.
98
- - **Record and context safety:** request IDs, user IDs, job IDs, and other context are snapshotted on the producer side at hand-off, so listeners and Writers do not depend on live `contextvars`. Sensitive-keyword masking is applied on the Writer side using the keyword set established at configure time.
98
+ - **Record and context safety:** request IDs, user IDs, job IDs, and other context are snapshotted on the producer side at hand-off, so listeners and Writers do not depend on live `contextvars`. Diagnostic local-variable snapshots and Writer-side formatting use the sensitive-keyword set established at configure time.
99
99
  - **Operational control:** environment variables provide explicit runtime overrides for diagnostics, routing, hashing, log levels, and queue/timeout behavior without rebuilding or editing application code.
100
100
  - **Concurrency and multiprocess safety:** multiprocess workers do not open the shared log files themselves. A parent-side Writer owns the sinks and accepts records over IPC, with bounded queues and explicit timeouts that keep the host process from unbounded waits.
101
101
  - **Failure observability:** when records cannot be delivered, the runtime classifies the outcome where it can: `KnownRejected`, `KnownDropped`, or `UnexplainedLost`. Counters and shutdown summaries make abnormal scenarios describable rather than silent.
@@ -155,11 +155,12 @@ Notes:
155
155
  - **Centralized setup:** replace common `basicConfig()`, `dictConfig()`, formatter, handler, and rotating-file boilerplate with `ConfigureLogger()`.
156
156
  - **Fail-fast initialization:** invalid configuration and unwritable log destinations fail during setup instead of degrading silently.
157
157
  - **Append-only file routing:** the routing layer opens the next destination instead of renaming or truncating the active log file. This avoids the common Windows failure mode where active log files cannot be renamed, and it avoids the POSIX case where a writer may continue writing to the previous file after a successful rename.
158
+ - **Retention for routed files:** routed files can be kept by `backup_count`; older files can be deleted by the purge worker or ZIP-archived with `archive_mode=True`.
158
159
  - **Classified delivery state:** loss, reject, and drop events are not treated as invisible file gaps. When records cannot be delivered, the runtime classifies the outcome as known-rejected, known-dropped, or unexplained-lost where applicable.
159
160
  - **Bounded logging path:** D-SafeLogger uses bounded queues, explicit timeouts, and explicit rejection paths to avoid unbounded logging-side waits in the host process.
160
161
  - **Structured JSON Lines:** emit log records as JSON fields for log collectors and observability pipelines.
161
162
  - **Contextual logging:** attach request IDs, user IDs, job IDs, or other context with thread-safe and async-safe propagation. Producer-side context snapshots are taken at hand-off so listeners and Writers do not look up live `contextvars`.
162
- - **Integrity sidecars:** generate SHA-256 sidecars and optional manifest entries for routed log files.
163
+ - **Integrity sidecars:** generate SHA-256 sidecars and optional manifest entries for routed log files. This is tamper-evidence for closed files, not an access-control or compliance system.
163
164
  - **Operational overrides:** change log level, module routing, console output, color, hashing, config file path, and queue/timeout parameters through environment variables, typically to raise diagnostics in production without code changes.
164
165
  - **Environment-only diagnostic mode:** opt in via `D_LOG_DIAGNOSE=1` for `f_locals` expansion of selected frames; deliberately not exposed through INI or arguments, so it cannot be enabled by an unowned configuration file.
165
166
  - **Async transport:** opt in to queue-backed logging when application threads should avoid direct sink writes.
@@ -173,6 +174,8 @@ Notes:
173
174
 
174
175
  In this mode, a parent-side Writer owns the file sinks. Workers attach to the Writer and submit log records through IPC. This centralizes file ownership and exposes delivery-state counters such as accepted, delivered, rejected, dropped, and unexplained-lost.
175
176
 
177
+ The Writer shutdown path is bounded: it attempts to drain and join within a timeout, emits a visible warning if drain is incomplete, and avoids hanging the host process indefinitely.
178
+
176
179
  For setup code, the `multiprocessing` context rules, pool initializer, `ProcessPoolExecutor` integration, Windows spawn caveats, custom log levels, attach/detach lifecycle, environment-variable knobs, and shutdown handling, see [`examples/12_multiprocess_logging.md`](examples/12_multiprocess_logging.md).
177
180
 
178
181
  Public API in `dsafelogger.mp`: `ConfigureLogger`, `AttachCurrentProcess`, `DetachCurrentProcess`, `GetLogger`, `GetWorkerInitializer`, `ReopenLogFiles`.
@@ -229,11 +232,13 @@ Suggested reading paths:
229
232
 
230
233
  D-SafeLogger is competitive in the selected single-process async benchmark runs. In multiprocess benchmarks, raw throughput is not the differentiator; parent-side file output and classified delivery-state accounting are.
231
234
 
235
+ The benchmark suite also includes multiprocess resilience profiles, such as sink-unavailable, burst backpressure, worker crash, mixed worker behavior, and shutdown behavior. These runs are not throughput claims; they check whether attempted records can be accounted for as delivered, known-rejected, known-dropped, or unexplained-lost.
236
+
232
237
  See [BENCHMARK.md](BENCHMARK.md) for the selected runs, methodology, and the explicit "what to claim / what not to claim" boundaries, and [`benchmarks/summary/`](benchmarks/summary/) for the published summaries.
233
238
 
234
239
  ## Testing / Quality
235
240
 
236
- The release gate runs the full dev test suite across Windows, macOS, and Linux on Python 3.11-3.14. Publication checks also verify generated API docs, public design documents, benchmark summaries, and package build output.
241
+ The release gate runs the full dev test suite across Windows, macOS, and Linux on Python 3.11-3.14. CI also runs Ubuntu free-threaded CPython `3.13t` and `3.14t` compatibility jobs with `PYTHON_GIL=0`. Publication checks also verify generated API docs, public design documents, benchmark summaries, and package build output.
237
242
 
238
243
  See [TESTING.md](TESTING.md) for details.
239
244
 
@@ -242,7 +247,7 @@ See [TESTING.md](TESTING.md) for details.
242
247
  - Python: 3.11 or newer.
243
248
  - OS: Windows, macOS, and Linux.
244
249
  - Runtime dependencies: none.
245
- - Typing: includes `py.typed`.
250
+ - Typing: includes `py.typed`; CI checks `mypy`, `pyright`, typing smoke tests, and 100% public type completeness with `pyright --verifytypes`. See [TESTING.md](TESTING.md).
246
251
  - API docs: [`docs/api/`](docs/api/).
247
252
  - Design docs: [`docs/design/`](docs/design/).
248
253
  - Distribution name is `d-safelogger` (with hyphen); import name is `dsafelogger` (no separator).
@@ -39,7 +39,7 @@ logger = GetLogger(__name__)
39
39
  logger.info("Application started")
40
40
  ```
41
41
 
42
- `pg_name` はルーティング後のログファイル名の接頭辞として使われるアプリケーション名です。例: `MyApp_2026-04-03.log`。
42
+ `pg_name` はルーティング後のログファイル名の接頭辞として使われるアプリケーション名です。例: `MyApp_20260403.log`。
43
43
 
44
44
  標準的なテキスト出力:
45
45
 
@@ -95,7 +95,7 @@ D-SafeLogger は、active file を後から動かす代わりに、書き込み
95
95
 
96
96
  - **起動時の安全性:** 不正な設定値、矛盾したオプション、書き込めない出力先は初期化時に失敗させます。壊れた logging 構成のまま本体処理を進め、あとから気づきにくい形で動作が崩れることを防ぎます。
97
97
  - **ファイルの安全性:** ルーティング層は使用中のログファイルを rename / truncate せず、境界到達時に次の出力先を開きます。これにより active file の rename に起因する Windows 特有の失敗を避けられます。また、POSIX 系で rename が成功しても writer が古い file descriptor へ書き続ける、という世代切り替えのずれも避けられます。ルーティング済みファイルには SHA-256 sidecar と、任意で manifest を付けられ、後からログ内容を検証できます。
98
- - **レコードとコンテキストの安全性:** request ID、user ID、job ID といったコンテキストは producer 側で snapshot を取り、listener / Writer 側では live な `contextvars` を参照しません。機微情報のマスキングは Writer 側で、初期化時に確定したキーワード集合を使って適用されます。
98
+ - **レコードとコンテキストの安全性:** request ID、user ID、job ID といったコンテキストは producer 側で snapshot を取り、listener / Writer 側では live な `contextvars` を参照しません。diagnostic のローカル変数 snapshot と Writer 側 formatting では、初期化時に確定した機微情報キーワード集合を使います。
99
99
  - **運用時の制御:** 環境変数により、コードを変更せずにログレベル、診断出力、モジュール別ルーティング、ハッシュ出力、キュー / timeout 設定を切り替えられます。
100
100
  - **並行性とマルチプロセスの安全性:** マルチプロセスでは worker が共有のログファイルを直接開かず、親プロセス側の Writer が出力先を所有して IPC でレコードを受け付けます。上限つきのキューと明示的な timeout により、本体プロセスが無制限に待ち続けることを避けます。
101
101
  - **失敗の可観測性:** 配送できなかったレコードは、可能な範囲で `KnownRejected` / `KnownDropped` / `UnexplainedLost` のいずれかに分類されます。カウンタと shutdown summary により、異常時のふるまいが見落とされず、説明できる形で残ります。
@@ -155,11 +155,12 @@ D-SafeLogger は、active file を後から動かす代わりに、書き込み
155
155
  - **中央初期化:** `basicConfig()`、`dictConfig()`、formatter、handler、rotation 設定の boilerplate を `ConfigureLogger()` に集約できます。
156
156
  - **fail-fast 初期化:** 不正な設定値や書き込めないログ出力先は初期化時に失敗させ、あとから気づきにくい形で動作が崩れることを避けます。
157
157
  - **追記専用のファイルルーティング:** ルーティング層は、使用中のログファイルを rename / truncate せず、境界到達時に次の出力先を開きます。Windows の active file rename 失敗だけでなく、POSIX 系で rename が成功したまま writer が旧世代へ書き続ける問題も避けられます。
158
+ - **ルーティング済みファイルの保持管理:** ルーティング済みファイルは `backup_count` に基づいて保持できます。古いファイルは purge worker による削除、または `archive_mode=True` による ZIP archive 化が可能です。
158
159
  - **配送状態の分類:** 失われたレコードをファイル上の見えない欠損として扱わず、可能な範囲で known-rejected / known-dropped / unexplained-lost に分類します。
159
160
  - **境界をもった logging 経路:** 上限つきキュー、明示的な timeout、明示的な拒否経路を使うことで、logging 処理が本体プロセス側で無制限に待ち続ける設計を避けます。
160
161
  - **JSON Lines 出力:** ログ収集基盤や監視基盤へ渡しやすい JSON 形式で出力できます。
161
162
  - **コンテキスト付与:** request ID、user ID、job ID などを、スレッドや非同期境界をまたいでログへ付与できます。`contextvars` の snapshot は producer 側で取り、Writer 側では live な `contextvars` を参照しません。
162
- - **整合性 sidecar:** ルーティング済みログファイルに対して SHA-256 sidecar と、任意で manifest を出力できます。
163
+ - **整合性 sidecar:** ルーティング済みログファイルに対して SHA-256 sidecar と、任意で manifest を出力できます。これは closed file の改ざんや破損を後から検出しやすくするためのもので、access-control system や compliance system ではありません。
163
164
  - **運用時の上書き:** ログレベル、モジュール別ルーティング、コンソール出力、色、ハッシュ、設定ファイルパス、キュー / timeout 関連を環境変数で変更できます。本番障害時にコードを変更せず診断レベルを上げる用途を主に想定しています。
164
165
  - **環境変数限定の診断モード:** `D_LOG_DIAGNOSE=1` を有効にすると、選択フレームの `f_locals` を展開できます。INI や引数からは意図的に有効化できないため、由来のわからない設定ファイルから ON にされることがありません。
165
166
  - **非同期出力:** アプリケーションスレッドが直接ファイル出力を待たないよう、キューを介した logging を選べます。
@@ -173,6 +174,8 @@ D-SafeLogger は、active file を後から動かす代わりに、書き込み
173
174
 
174
175
  このモードでは、親プロセス側の Writer がファイル出力先を所有します。worker は Writer に attach し、IPC 経由でログレコードを送ります。これによりファイル所有が一箇所に集約され、accepted / delivered / rejected / dropped / unexplained-lost といった配送状態のカウンターが公開されます。
175
176
 
177
+ Writer の終了処理では上限つきの待機を行います。timeout 内で drain と join を試み、drain が完了しない場合は warning を出し、host process が無期限に hang し続けることを避けます。
178
+
176
179
  具体的なコード、`multiprocessing` の context ルール、Pool initializer、`ProcessPoolExecutor` 連携、Windows での spawn の注意、カスタムログレベル、attach / detach のライフサイクル、環境変数のチューニング、終了処理は [`examples/12_multiprocess_logging.md`](examples/12_multiprocess_logging.md) を参照してください。
177
180
 
178
181
  `dsafelogger.mp` の公開 API: `ConfigureLogger`, `AttachCurrentProcess`, `DetachCurrentProcess`, `GetLogger`, `GetWorkerInitializer`, `ReopenLogFiles`。
@@ -229,11 +232,13 @@ INI ファイル、dict 設定、モジュール別ルーティング、優先
229
232
 
230
233
  D-SafeLogger は、採用済みの単一プロセス async ベンチマークでは競争力があります。マルチプロセスでは、単純な throughput ではなく、親プロセス側 Writer によるファイル出力と配送状態の分類が主な価値です。
231
234
 
235
+ ベンチマークには、sink-unavailable、burst backpressure、worker crash、mixed worker behavior、shutdown behavior などの multiprocess resilience profile も含まれます。これらは throughput claim ではなく、attempted record を delivered / known-rejected / known-dropped / unexplained-lost として説明できるかを確認するものです。
236
+
232
237
  採用 run、計測条件、主張できる範囲は [BENCHMARK.md](BENCHMARK.md) を、公開済みの summary は [`benchmarks/summary/`](benchmarks/summary/) を参照してください。
233
238
 
234
239
  ## テスト / 品質
235
240
 
236
- リリースゲートでは、Windows / macOS / Linux と Python 3.11-3.14 の組み合わせで dev 依存を含む full test suite を実行します。公開前チェックでは、生成済み API docs、公開設計書、ベンチマークサマリー、パッケージ build も検証します。
241
+ リリースゲートでは、Windows / macOS / Linux と Python 3.11-3.14 の組み合わせで dev 依存を含む full test suite を実行します。CI では Ubuntu free-threaded CPython `3.13t` / `3.14t` の互換性ジョブも `PYTHON_GIL=0` で実行します。公開前チェックでは、生成済み API docs、公開設計書、ベンチマークサマリー、パッケージ build も検証します。
237
242
 
238
243
  詳しくは [TESTING.md](TESTING.md) を参照してください。
239
244
 
@@ -242,7 +247,7 @@ D-SafeLogger は、採用済みの単一プロセス async ベンチマークで
242
247
  - Python: 3.11 以上。
243
248
  - OS: Windows, macOS, Linux。
244
249
  - 実行時依存: なし。
245
- - 型情報: `py.typed` を同梱。
250
+ - 型情報: `py.typed` を同梱。CI で `mypy` / `pyright`、typing smoke test、`pyright --verifytypes` による public type completeness 100% gate を検証。詳細は [TESTING.md](TESTING.md)。
246
251
  - API docs: [`docs/api/`](docs/api/)。
247
252
  - Design docs: [`docs/design/`](docs/design/)。
248
253
  - 配布パッケージ名は `d-safelogger` (ハイフン)、import 名は `dsafelogger` (区切りなし) です。
@@ -29,8 +29,8 @@ uv run pytest tests -v
29
29
  Current v23j local validation on Python 3.14.3 / Windows:
30
30
 
31
31
  ```text
32
- 651 passed, 3 skipped
33
- 654 collected
32
+ 658 passed, 3 skipped
33
+ 661 collected
34
34
  ```
35
35
 
36
36
  The collected test count is the baseline. The number of skipped tests is platform-dependent because fork E2E tests are POSIX-only and Windows spawn E2E tests are Windows-only.
@@ -38,9 +38,9 @@ The collected test count is the baseline. The number of skipped tests is platfor
38
38
  Latest coverage validation generated `coverage.xml` on Python 3.14.3 / Windows:
39
39
 
40
40
  ```text
41
- TOTAL coverage: 86%
42
- XML line-rate: 88.49%
43
- XML branch-rate: 80.53%
41
+ TOTAL coverage: 87%
42
+ XML line-rate: 88.97%
43
+ XML branch-rate: 81.46%
44
44
  ```
45
45
 
46
46
  `coverage.xml`, `.coverage`, and `htmlcov/` are local/CI artifacts and are ignored by `.gitignore`; keep coverage numbers in documentation, not the generated files themselves.
@@ -112,6 +112,11 @@ uv run pytest tests -x -v
112
112
  | Third-party coexistence | `tests/test_opentelemetry.py`, `tests/test_structlog.py` |
113
113
  | Branch coverage edge cases | `tests/test_coverage_boost.py` |
114
114
 
115
+ Diagnostic masking coverage must include both component-level checks and
116
+ configuration-to-output integration checks. In particular, `sens_kws` and
117
+ `sens_kws_replace` are validated through `ConfigureLogger(...)` into sync text,
118
+ sync structured, async snapshot, and multiprocess Writer formatter paths.
119
+
115
120
  ## Multiprocess Test Policy
116
121
 
117
122
  `dsafelogger.mp` is a formal feature, so multiprocess tests are part of the standard quality gate.
@@ -124,6 +129,60 @@ Important expectations:
124
129
  - Tests must not rely on `multiprocessing.Queue.empty()` for correctness. Use timeout-based `get()` or fake/recording queues instead.
125
130
  - CloseMarker drain, control-plane ACKs, backpressure, reject counters, partial delivery, and bounded shutdown warning paths are covered by MP tests.
126
131
 
132
+ ## Type Validation
133
+
134
+ `D-SafeLogger` ships with `py.typed` (PEP 561), so source typing and public type completeness are part of the standard quality gate. CI runs `mypy`, `pyright`, a typing smoke test, and a 100% `pyright --verifytypes` gate on every push.
135
+
136
+ ### Tooling
137
+
138
+ - `mypy>=2.1` — strict-ish config (`disallow_untyped_defs = true`, `warn_unused_ignores = true`, `warn_return_any = true`).
139
+ - `pyright>=1.1.409` — `typeCheckingMode = "basic"` with `include = ["src"]`.
140
+
141
+ ### Required commands (PR pre-flight)
142
+
143
+ ```bash
144
+ uv sync --group dev
145
+ uv run pyright --version # record first
146
+ uv run mypy src # → 0 errors
147
+ uv run pyright src # → 0 errors
148
+ uv run pyright tests/typing_smoke # → 0 errors
149
+ ```
150
+
151
+ Local green (`0 errors` from both tools) is the precondition for pushing. CI runs the same commands and treats any error as a hard fail.
152
+
153
+ Package-level type completeness is checked from the built wheel, not the editable source tree:
154
+
155
+ ```bash
156
+ uv build
157
+ uv run python scripts/install_built_wheel.py
158
+ uv run --no-sync python scripts/check_type_completeness.py --min-score 100
159
+ uv sync --reinstall
160
+ ```
161
+
162
+ Use `uv run --no-sync` for the completeness check so the wheel install is not replaced by the editable project before `pyright --verifytypes` runs.
163
+
164
+ ### Latest local validation (2026-05-21 / Python 3.14.3 / Windows)
165
+
166
+ | Tool | Version | Result |
167
+ |---|---|---|
168
+ | `mypy` | 2.1.0 | `Success: no issues found in 27 source files` |
169
+ | `pyright` | 1.1.409 | `0 errors, 0 warnings, 0 informations` |
170
+ | `pyright --verifytypes dsafelogger --ignoreexternal` | 1.1.409 | `Type completeness score: 100%` (10 public symbols, 23 referenced internal symbols — all known type) |
171
+
172
+ ### Package name vs. type checker target
173
+
174
+ D-SafeLogger uses three name forms — be careful when invoking type tools:
175
+
176
+ - PyPI metadata: `D-SafeLogger`
177
+ - Python import / `verifytypes` target: `dsafelogger`
178
+ - Wheel filename: `d_safelogger-*.whl`
179
+
180
+ For `pyright --verifytypes`, always pass `dsafelogger` (the import name).
181
+
182
+ ### Private module surface policy
183
+
184
+ Names starting with a leading underscore (`_constants.MASK_STRING`, `_constants._resolved_sensitive_keywords`, `_pipeline.ResolvedConfig`, `_async.DSafeQueueHandler`, etc.) are **private** even though `py.typed` exposes them to user type checkers. Library consumers MUST NOT depend on private symbols; they may change without notice in PATCH or MINOR releases. Only names re-exported from `dsafelogger` / `dsafelogger.mp` `__init__.py` are public.
185
+
127
186
  ## Free-Threaded Python
128
187
 
129
188
  GitHub Actions runs Ubuntu free-threaded CPython `3.13t` and `3.14t` jobs with `PYTHON_GIL=0`.
@@ -161,13 +220,21 @@ See [`.github/workflows/ci.yml`](.github/workflows/ci.yml).
161
220
  The CI workflow also runs publication checks on Ubuntu/Python 3.13:
162
221
 
163
222
  ```bash
223
+ uv run pyright --version
224
+ uv run mypy src
225
+ uv run pyright src
226
+ uv run pyright tests/typing_smoke
164
227
  uv run python scripts/generate_api_docs.py --check
165
228
  uv run python scripts/check_design_docs_sync.py
166
229
  uv run python benchmarks/update_summary.py --check
167
230
  uv build
231
+ uv run python scripts/check_distribution_contents.py
232
+ uv run python scripts/install_built_wheel.py
233
+ uv run --no-sync python scripts/check_type_completeness.py --min-score 100
234
+ uv sync --reinstall --group dev
168
235
  ```
169
236
 
170
- The publish workflow repeats these checks, verifies the git tag matches the package version, runs the full test suite, and only then publishes.
237
+ The publish workflow repeats release document, benchmark, build, distribution-content, metadata, and full-suite checks, verifies the git tag matches the package version, and only then publishes.
171
238
 
172
239
  ## Documentation Checks
173
240
 
@@ -33,5 +33,6 @@ Public methods:
33
33
 
34
34
  | Name | Type | Value |
35
35
  |---|---|---|
36
+ | `MASK_STRING` | `str` | `'*** MASKED ***'` |
36
37
  | `QUEUE_DRAIN_TIMEOUT_SEC` | `float` | `10.0` |
37
38
  | `WORKER_JOIN_TIMEOUT_SEC` | `float` | `5.0` |
@@ -12,7 +12,7 @@ Enable ANSI escape sequences on Windows 10+.
12
12
 
13
13
  ## Classes
14
14
 
15
- ### `ColorStreamHandler(stream=None, color_enabled: 'bool' = True, color_overrides: 'dict[str, str] | None' = None) -> 'None'`
15
+ ### `ColorStreamHandler(stream: 'IO[str] | None' = None, color_enabled: 'bool' = True, color_overrides: 'dict[str, str] | None' = None) -> 'None'`
16
16
 
17
17
  StreamHandler with ANSI color codes for log levels.
18
18
 
@@ -43,7 +43,7 @@ in high-throughput multi-threaded scenarios.
43
43
 
44
44
  ## Classes
45
45
 
46
- ### `DSafeFormatter(fmt: 'str | None' = None, datefmt: 'str | None' = None, style: 'str' = '%') -> 'None'`
46
+ ### `DSafeFormatter(fmt: 'str | None' = None, datefmt: 'str | None' = None, style: "Literal['%', '{', '$']" = '%') -> 'None'`
47
47
 
48
48
  Standard D-SafeLogger formatter with level abbreviation and context suffix.
49
49
 
@@ -24,3 +24,15 @@ Public methods:
24
24
  - `emit(self, record: 'logging.LogRecord') -> 'None'`
25
25
  - `flush(self) -> 'None'`
26
26
  - `reopen(self) -> 'None'`
27
+
28
+ ### `ReopenableHandler(*args, **kwargs)`
29
+
30
+ Protocol for logging handlers that support external rotation reopen.
31
+
32
+ `isinstance(h, ReopenableHandler)` narrows `logging.Handler` references
33
+ to those that implement `reopen()`, replacing `hasattr(h, 'reopen')`
34
+ for static type checking.
35
+
36
+ Public methods:
37
+
38
+ - `reopen(self) -> 'None'`
@@ -39,7 +39,7 @@ Restart pump threads that were lost due to a post-fork in the parent process.
39
39
 
40
40
  ### `_same_process_identity(state: 'MPProcessState') -> 'bool'`
41
41
 
42
- ### `_validate_attach_ack(ack: 'dict[str, Any]', *, expected_protocol_version: 'int', expected_registry_hash: 'str') -> 'None'`
42
+ ### `_validate_attach_ack(ack: 'ControlAck', *, expected_protocol_version: 'int', expected_registry_hash: 'str') -> 'None'`
43
43
 
44
44
  ### `_validate_bootstrap_context(ctx: 'BootstrapContext') -> 'None'`
45
45
 
@@ -41,6 +41,12 @@ Public methods:
41
41
 
42
42
  - `build(self, config: 'ResolvedConfig') -> 'Pipeline'`
43
43
 
44
- ### `ResolvedConfig(pg_name: 'str', log_dir: 'Path', file_fmt: 'str | FormatterConfigDict | logging.Formatter', console_fmt: 'str | FormatterConfigDict | logging.Formatter', routing_mode: 'str', routing_kwargs: 'dict', backup_count: 'int', archive_mode: 'bool', enable_hash: 'bool', manifest_path: 'Path | None', encoding: 'str', diagnose: 'bool', max_level: 'str', console: 'bool', is_async: 'bool', queue_size: 'int', log_level: 'str', color_stream: 'bool', module_configs: 'dict[str, dict]', color_overrides: 'dict[str, str]') -> None`
44
+ ### `ResolvedConfig(pg_name: 'str', log_dir: 'Path', file_fmt: 'str | FormatterConfigDict | logging.Formatter', console_fmt: 'str | FormatterConfigDict | logging.Formatter', routing_mode: 'str', routing_kwargs: 'dict', backup_count: 'int', archive_mode: 'bool', enable_hash: 'bool', manifest_path: 'Path | None', encoding: 'str', diagnose: 'bool', max_level: 'str', console: 'bool', is_async: 'bool', queue_size: 'int', log_level: 'str', color_stream: 'bool', module_configs: 'dict[str, dict]', color_overrides: 'dict[str, str]', sensitive_keywords: 'frozenset[str]' = frozenset({'access_key', 'api_key', 'apikey', 'auth', 'cookie', 'credential', 'passwd', 'password', 'private_key', 'secret', 'session_id', 'token'})) -> None`
45
45
 
46
46
  Resolved configuration holding 3-layer merged parameters.
47
+
48
+ ## Constants
49
+
50
+ | Name | Type | Value |
51
+ |---|---|---|
52
+ | `BUILTIN_SENSITIVE_KEYWORDS` | `frozenset` | `frozenset({'access_key', 'api_key', 'apikey', 'auth', 'cookie', 'credential',...` |