Skip to content
This repository was archived by the owner on Mar 23, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions localstack-core/localstack/runtime/analytics.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging
import os
import platform

from localstack import config
from localstack.runtime import hooks
Expand Down Expand Up @@ -132,10 +133,21 @@ def get_image_variant(self) -> str:
def has_docker_socket(self) -> bool:
return os.path.exists("/run/docker.sock")

def uname(self) -> dict:
result = platform.uname()
return {
"uname_system": result.system,
"uname_release": result.release,
"uname_version": result.version,
"uname_machine": result.machine,
}

def to_dict(self):
return {
"variant": self.get_image_variant(),
"has_docker_socket": self.has_docker_socket(),
"container_runtime": config.CONTAINER_RUNTIME,
**self.uname(),
}


Expand Down
66 changes: 65 additions & 1 deletion localstack-core/localstack/utils/analytics/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def read_client_metadata() -> ClientMetadata:
session_id=get_session_id(),
machine_id=get_machine_id(),
api_key=get_api_key_or_auth_token() or "", # api key should not be None
system=get_system(),
system=get_system_information_summary(),
version=get_version_string(),
is_ci=os.getenv("CI") is not None,
is_docker=config.is_in_docker,
Expand Down Expand Up @@ -215,6 +215,7 @@ def get_api_key_or_auth_token() -> str | None:

@singleton_factory
def get_system() -> str:
# TODO: candidate for removal
try:
# try to get the system from the docker socket
from localstack.utils.docker_utils import DOCKER_CLIENT
Expand All @@ -231,6 +232,69 @@ def get_system() -> str:
return platform.system().lower()


@singleton_factory
def get_system_information_summary() -> str:
"""
Returns a string that contains three comma-separated values: The operating system, kernel version,
and architecture. We either use the docker socket to resolve the information, if that is not available
we fall back ``platform.uname()``. If we're in docker and we don't have the docker socket available,
we add ``(Container)`` to the operating system type to indicate that we don't have any additional
information.

Some examples:

If the Docker socket is available:
- Docker Desktop,5.15.90.1-microsoft-standard-WSL2,x86_64
- Linux Mint 21.1,5.19.0-32-generic,x86_64

If the Docker socket is not available, and we're on the host:
- Windows,10,AMD64
- Linux,5.19.0-32-generic,x86_64

If the Docker socket is not available, and we're in the container:
- Linux(Container),5.19.0-32-generic,x86_64

:return: A string representing the system's information
"""
try:
# try to get the system from the docker socket
from localstack.utils.docker_utils import DOCKER_CLIENT

system = DOCKER_CLIENT.get_system_info()

return ",".join(
[
system["OperatingSystem"],
system["KernelVersion"],
system["Architecture"],
]
)
except Exception:
if config.DEBUG_ANALYTICS:
LOG.exception(
"Unable to get system information from docker socket, falling back to platform.uname()"
)

uname = platform.uname()

if config.is_in_docker:
return ",".join(
[
f"{uname.system}(Container)",
uname.release,
uname.machine,
]
)

return ",".join(
[
uname.system,
uname.release,
uname.machine,
]
)


@hooks.prepare_host()
def prepare_host_machine_id():
# lazy-init machine ID into cache on the host, which can then be used in the container
Expand Down
Loading