Skip to content

feat(metrics): collect the DOCKER_HOST environment variable path #8007

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: develop
Choose a base branch
from
5 changes: 5 additions & 0 deletions samcli/cli/global_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ class GlobalConfig(metaclass=Singleton):
# Env var for injecting dir in integration tests
_DIR_INJECTION_ENV_VAR: str = "__SAM_CLI_APP_DIR"

# Env var used by docker client to specify which socket to use
DOCKER_HOST_ENV_VAR: str = "DOCKER_HOST"

# Static singleton instance

_access_lock: threading.RLock
Expand All @@ -71,6 +74,7 @@ class GlobalConfig(metaclass=Singleton):
_config_data: Optional[Dict[str, Any]]
# config_keys that should be flushed to file
_persistent_fields: List[str]
docker_host: str

def __init__(self):
"""__init__ should only be called once due to Singleton metaclass"""
Expand All @@ -79,6 +83,7 @@ def __init__(self):
self._config_filename = None
self._config_data = None
self._persistent_fields = list()
self.docker_host = os.environ.get(GlobalConfig.DOCKER_HOST_ENV_VAR, "")

@property
def config_dir(self) -> Path:
Expand Down
19 changes: 18 additions & 1 deletion samcli/lib/telemetry/metric.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import uuid
from dataclasses import dataclass
from functools import reduce, wraps
from pathlib import Path
from pathlib import Path, PurePath
from timeit import default_timer
from typing import Any, Dict, Optional

Expand Down Expand Up @@ -436,6 +436,7 @@ def _add_common_metric_attributes(self):
self._data["installationId"] = self._gc.installation_id
self._data["sessionId"] = self._session_id
self._data["executionEnvironment"] = self._get_execution_environment()
self._data["dockerHost"] = self._get_docker_host()
self._data["ci"] = bool(self._cicd_detector.platform())
self._data["pyversion"] = platform.python_version()
self._data["samcliVersion"] = samcli_version
Expand Down Expand Up @@ -476,6 +477,22 @@ def _get_execution_environment(self) -> str:
return cicd_platform.name
return "CLI"

def _get_docker_host(self) -> str:
"""
Returns the last part of a DOCKER_HOST string.
If the DOCKER_HOST is not set, returns an empty string.

Examples:
- unix:///var/run/docker.sock -> docker.sock
- tcp://localhost:1234 -> localhost:1234
- /var/run/docker.sock -> docker.sock
"""

try:
return PurePath(self._gc.docker_host).name
except TypeError:
return ""


class MetricDataNotList(Exception):
pass
1 change: 1 addition & 0 deletions tests/integration/telemetry/integ_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def setUp(self):
self.config_dir = tempfile.mkdtemp()
self._gc = GlobalConfig()
self._gc.config_dir = Path(self.config_dir)
self._gc.docker_host = ""

def tearDown(self):
self.config_dir and shutil.rmtree(self.config_dir)
Expand Down
4 changes: 4 additions & 0 deletions tests/integration/telemetry/test_experimental_metric.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def test_must_send_experimental_metrics_if_experimental_command(self):
"debugFlagProvided": ANY,
"region": ANY,
"commandName": ANY,
"dockerHost": ANY,
"metricSpecificAttributes": {
"experimentalAll": False,
"experimentalEsbuild": False,
Expand Down Expand Up @@ -115,6 +116,7 @@ def test_must_send_experimental_metrics_if_experimental_option(self):
"debugFlagProvided": ANY,
"region": ANY,
"commandName": ANY,
"dockerHost": ANY,
"metricSpecificAttributes": {
"experimentalAll": True,
"experimentalEsbuild": True,
Expand Down Expand Up @@ -182,6 +184,7 @@ def test_must_send_cdk_project_type_metrics(self):
"debugFlagProvided": ANY,
"region": ANY,
"commandName": ANY,
"dockerHost": ANY,
"metricSpecificAttributes": {
"projectType": "CDK",
"gitOrigin": ANY,
Expand Down Expand Up @@ -232,6 +235,7 @@ def test_must_send_not_experimental_metrics_if_not_experimental(self):
"executionEnvironment": ANY,
"ci": ANY,
"pyversion": ANY,
"dockerHost": ANY,
"samcliVersion": SAM_CLI_VERSION,
"awsProfileProvided": ANY,
"debugFlagProvided": ANY,
Expand Down
1 change: 1 addition & 0 deletions tests/integration/telemetry/test_installed_metric.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def test_send_installed_metric_on_first_run(self):
{
"installed": {
"installationId": self.get_global_config().installation_id,
"dockerHost": ANY,
"samcliVersion": SAM_CLI_VERSION,
"osPlatform": platform.system(),
"executionEnvironment": ANY,
Expand Down
1 change: 1 addition & 0 deletions tests/unit/lib/telemetry/test_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ def test_events_get_sent(self, telemetry_mock):
"pyversion": ANY,
"samcliVersion": ANY,
"commandName": ANY,
"dockerHost": ANY,
"metricSpecificAttributes": {
"events": [
{
Expand Down
15 changes: 14 additions & 1 deletion tests/unit/lib/telemetry/test_metric.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def test_must_send_installed_metric_with_attributes(self, TelemetryClassMock):
telemetry_mock = TelemetryClassMock.return_value = Mock()

self.gc_mock.return_value.telemetry_enabled = False
self.gc_mock.return_value.docker_host = ""
send_installed_metric()
args, _ = telemetry_mock.emit.call_args_list[0]
metric = args[0]
Expand Down Expand Up @@ -73,6 +74,7 @@ def setUp(self):

# Enable telemetry so we can actually run the tests
self.gc_instance_mock.telemetry_enabled = True
self.gc_instance_mock.docker_host = ""

def tearDown(self):
self.telemetry_class_patcher.stop()
Expand Down Expand Up @@ -310,6 +312,7 @@ def setUp(self):

# Enable telemetry so we can actually run the tests
self.gc_instance_mock.telemetry_enabled = True
self.gc_instance_mock.docker_host = ""

def tearDown(self):
self.telemetry_class_patcher.stop()
Expand Down Expand Up @@ -524,6 +527,7 @@ def test_must_add_common_attributes(
):
request_id = uuid_mock.uuid4.return_value = "fake requestId"
installation_id = gc_mock.return_value.installation_id = "fake installation id"
docker_host = gc_mock.return_value.docker_host = "fake docker host"
session_id = context_mock.get_current_context.return_value.session_id = "fake installation id"
python_version = platform_mock.python_version.return_value = "8.8.0"
cicd_platform_mock.return_value = cicd_platform
Expand All @@ -540,10 +544,19 @@ def test_must_add_common_attributes(
assert metric.get_data()["userAgent"] == user_agent
assert metric.get_data()["pyversion"] == python_version
assert metric.get_data()["samcliVersion"] == samcli.__version__
assert metric.get_data()["dockerHost"] == docker_host


def _ignore_common_attributes(data):
common_attrs = ["requestId", "installationId", "sessionId", "executionEnvironment", "pyversion", "samcliVersion"]
common_attrs = [
"requestId",
"installationId",
"sessionId",
"executionEnvironment",
"pyversion",
"samcliVersion",
"dockerHost",
]
for a in common_attrs:
if a not in data:
data[a] = ANY
Expand Down
Loading