Skip to content

Commit 20530fb

Browse files
committed
CM-34777 - Add correlation ID
1 parent baf376b commit 20530fb

File tree

5 files changed

+59
-23
lines changed

5 files changed

+59
-23
lines changed

cycode/cli/printers/printer_base.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import click
66

77
from cycode.cli.models import CliError, CliResult
8+
from cycode.cyclient.headers import get_correlation_id
89

910
if TYPE_CHECKING:
1011
from cycode.cli.models import LocalScanResult
@@ -46,3 +47,6 @@ def print_exception(self, e: Optional[BaseException] = None) -> None:
4647
message = f'Error: {traceback_message}'
4748

4849
click.secho(message, err=True, fg=self.RED_COLOR_NAME)
50+
51+
correlation_message = f'Correlation ID: {get_correlation_id()}'
52+
click.secho(correlation_message, err=True, fg=self.RED_COLOR_NAME)

cycode/cyclient/cycode_client_base.py

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,17 @@
1-
import platform
21
from typing import ClassVar, Dict, Optional
32

43
from requests import Response, exceptions, request
54

6-
from cycode import __version__
75
from cycode.cli.exceptions.custom_exceptions import HttpUnauthorizedError, NetworkError
8-
from cycode.cli.user_settings.configuration_manager import ConfigurationManager
96
from cycode.cyclient import config, logger
10-
11-
12-
def get_cli_user_agent() -> str:
13-
"""Return base User-Agent of CLI.
14-
15-
Example: CycodeCLI/0.2.3 (OS: Darwin; Arch: arm64; Python: 3.8.16; InstallID: *uuid4*)
16-
"""
17-
app_name = 'CycodeCLI'
18-
version = __version__
19-
20-
os = platform.system()
21-
arch = platform.machine()
22-
python_version = platform.python_version()
23-
24-
install_id = ConfigurationManager().get_or_create_installation_id()
25-
26-
return f'{app_name}/{version} (OS: {os}; Arch: {arch}; Python: {python_version}; InstallID: {install_id})'
7+
from cycode.cyclient.headers import get_cli_user_agent, get_correlation_id
278

289

2910
class CycodeClientBase:
30-
MANDATORY_HEADERS: ClassVar[Dict[str, str]] = {'User-Agent': get_cli_user_agent()}
11+
MANDATORY_HEADERS: ClassVar[Dict[str, str]] = {
12+
'User-Agent': get_cli_user_agent(),
13+
'X-Correlation-Id': get_correlation_id(),
14+
}
3115

3216
def __init__(self, api_url: str) -> None:
3317
self.timeout = config.timeout

cycode/cyclient/headers.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import platform
2+
from typing import Optional
3+
from uuid import uuid4
4+
5+
from cycode import __version__
6+
from cycode.cli.user_settings.configuration_manager import ConfigurationManager
7+
from cycode.cyclient import logger
8+
9+
10+
def get_cli_user_agent() -> str:
11+
"""Return base User-Agent of CLI.
12+
13+
Example: CycodeCLI/0.2.3 (OS: Darwin; Arch: arm64; Python: 3.8.16; InstallID: *uuid4*)
14+
"""
15+
app_name = 'CycodeCLI'
16+
version = __version__
17+
18+
os = platform.system()
19+
arch = platform.machine()
20+
python_version = platform.python_version()
21+
22+
install_id = ConfigurationManager().get_or_create_installation_id()
23+
24+
return f'{app_name}/{version} (OS: {os}; Arch: {arch}; Python: {python_version}; InstallID: {install_id})'
25+
26+
27+
class _CorrelationId:
28+
_id: Optional[str] = None
29+
30+
def get_correlation_id(self) -> str:
31+
"""Get correlation ID.
32+
33+
Notes:
34+
Used across all requests to correlate logs and metrics.
35+
It doesn't depend on client instances.
36+
Lifetime is the same as the process.
37+
"""
38+
if self._id is None:
39+
# example: 16fd2706-8baf-433b-82eb-8c7fada847da
40+
self._id = str(uuid4())
41+
logger.debug(f'Correlation ID: {self._id}')
42+
43+
return self._id
44+
45+
46+
get_correlation_id = _CorrelationId().get_correlation_id

tests/cli/exceptions/test_handle_scan_errors.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def test_handle_exception_verbose(monkeypatch: 'MonkeyPatch') -> None:
5959
ctx = click.Context(click.Command('path'), obj={'verbose': True, 'output': 'text'})
6060

6161
def mock_secho(msg: str, *_, **__) -> None:
62-
assert 'Error:' in msg
62+
assert 'Error:' in msg or 'Correlation ID:' in msg
6363

6464
monkeypatch.setattr(click, 'secho', mock_secho)
6565

tests/cyclient/test_client_base.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
from cycode.cyclient import config
2-
from cycode.cyclient.cycode_client_base import CycodeClientBase, get_cli_user_agent
2+
from cycode.cyclient.cycode_client_base import CycodeClientBase
3+
from cycode.cyclient.headers import get_cli_user_agent, get_correlation_id
34

45

56
def test_mandatory_headers() -> None:
67
expected_headers = {
78
'User-Agent': get_cli_user_agent(),
9+
'X-Correlation-Id': get_correlation_id(),
810
}
911

1012
client = CycodeClientBase(config.cycode_api_url)

0 commit comments

Comments
 (0)