devlogs 2.3.4__tar.gz → 2.3.5__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 (82) hide show
  1. {devlogs-2.3.4/src/devlogs.egg-info → devlogs-2.3.5}/PKG-INFO +1 -1
  2. {devlogs-2.3.4 → devlogs-2.3.5}/pyproject.toml +1 -1
  3. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/_version_static.py +1 -1
  4. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/cli.py +14 -0
  5. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/config.py +10 -2
  6. {devlogs-2.3.4 → devlogs-2.3.5/src/devlogs.egg-info}/PKG-INFO +1 -1
  7. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_cli.py +22 -0
  8. {devlogs-2.3.4 → devlogs-2.3.5}/LICENSE +0 -0
  9. {devlogs-2.3.4 → devlogs-2.3.5}/MANIFEST.in +0 -0
  10. {devlogs-2.3.4 → devlogs-2.3.5}/README.md +0 -0
  11. {devlogs-2.3.4 → devlogs-2.3.5}/setup.cfg +0 -0
  12. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/__init__.py +0 -0
  13. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/__main__.py +0 -0
  14. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/build_info.py +0 -0
  15. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/collector/__init__.py +0 -0
  16. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/collector/auth.py +0 -0
  17. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/collector/cli.py +0 -0
  18. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/collector/errors.py +0 -0
  19. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/collector/forwarder.py +0 -0
  20. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/collector/ingestor.py +0 -0
  21. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/collector/loki_plugin.py +0 -0
  22. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/collector/plugins.py +0 -0
  23. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/collector/schema.py +0 -0
  24. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/collector/server.py +0 -0
  25. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/context.py +0 -0
  26. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/demo.py +0 -0
  27. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/devlogs_client.py +0 -0
  28. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/formatting.py +0 -0
  29. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/handler.py +0 -0
  30. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/jenkins/__init__.py +0 -0
  31. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/jenkins/cli.py +0 -0
  32. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/jenkins/core.py +0 -0
  33. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/levels.py +0 -0
  34. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/loki/__init__.py +0 -0
  35. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/loki/queries.py +0 -0
  36. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/mcp/__init__.py +0 -0
  37. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/mcp/server.py +0 -0
  38. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/opensearch/__init__.py +0 -0
  39. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/opensearch/client.py +0 -0
  40. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/opensearch/indexing.py +0 -0
  41. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/opensearch/mappings.py +0 -0
  42. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/opensearch/queries.py +0 -0
  43. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/proxy/__init__.py +0 -0
  44. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/proxy/server.py +0 -0
  45. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/retention.py +0 -0
  46. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/scrub.py +0 -0
  47. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/time_utils.py +0 -0
  48. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/version.py +0 -0
  49. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/web/__init__.py +0 -0
  50. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/web/server.py +0 -0
  51. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/web/static/devlogs.css +0 -0
  52. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/web/static/devlogs.js +0 -0
  53. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/web/static/index.html +0 -0
  54. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs/wrapper.py +0 -0
  55. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs.egg-info/SOURCES.txt +0 -0
  56. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs.egg-info/dependency_links.txt +0 -0
  57. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs.egg-info/entry_points.txt +0 -0
  58. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs.egg-info/requires.txt +0 -0
  59. {devlogs-2.3.4 → devlogs-2.3.5}/src/devlogs.egg-info/top_level.txt +0 -0
  60. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_build_info.py +0 -0
  61. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_collector_auth.py +0 -0
  62. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_collector_config.py +0 -0
  63. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_collector_plugins.py +0 -0
  64. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_collector_schema.py +0 -0
  65. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_collector_server.py +0 -0
  66. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_config.py +0 -0
  67. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_context.py +0 -0
  68. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_devlogs_client.py +0 -0
  69. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_formatting.py +0 -0
  70. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_handler.py +0 -0
  71. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_indexing.py +0 -0
  72. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_levels.py +0 -0
  73. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_mappings.py +0 -0
  74. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_mcp_server.py +0 -0
  75. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_opensearch_client.py +0 -0
  76. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_opensearch_queries.py +0 -0
  77. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_proxy_server.py +0 -0
  78. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_retention.py +0 -0
  79. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_scrub.py +0 -0
  80. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_time_utils.py +0 -0
  81. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_url_parsing.py +0 -0
  82. {devlogs-2.3.4 → devlogs-2.3.5}/tests/test_web.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devlogs
3
- Version: 2.3.4
3
+ Version: 2.3.5
4
4
  Summary: Developer-focused logging library for Python with OpenSearch integration.
5
5
  Author-email: Dan Driscoll <dan@thedandriscoll.org>
6
6
  License: MIT License
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "devlogs"
7
- version = "2.3.4"
7
+ version = "2.3.5"
8
8
  description = "Developer-focused logging library for Python with OpenSearch integration."
9
9
  requires-python = ">=3.11"
10
10
  readme = "README.md"
@@ -1,2 +1,2 @@
1
1
  # AUTO-GENERATED at build time — do not edit or commit
2
- __version__ = "2.3.4"
2
+ __version__ = "2.3.5"
@@ -926,6 +926,13 @@ def tail(
926
926
  _apply_common_options(env, url)
927
927
 
928
928
  cfg = load_config()
929
+ if cfg.url_mode == "collector":
930
+ typer.echo(typer.style(
931
+ "Error: the provided URL is a collector (ingest) endpoint and cannot be used for querying.\n"
932
+ "For Loki backends, use lokis://TOKEN@host/path instead of https://TOKEN@host/path",
933
+ fg=typer.colors.RED
934
+ ), err=True)
935
+ raise typer.Exit(1)
929
936
  if cfg.is_loki:
930
937
  _tail_loki(cfg, application=application, operation_id=operation_id, area=area,
931
938
  component=component, level=level, since=since, limit=limit, follow=follow,
@@ -1115,6 +1122,13 @@ def search(
1115
1122
  _apply_common_options(env, url)
1116
1123
 
1117
1124
  cfg = load_config()
1125
+ if cfg.url_mode == "collector":
1126
+ typer.echo(typer.style(
1127
+ "Error: the provided URL is a collector (ingest) endpoint and cannot be used for querying.\n"
1128
+ "For Loki backends, use lokis://TOKEN@host/path instead of https://TOKEN@host/path",
1129
+ fg=typer.colors.RED
1130
+ ), err=True)
1131
+ raise typer.Exit(1)
1118
1132
  if cfg.is_loki:
1119
1133
  _search_loki(cfg, q=q, application=application, area=area,
1120
1134
  component=component, level=level, operation_id=operation_id,
@@ -414,8 +414,9 @@ class DevlogsConfig:
414
414
  # Treat unparseable DEVLOGS_URL as legacy OpenSearch
415
415
  opensearch_url_config = _parse_opensearch_url(devlogs_url)
416
416
 
417
- # Legacy: DEVLOGS_OPENSEARCH_URL overrides OpenSearch settings from DEVLOGS_URL
418
- if legacy_opensearch_url:
417
+ # Legacy: DEVLOGS_OPENSEARCH_URL overrides OpenSearch settings from DEVLOGS_URL,
418
+ # but NOT when the URL was explicitly set via --url flag.
419
+ if legacy_opensearch_url and not _url_set_explicitly:
419
420
  opensearch_url_config = _parse_opensearch_url(legacy_opensearch_url)
420
421
  # Parse application filter from opensearch:// URL (second path segment)
421
422
  if legacy_opensearch_url.startswith("opensearchs://") or legacy_opensearch_url.startswith("opensearch://"):
@@ -539,15 +540,22 @@ def set_dotenv_path(path: str):
539
540
  _dotenv_loaded = False # Reset to force reload with new path
540
541
 
541
542
 
543
+ _url_set_explicitly = False
544
+
542
545
  def set_url(url: str):
543
546
  """Set the URL, auto-detecting whether it's a collector or OpenSearch URL.
544
547
 
545
548
  Uses parse_url() to detect the URL type:
546
549
  - Collector URLs → sets DEVLOGS_URL
547
550
  - OpenSearch URLs → sets DEVLOGS_OPENSEARCH_URL
551
+
552
+ When called (i.e. via --url flag), marks the URL as explicitly set so that
553
+ dotenv values cannot silently override it.
548
554
  """
555
+ global _url_set_explicitly
549
556
  if not url:
550
557
  return
558
+ _url_set_explicitly = True
551
559
  try:
552
560
  parsed = parse_url(url)
553
561
  except URLParseError:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devlogs
3
- Version: 2.3.4
3
+ Version: 2.3.5
4
4
  Summary: Developer-focused logging library for Python with OpenSearch integration.
5
5
  Author-email: Dan Driscoll <dan@thedandriscoll.org>
6
6
  License: MIT License
@@ -919,3 +919,25 @@ class TestLokiCLI:
919
919
  result = runner.invoke(cli.app, ["--url", "lokis://token@host.example.io/query", "last-error"])
920
920
  assert result.exit_code == 1
921
921
  assert "--application is required" in result.output
922
+
923
+ def test_tail_rejects_collector_url(self, monkeypatch):
924
+ """Test that tail fails with a clear error for collector (https) URLs."""
925
+ monkeypatch.setattr(config, "_dotenv_loaded", True)
926
+ monkeypatch.delenv("DEVLOGS_OPENSEARCH_URL", raising=False)
927
+ monkeypatch.delenv("DEVLOGS_OPENSEARCH_HOST", raising=False)
928
+ runner = CliRunner()
929
+ result = runner.invoke(cli.app, ["--url", "https://token@host.example.io/ingest", "tail"])
930
+ assert result.exit_code == 1
931
+ assert "collector" in result.output
932
+ assert "lokis://" in result.output
933
+
934
+ def test_search_rejects_collector_url(self, monkeypatch):
935
+ """Test that search fails with a clear error for collector (https) URLs."""
936
+ monkeypatch.setattr(config, "_dotenv_loaded", True)
937
+ monkeypatch.delenv("DEVLOGS_OPENSEARCH_URL", raising=False)
938
+ monkeypatch.delenv("DEVLOGS_OPENSEARCH_HOST", raising=False)
939
+ runner = CliRunner()
940
+ result = runner.invoke(cli.app, ["--url", "https://token@host.example.io/ingest", "search"])
941
+ assert result.exit_code == 1
942
+ assert "collector" in result.output
943
+ assert "lokis://" in result.output
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes