nginx-lens 0.4.0__tar.gz → 0.5.0__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 (67) hide show
  1. {nginx_lens-0.4.0/nginx_lens.egg-info → nginx_lens-0.5.0}/PKG-INFO +1 -1
  2. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/commands/cli.py +6 -0
  3. nginx_lens-0.5.0/commands/completion.py +174 -0
  4. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/commands/health.py +41 -6
  5. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/commands/logs.py +10 -2
  6. nginx_lens-0.5.0/commands/metrics.py +495 -0
  7. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/commands/resolve.py +32 -2
  8. nginx_lens-0.5.0/commands/validate.py +451 -0
  9. nginx_lens-0.5.0/config/__init__.py +4 -0
  10. nginx_lens-0.5.0/config/config_loader.py +200 -0
  11. {nginx_lens-0.4.0 → nginx_lens-0.5.0/nginx_lens.egg-info}/PKG-INFO +1 -1
  12. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/nginx_lens.egg-info/SOURCES.txt +9 -1
  13. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/nginx_lens.egg-info/top_level.txt +2 -0
  14. nginx_lens-0.5.0/setup.py +54 -0
  15. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/upstream_checker/checker.py +47 -7
  16. nginx_lens-0.5.0/upstream_checker/dns_cache.py +216 -0
  17. nginx_lens-0.5.0/utils/__init__.py +4 -0
  18. nginx_lens-0.5.0/utils/progress.py +120 -0
  19. nginx_lens-0.4.0/setup.py +0 -30
  20. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/LICENSE +0 -0
  21. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/README.md +0 -0
  22. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/analyzer/__init__.py +0 -0
  23. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/analyzer/base.py +0 -0
  24. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/analyzer/conflicts.py +0 -0
  25. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/analyzer/dead_locations.py +0 -0
  26. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/analyzer/diff.py +0 -0
  27. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/analyzer/duplicates.py +0 -0
  28. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/analyzer/empty_blocks.py +0 -0
  29. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/analyzer/include.py +0 -0
  30. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/analyzer/rewrite.py +0 -0
  31. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/analyzer/route.py +0 -0
  32. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/analyzer/unused.py +0 -0
  33. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/analyzer/warnings.py +0 -0
  34. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/commands/__init__.py +0 -0
  35. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/commands/analyze.py +0 -0
  36. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/commands/diff.py +0 -0
  37. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/commands/graph.py +0 -0
  38. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/commands/include.py +0 -0
  39. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/commands/route.py +0 -0
  40. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/commands/syntax.py +0 -0
  41. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/commands/tree.py +0 -0
  42. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/exporter/__init__.py +0 -0
  43. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/exporter/csv.py +0 -0
  44. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/exporter/graph.py +0 -0
  45. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/exporter/html.py +0 -0
  46. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/exporter/json_yaml.py +0 -0
  47. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/exporter/markdown.py +0 -0
  48. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/nginx_lens.egg-info/dependency_links.txt +0 -0
  49. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/nginx_lens.egg-info/entry_points.txt +0 -0
  50. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/nginx_lens.egg-info/requires.txt +0 -0
  51. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/parser/__init__.py +0 -0
  52. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/parser/nginx_parser.py +0 -0
  53. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/pyproject.toml +0 -0
  54. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/setup.cfg +0 -0
  55. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/tests/test_conflicts.py +0 -0
  56. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/tests/test_diff.py +0 -0
  57. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/tests/test_duplicates.py +0 -0
  58. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/tests/test_empty_blocks.py +0 -0
  59. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/tests/test_graph.py +0 -0
  60. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/tests/test_health.py +0 -0
  61. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/tests/test_integration.py +0 -0
  62. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/tests/test_logs.py +0 -0
  63. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/tests/test_parser.py +0 -0
  64. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/tests/test_performance.py +0 -0
  65. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/tests/test_resolve.py +0 -0
  66. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/tests/test_route.py +0 -0
  67. {nginx_lens-0.4.0 → nginx_lens-0.5.0}/upstream_checker/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nginx-lens
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: CLI-инструмент для анализа, визуализации и диагностики конфигураций Nginx
5
5
  Author: Daniil Astrouski
6
6
  Author-email: shelovesuastra@gmail.com
@@ -10,6 +10,9 @@ from commands.graph import graph
10
10
  from commands.logs import logs
11
11
  from commands.syntax import syntax
12
12
  from commands.resolve import resolve
13
+ from commands.validate import validate
14
+ from commands.metrics import metrics
15
+ from commands.completion import app as completion_app
13
16
 
14
17
  app = typer.Typer(help="nginx-lens — анализ и диагностика конфигураций Nginx")
15
18
  console = Console()
@@ -24,6 +27,9 @@ app.command()(graph)
24
27
  app.command()(logs)
25
28
  app.command()(syntax)
26
29
  app.command()(resolve)
30
+ app.command()(validate)
31
+ app.command()(metrics)
32
+ app.add_typer(completion_app, name="completion", help="Генерация скриптов автодополнения")
27
33
 
28
34
  if __name__ == "__main__":
29
35
  app()
@@ -0,0 +1,174 @@
1
+ """
2
+ Команда для генерации скриптов автодополнения.
3
+ """
4
+ import sys
5
+ import typer
6
+ from rich.console import Console
7
+ from rich.panel import Panel
8
+ from rich import box
9
+
10
+ app = typer.Typer()
11
+ console = Console()
12
+
13
+
14
+ def _generate_completion_script(shell: str) -> str:
15
+ """
16
+ Генерирует базовый completion скрипт для указанного shell.
17
+
18
+ Args:
19
+ shell: Тип shell (bash, zsh, fish, powershell)
20
+
21
+ Returns:
22
+ Строка с completion скриптом
23
+ """
24
+ commands = [
25
+ "health", "analyze", "tree", "diff", "route", "include",
26
+ "graph", "logs", "syntax", "resolve", "validate", "metrics"
27
+ ]
28
+
29
+ if shell == "bash":
30
+ script = f"""# Bash completion for nginx-lens
31
+ _nginx_lens_completion() {{
32
+ local cur="${{COMP_WORDS[COMP_CWORD]}}"
33
+ local commands="{' '.join(commands)}"
34
+
35
+ if [[ ${{COMP_CWORD}} -eq 1 ]]; then
36
+ COMPREPLY=($(compgen -W "$commands" -- "$cur"))
37
+ else
38
+ COMPREPLY=($(compgen -f -- "$cur"))
39
+ fi
40
+ }}
41
+
42
+ complete -F _nginx_lens_completion nginx-lens
43
+ """
44
+ elif shell == "zsh":
45
+ script = f"""# Zsh completion for nginx-lens
46
+ #compdef nginx-lens
47
+
48
+ _nginx_lens() {{
49
+ local -a commands
50
+ commands=(
51
+ {' '.join(f'"{cmd}":{cmd}' for cmd in commands)}
52
+ )
53
+
54
+ _describe 'command' commands
55
+ }}
56
+
57
+ _nginx_lens "$@"
58
+ """
59
+ elif shell == "fish":
60
+ script = f"""# Fish completion for nginx-lens
61
+ complete -c nginx-lens -f -a "{' '.join(commands)}"
62
+ """
63
+ elif shell == "powershell":
64
+ script = f"""# PowerShell completion for nginx-lens
65
+ Register-ArgumentCompleter -Native -CommandName nginx-lens -ScriptBlock {{
66
+ param($commandName, $wordToComplete, $cursorPosition)
67
+
68
+ $commands = @({', '.join(f'"{cmd}"' for cmd in commands)})
69
+
70
+ $commands | Where-Object {{ $_ -like "$wordToComplete*" }} | ForEach-Object {{
71
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
72
+ }}
73
+ }}
74
+ """
75
+ else:
76
+ script = f"# Completion script for {shell}\n# Use: typer commands.cli app {shell}\n"
77
+
78
+ return script
79
+
80
+
81
+ @app.command()
82
+ def install(
83
+ shell: str = typer.Argument(..., help="Тип shell: bash, zsh, fish, powershell"),
84
+ output: str = typer.Option(None, "--output", "-o", help="Путь для сохранения скрипта (по умолчанию выводится в stdout)"),
85
+ ):
86
+ """
87
+ Генерирует скрипт автодополнения для указанного shell.
88
+
89
+ После генерации нужно добавить его в конфигурацию shell:
90
+
91
+ Bash:
92
+ nginx-lens completion install bash >> ~/.bashrc
93
+
94
+ Zsh:
95
+ nginx-lens completion install zsh >> ~/.zshrc
96
+
97
+ Fish:
98
+ nginx-lens completion install fish > ~/.config/fish/completions/nginx-lens.fish
99
+
100
+ PowerShell:
101
+ nginx-lens completion install powershell > nginx-lens-completion.ps1
102
+ # Затем выполните: . .\nginx-lens-completion.ps1
103
+ """
104
+ import subprocess
105
+ import sys
106
+
107
+ # Пробуем использовать typer CLI для генерации completion
108
+ completion_script = None
109
+ try:
110
+ result = subprocess.run(
111
+ [sys.executable, "-m", "typer", "commands.cli", "app", shell],
112
+ capture_output=True,
113
+ text=True,
114
+ check=False,
115
+ timeout=10
116
+ )
117
+
118
+ if result.returncode == 0 and result.stdout and len(result.stdout.strip()) > 0:
119
+ completion_script = result.stdout
120
+ except (subprocess.TimeoutExpired, FileNotFoundError, Exception):
121
+ pass
122
+
123
+ # Если typer CLI не сработал, используем базовый скрипт
124
+ if not completion_script:
125
+ completion_script = _generate_completion_script(shell)
126
+
127
+ if shell not in ["bash", "zsh", "fish", "powershell"]:
128
+ console.print(f"[red]Неподдерживаемый shell: {shell}[/red]")
129
+ console.print("[yellow]Поддерживаемые shell: bash, zsh, fish, powershell[/yellow]")
130
+ raise typer.Exit(1)
131
+
132
+ if output:
133
+ try:
134
+ with open(output, 'w') as f:
135
+ f.write(completion_script)
136
+ console.print(f"[green]✓ Скрипт автодополнения сохранен в {output}[/green]")
137
+ console.print(f"[yellow]Не забудьте добавить его в конфигурацию {shell}[/yellow]")
138
+ except Exception as e:
139
+ console.print(f"[red]Ошибка при сохранении файла: {e}[/red]")
140
+ raise typer.Exit(1)
141
+ else:
142
+ typer.echo(completion_script)
143
+ # Выводим инструкцию в stderr, чтобы не мешать скрипту
144
+ console.print("\n[yellow]Добавьте этот скрипт в конфигурацию вашего shell[/yellow]", file=sys.stderr)
145
+
146
+
147
+ @app.command()
148
+ def show_instructions():
149
+ """
150
+ Показывает инструкции по установке автодополнения для всех поддерживаемых shell.
151
+ """
152
+ console.print(Panel("[bold blue]Инструкции по установке автодополнения[/bold blue]", box=box.ROUNDED))
153
+
154
+ console.print("\n[bold]Bash:[/bold]")
155
+ console.print(" nginx-lens completion install bash >> ~/.bashrc")
156
+ console.print(" source ~/.bashrc")
157
+
158
+ console.print("\n[bold]Zsh:[/bold]")
159
+ console.print(" nginx-lens completion install zsh >> ~/.zshrc")
160
+ console.print(" source ~/.zshrc")
161
+
162
+ console.print("\n[bold]Fish:[/bold]")
163
+ console.print(" mkdir -p ~/.config/fish/completions")
164
+ console.print(" nginx-lens completion install fish > ~/.config/fish/completions/nginx-lens.fish")
165
+
166
+ console.print("\n[bold]PowerShell:[/bold]")
167
+ console.print(" nginx-lens completion install powershell > nginx-lens-completion.ps1")
168
+ console.print(" . .\\nginx-lens-completion.ps1")
169
+ console.print(" # Или добавьте в профиль PowerShell: $PROFILE")
170
+
171
+
172
+ if __name__ == "__main__":
173
+ app()
174
+
@@ -1,36 +1,64 @@
1
1
  import sys
2
+ from typing import Optional
2
3
  import typer
3
4
  from rich.console import Console
4
5
  from rich.table import Table
5
6
  from upstream_checker.checker import check_upstreams, resolve_upstreams
7
+ from upstream_checker.dns_cache import disable_cache, enable_cache
6
8
  from parser.nginx_parser import parse_nginx_config
7
9
  from exporter.json_yaml import format_health_results, print_export
10
+ from config.config_loader import get_config
11
+ from utils.progress import ProgressManager
8
12
 
9
13
  app = typer.Typer()
10
14
  console = Console()
11
15
 
12
16
  def health(
13
17
  config_path: str = typer.Argument(..., help="Путь к nginx.conf"),
14
- timeout: float = typer.Option(2.0, help="Таймаут проверки (сек)"),
15
- retries: int = typer.Option(1, help="Количество попыток"),
16
- mode: str = typer.Option("tcp", help="Режим проверки: tcp или http", case_sensitive=False),
18
+ timeout: Optional[float] = typer.Option(None, help="Таймаут проверки (сек)"),
19
+ retries: Optional[int] = typer.Option(None, help="Количество попыток"),
20
+ mode: Optional[str] = typer.Option(None, help="Режим проверки: tcp или http", case_sensitive=False),
17
21
  resolve: bool = typer.Option(False, "--resolve", "-r", help="Показать резолвленные IP-адреса"),
18
- max_workers: int = typer.Option(10, "--max-workers", "-w", help="Максимальное количество потоков для параллельной обработки"),
22
+ max_workers: Optional[int] = typer.Option(None, "--max-workers", "-w", help="Максимальное количество потоков для параллельной обработки"),
19
23
  json: bool = typer.Option(False, "--json", help="Экспортировать результаты в JSON"),
20
24
  yaml: bool = typer.Option(False, "--yaml", help="Экспортировать результаты в YAML"),
25
+ no_cache: bool = typer.Option(False, "--no-cache", help="Отключить кэширование DNS резолвинга"),
26
+ cache_ttl: Optional[int] = typer.Option(None, "--cache-ttl", help="Время жизни кэша в секундах"),
21
27
  ):
22
28
  """
23
29
  Проверяет доступность upstream-серверов, определённых в nginx.conf. Выводит таблицу.
24
30
  Использует параллельную обработку для ускорения проверки множества upstream серверов.
31
+ Поддерживает кэширование результатов DNS резолвинга для ускорения повторных запусков.
25
32
 
26
33
  Пример:
27
34
  nginx-lens health /etc/nginx/nginx.conf
28
35
  nginx-lens health /etc/nginx/nginx.conf --timeout 5 --retries 3 --mode http
29
36
  nginx-lens health /etc/nginx/nginx.conf --resolve
30
37
  nginx-lens health /etc/nginx/nginx.conf --max-workers 20
38
+ nginx-lens health /etc/nginx/nginx.conf --resolve --no-cache
39
+ nginx-lens health /etc/nginx/nginx.conf --resolve --cache-ttl 600
31
40
  """
32
41
  exit_code = 0
33
42
 
43
+ # Загружаем конфигурацию
44
+ config = get_config()
45
+ defaults = config.get_defaults()
46
+ cache_config = config.get_cache_config()
47
+
48
+ # Применяем значения из конфига, если не указаны через CLI
49
+ timeout = timeout if timeout is not None else defaults.get("timeout", 2.0)
50
+ retries = retries if retries is not None else defaults.get("retries", 1)
51
+ mode = mode if mode is not None else defaults.get("mode", "tcp")
52
+ max_workers = max_workers if max_workers is not None else defaults.get("max_workers", 10)
53
+ cache_ttl = cache_ttl if cache_ttl is not None else cache_config.get("ttl", defaults.get("dns_cache_ttl", 300))
54
+
55
+ # Управление кэшем
56
+ use_cache = not no_cache and cache_config.get("enabled", True)
57
+ if no_cache:
58
+ disable_cache()
59
+ else:
60
+ enable_cache()
61
+
34
62
  try:
35
63
  tree = parse_nginx_config(config_path)
36
64
  except FileNotFoundError:
@@ -41,12 +69,19 @@ def health(
41
69
  sys.exit(1)
42
70
 
43
71
  upstreams = tree.get_upstreams()
44
- results = check_upstreams(upstreams, timeout=timeout, retries=retries, mode=mode.lower(), max_workers=max_workers)
72
+
73
+ # Подсчитываем общее количество серверов для прогресс-бара
74
+ total_servers = sum(len(servers) for servers in upstreams.values())
75
+
76
+ # Проверка upstream с прогресс-баром
77
+ with ProgressManager(description="Проверка upstream серверов", show_progress=total_servers > 5) as pm:
78
+ results = check_upstreams(upstreams, timeout=timeout, retries=retries, mode=mode.lower(), max_workers=max_workers, progress_manager=pm)
45
79
 
46
80
  # Если нужно показать резолвленные IP-адреса
47
81
  resolved_info = {}
48
82
  if resolve:
49
- resolved_info = resolve_upstreams(upstreams, max_workers=max_workers)
83
+ with ProgressManager(description="Резолвинг DNS", show_progress=total_servers > 5) as pm:
84
+ resolved_info = resolve_upstreams(upstreams, max_workers=max_workers, use_cache=use_cache, cache_ttl=cache_ttl, progress_manager=pm)
50
85
 
51
86
  # Экспорт в JSON/YAML
52
87
  if json or yaml:
@@ -1,4 +1,5 @@
1
1
  import sys
2
+ from typing import Optional, List, Dict, Any
2
3
  import typer
3
4
  from rich.console import Console
4
5
  from rich.table import Table
@@ -6,9 +7,9 @@ import re
6
7
  import gzip
7
8
  from datetime import datetime, timedelta
8
9
  from collections import Counter, defaultdict
9
- from typing import Optional, List, Dict, Any
10
10
  from exporter.json_yaml import format_logs_results, print_export
11
11
  from exporter.csv import export_logs_to_csv
12
+ from config.config_loader import get_config
12
13
 
13
14
  app = typer.Typer(help="Анализ access.log/error.log: топ-статусы, пути, IP, User-Agent, ошибки.")
14
15
  console = Console()
@@ -23,7 +24,7 @@ log_line_re = re.compile(
23
24
 
24
25
  def logs(
25
26
  log_path: str = typer.Argument(..., help="Путь к access.log или error.log"),
26
- top: int = typer.Option(10, help="Сколько топ-значений выводить"),
27
+ top: Optional[int] = typer.Option(None, help="Сколько топ-значений выводить"),
27
28
  json: bool = typer.Option(False, "--json", help="Экспортировать результаты в JSON"),
28
29
  yaml: bool = typer.Option(False, "--yaml", help="Экспортировать результаты в YAML"),
29
30
  csv: bool = typer.Option(False, "--csv", help="Экспортировать результаты в CSV"),
@@ -49,6 +50,13 @@ def logs(
49
50
  nginx-lens logs /var/log/nginx/access.log --since "2024-01-01" --status 404,500
50
51
  nginx-lens logs /var/log/nginx/access.log.gz --detect-anomalies --json
51
52
  """
53
+ # Загружаем конфигурацию
54
+ config = get_config()
55
+ defaults = config.get_defaults()
56
+
57
+ # Применяем значения из конфига, если не указаны через CLI
58
+ top = top if top is not None else defaults.get("top", 10)
59
+
52
60
  # Парсинг фильтров
53
61
  status_filter = None
54
62
  if status: