playground-ls-cli 4.14.1.dev8__py3-none-any.whl

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 (112) hide show
  1. localstack_cli/__init__.py +0 -0
  2. localstack_cli/cli/__init__.py +10 -0
  3. localstack_cli/cli/console.py +11 -0
  4. localstack_cli/cli/core_plugin.py +12 -0
  5. localstack_cli/cli/exceptions.py +19 -0
  6. localstack_cli/cli/localstack.py +951 -0
  7. localstack_cli/cli/lpm.py +138 -0
  8. localstack_cli/cli/main.py +22 -0
  9. localstack_cli/cli/plugin.py +39 -0
  10. localstack_cli/cli/plugins.py +134 -0
  11. localstack_cli/cli/profiles.py +65 -0
  12. localstack_cli/config.py +1689 -0
  13. localstack_cli/constants.py +165 -0
  14. localstack_cli/logging/__init__.py +0 -0
  15. localstack_cli/logging/format.py +194 -0
  16. localstack_cli/logging/setup.py +142 -0
  17. localstack_cli/packages/__init__.py +25 -0
  18. localstack_cli/packages/api.py +418 -0
  19. localstack_cli/packages/core.py +416 -0
  20. localstack_cli/pro/__init__.py +0 -0
  21. localstack_cli/pro/core/__init__.py +0 -0
  22. localstack_cli/pro/core/bootstrap/__init__.py +1 -0
  23. localstack_cli/pro/core/bootstrap/auth.py +213 -0
  24. localstack_cli/pro/core/bootstrap/dns_utils.py +55 -0
  25. localstack_cli/pro/core/bootstrap/entitlements.py +117 -0
  26. localstack_cli/pro/core/bootstrap/extensions/__init__.py +3 -0
  27. localstack_cli/pro/core/bootstrap/extensions/__main__.py +106 -0
  28. localstack_cli/pro/core/bootstrap/extensions/autoinstall.py +63 -0
  29. localstack_cli/pro/core/bootstrap/extensions/bootstrap.py +97 -0
  30. localstack_cli/pro/core/bootstrap/extensions/repository.py +374 -0
  31. localstack_cli/pro/core/bootstrap/licensingv2.py +1259 -0
  32. localstack_cli/pro/core/bootstrap/pods/__init__.py +0 -0
  33. localstack_cli/pro/core/bootstrap/pods/api_types.py +17 -0
  34. localstack_cli/pro/core/bootstrap/pods/constants.py +26 -0
  35. localstack_cli/pro/core/bootstrap/pods/remotes/__init__.py +0 -0
  36. localstack_cli/pro/core/bootstrap/pods/remotes/api.py +75 -0
  37. localstack_cli/pro/core/bootstrap/pods/remotes/configs.py +69 -0
  38. localstack_cli/pro/core/bootstrap/pods/remotes/params.py +86 -0
  39. localstack_cli/pro/core/bootstrap/pods_client.py +834 -0
  40. localstack_cli/pro/core/cli/__init__.py +0 -0
  41. localstack_cli/pro/core/cli/auth.py +226 -0
  42. localstack_cli/pro/core/cli/aws.py +16 -0
  43. localstack_cli/pro/core/cli/cli.py +99 -0
  44. localstack_cli/pro/core/cli/click_utils.py +21 -0
  45. localstack_cli/pro/core/cli/cloud_pods.py +465 -0
  46. localstack_cli/pro/core/cli/diff_view.py +41 -0
  47. localstack_cli/pro/core/cli/ephemeral.py +199 -0
  48. localstack_cli/pro/core/cli/extensions.py +492 -0
  49. localstack_cli/pro/core/cli/iam.py +180 -0
  50. localstack_cli/pro/core/cli/license.py +90 -0
  51. localstack_cli/pro/core/cli/localstack.py +118 -0
  52. localstack_cli/pro/core/cli/replicator.py +378 -0
  53. localstack_cli/pro/core/cli/state.py +183 -0
  54. localstack_cli/pro/core/cli/tree_view.py +235 -0
  55. localstack_cli/pro/core/config.py +556 -0
  56. localstack_cli/pro/core/constants.py +54 -0
  57. localstack_cli/pro/core/plugins.py +169 -0
  58. localstack_cli/runtime/__init__.py +6 -0
  59. localstack_cli/runtime/exceptions.py +7 -0
  60. localstack_cli/runtime/hooks.py +73 -0
  61. localstack_cli/testing/__init__.py +1 -0
  62. localstack_cli/testing/config.py +4 -0
  63. localstack_cli/utils/__init__.py +0 -0
  64. localstack_cli/utils/analytics/__init__.py +12 -0
  65. localstack_cli/utils/analytics/cli.py +67 -0
  66. localstack_cli/utils/analytics/client.py +111 -0
  67. localstack_cli/utils/analytics/events.py +30 -0
  68. localstack_cli/utils/analytics/logger.py +48 -0
  69. localstack_cli/utils/analytics/metadata.py +250 -0
  70. localstack_cli/utils/analytics/publisher.py +160 -0
  71. localstack_cli/utils/analytics/service_request_aggregator.py +133 -0
  72. localstack_cli/utils/archives.py +271 -0
  73. localstack_cli/utils/batching.py +258 -0
  74. localstack_cli/utils/bootstrap.py +1418 -0
  75. localstack_cli/utils/checksum.py +313 -0
  76. localstack_cli/utils/collections.py +554 -0
  77. localstack_cli/utils/common.py +229 -0
  78. localstack_cli/utils/container_networking.py +142 -0
  79. localstack_cli/utils/container_utils/__init__.py +0 -0
  80. localstack_cli/utils/container_utils/container_client.py +1585 -0
  81. localstack_cli/utils/container_utils/docker_cmd_client.py +987 -0
  82. localstack_cli/utils/container_utils/docker_sdk_client.py +1018 -0
  83. localstack_cli/utils/crypto.py +294 -0
  84. localstack_cli/utils/docker_utils.py +272 -0
  85. localstack_cli/utils/files.py +327 -0
  86. localstack_cli/utils/functions.py +92 -0
  87. localstack_cli/utils/http.py +326 -0
  88. localstack_cli/utils/json.py +219 -0
  89. localstack_cli/utils/net.py +516 -0
  90. localstack_cli/utils/no_exit_argument_parser.py +19 -0
  91. localstack_cli/utils/numbers.py +49 -0
  92. localstack_cli/utils/objects.py +235 -0
  93. localstack_cli/utils/patch.py +260 -0
  94. localstack_cli/utils/platform.py +77 -0
  95. localstack_cli/utils/run.py +514 -0
  96. localstack_cli/utils/server/__init__.py +0 -0
  97. localstack_cli/utils/server/tcp_proxy.py +108 -0
  98. localstack_cli/utils/serving.py +187 -0
  99. localstack_cli/utils/ssl.py +71 -0
  100. localstack_cli/utils/strings.py +245 -0
  101. localstack_cli/utils/sync.py +267 -0
  102. localstack_cli/utils/threads.py +163 -0
  103. localstack_cli/utils/time.py +81 -0
  104. localstack_cli/utils/urls.py +21 -0
  105. localstack_cli/utils/venv.py +100 -0
  106. localstack_cli/utils/xml.py +41 -0
  107. localstack_cli/version.py +34 -0
  108. playground_ls_cli-4.14.1.dev8.dist-info/METADATA +95 -0
  109. playground_ls_cli-4.14.1.dev8.dist-info/RECORD +112 -0
  110. playground_ls_cli-4.14.1.dev8.dist-info/WHEEL +5 -0
  111. playground_ls_cli-4.14.1.dev8.dist-info/entry_points.txt +17 -0
  112. playground_ls_cli-4.14.1.dev8.dist-info/top_level.txt +1 -0
@@ -0,0 +1,165 @@
1
+ import os
2
+
3
+ from localstack_cli.version import __version__
4
+
5
+ VERSION = __version__
6
+
7
+ # HTTP headers used to forward proxy request URLs
8
+ HEADER_LOCALSTACK_EDGE_URL = "x-localstack-edge"
9
+ HEADER_LOCALSTACK_REQUEST_URL = "x-localstack-request-url"
10
+ # HTTP header optionally added to LocalStack responses
11
+ HEADER_LOCALSTACK_IDENTIFIER = "x-localstack"
12
+ # xXx custom localstack authorization header only used in ext
13
+ HEADER_LOCALSTACK_AUTHORIZATION = "x-localstack-authorization"
14
+ HEADER_LOCALSTACK_TARGET = "x-localstack-target"
15
+ HEADER_AMZN_ERROR_TYPE = "X-Amzn-Errortype"
16
+
17
+ # backend service ports, for services that are behind a proxy (counting down from 4566)
18
+ DEFAULT_PORT_EDGE = 4566
19
+
20
+ # host name for localhost
21
+ LOCALHOST = "localhost"
22
+ LOCALHOST_IP = "127.0.0.1"
23
+ LOCALHOST_HOSTNAME = "localhost.localstack.cloud"
24
+
25
+ # User-agent string used in outgoing HTTP requests made by LocalStack
26
+ USER_AGENT_STRING = f"localstack/{VERSION}"
27
+
28
+ # version of the Maven dependency with Java utility code
29
+ LOCALSTACK_MAVEN_VERSION = "0.2.21"
30
+ MAVEN_REPO_URL = "https://repo1.maven.org/maven2"
31
+
32
+ # URL of localstack's artifacts repository on GitHub
33
+ ARTIFACTS_REPO = "https://github.com/localstack/localstack-artifacts"
34
+
35
+ # Artifacts endpoint
36
+ ASSETS_ENDPOINT = "https://assets.localstack.cloud"
37
+
38
+ # Hugging Face endpoint for localstack
39
+ HUGGING_FACE_ENDPOINT = "https://huggingface.co/localstack"
40
+
41
+ # host to bind to when starting the services
42
+ BIND_HOST = "0.0.0.0"
43
+
44
+ # root code folder
45
+ MODULE_MAIN_PATH = os.path.dirname(os.path.realpath(__file__))
46
+ # TODO rename to "ROOT_FOLDER"!
47
+ LOCALSTACK_ROOT_FOLDER = os.path.realpath(os.path.join(MODULE_MAIN_PATH, ".."))
48
+
49
+ # virtualenv folder
50
+ LOCALSTACK_VENV_FOLDER: str = os.environ.get("VIRTUAL_ENV")
51
+ if not LOCALSTACK_VENV_FOLDER:
52
+ # fallback to the previous logic
53
+ LOCALSTACK_VENV_FOLDER = os.path.join(LOCALSTACK_ROOT_FOLDER, ".venv")
54
+ if not os.path.isdir(LOCALSTACK_VENV_FOLDER):
55
+ # assuming this package lives here: <python>/lib/pythonX.X/site-packages/localstack/
56
+ LOCALSTACK_VENV_FOLDER = os.path.realpath(
57
+ os.path.join(LOCALSTACK_ROOT_FOLDER, "..", "..", "..")
58
+ )
59
+
60
+ # default volume directory containing shared data
61
+ DEFAULT_VOLUME_DIR = "/var/lib/localstack"
62
+
63
+ # API Gateway path to indicate a user request sent to the gateway
64
+ PATH_USER_REQUEST = "_user_request_"
65
+
66
+ # name of LocalStack Docker image
67
+ DOCKER_IMAGE_NAME_PRO = "localstack/localstack-pro"
68
+
69
+ # backdoor API path used to retrieve or update config variables
70
+ CONFIG_UPDATE_PATH = "/?_config_"
71
+
72
+ # API path for localstack internal resources
73
+ INTERNAL_RESOURCE_PATH = "/_localstack"
74
+
75
+ # environment variable name to tag local test runs
76
+ ENV_INTERNAL_TEST_RUN = "LOCALSTACK_INTERNAL_TEST_RUN"
77
+
78
+ # environment variable name to tag collect metrics during a test run
79
+ ENV_INTERNAL_TEST_COLLECT_METRIC = "LOCALSTACK_INTERNAL_TEST_COLLECT_METRIC"
80
+
81
+ # environment variable name to indicate that metrics should be stored within the container
82
+ ENV_INTERNAL_TEST_STORE_METRICS_IN_LOCALSTACK = "LOCALSTACK_INTERNAL_TEST_METRICS_IN_LOCALSTACK"
83
+ ENV_INTERNAL_TEST_STORE_METRICS_PATH = "LOCALSTACK_INTERNAL_TEST_STORE_METRICS_PATH"
84
+
85
+ # environment variable that flags whether pro was activated. do not use it for security purposes!
86
+ ENV_PRO_ACTIVATED = "PRO_ACTIVATED"
87
+
88
+ # content types / encodings
89
+ HEADER_CONTENT_TYPE = "Content-Type"
90
+ TEXT_XML = "text/xml"
91
+ APPLICATION_AMZ_JSON_1_0 = "application/x-amz-json-1.0"
92
+ APPLICATION_AMZ_JSON_1_1 = "application/x-amz-json-1.1"
93
+ APPLICATION_AMZ_CBOR_1_1 = "application/x-amz-cbor-1.1"
94
+ APPLICATION_CBOR = "application/cbor"
95
+ APPLICATION_JSON = "application/json"
96
+ APPLICATION_XML = "application/xml"
97
+ APPLICATION_OCTET_STREAM = "application/octet-stream"
98
+ APPLICATION_X_WWW_FORM_URLENCODED = "application/x-www-form-urlencoded"
99
+ HEADER_ACCEPT_ENCODING = "Accept-Encoding"
100
+
101
+ # strings to indicate truthy/falsy values
102
+ TRUE_STRINGS = ("1", "true", "True")
103
+ FALSE_STRINGS = ("0", "false", "False")
104
+ # strings with valid log levels for LS_LOG
105
+ LOG_LEVELS = ("trace-internal", "trace", "debug", "info", "warn", "error", "warning")
106
+
107
+ # API endpoint for analytics events
108
+ API_ENDPOINT = os.environ.get("API_ENDPOINT") or "https://api.localstack.cloud/v1"
109
+ # new analytics API endpoint
110
+ ANALYTICS_API = os.environ.get("ANALYTICS_API") or "https://analytics.localstack.cloud/v1"
111
+
112
+ # environment variable to indicate this process should run the localstack infrastructure
113
+ LOCALSTACK_INFRA_PROCESS = "LOCALSTACK_INFRA_PROCESS"
114
+
115
+ # AWS region us-east-1
116
+ AWS_REGION_US_EAST_1 = "us-east-1"
117
+
118
+ # AWS region eu-west-1
119
+ AWS_REGION_EU_WEST_1 = "eu-west-1"
120
+
121
+ # environment variable to override max pool connections
122
+ try:
123
+ MAX_POOL_CONNECTIONS = int(os.environ["MAX_POOL_CONNECTIONS"])
124
+ except Exception:
125
+ MAX_POOL_CONNECTIONS = 150
126
+
127
+ # Fallback Account ID if not available in the client request
128
+ DEFAULT_AWS_ACCOUNT_ID = "000000000000"
129
+
130
+ # Credentials used for internal calls
131
+ INTERNAL_AWS_ACCESS_KEY_ID = "__internal_call__"
132
+ INTERNAL_AWS_SECRET_ACCESS_KEY = "__internal_call__"
133
+
134
+ # trace log levels (excluding/including internal API calls), configurable via $LS_LOG
135
+ LS_LOG_TRACE = "trace"
136
+ LS_LOG_TRACE_INTERNAL = "trace-internal"
137
+ TRACE_LOG_LEVELS = [LS_LOG_TRACE, LS_LOG_TRACE_INTERNAL]
138
+
139
+ # list of official docker images
140
+ OFFICIAL_IMAGES = [
141
+ "localstack/localstack",
142
+ "localstack/localstack-pro",
143
+ "localstack/snowflake"
144
+ ]
145
+
146
+ # port for debug py
147
+ DEFAULT_DEVELOP_PORT = 5678
148
+
149
+ # Default bucket name of the s3 bucket used for local lambda development
150
+ # This name should be accepted by all IaC tools, so should respect s3 bucket naming conventions
151
+ DEFAULT_BUCKET_MARKER_LOCAL = "hot-reload"
152
+ LEGACY_DEFAULT_BUCKET_MARKER_LOCAL = "__local__"
153
+
154
+ # output string that indicates that the stack is ready
155
+ READY_MARKER_OUTPUT = "Ready."
156
+
157
+ # Regex for `Credential` field in the Authorization header in AWS signature version v4
158
+ # The format is as follows:
159
+ # Credential=<access-key-id>/<date>/<region-name>/<service-name>/aws4_request
160
+ # eg.
161
+ # Credential=AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request
162
+ AUTH_CREDENTIAL_REGEX = r"Credential=(?P<access_key_id>[a-zA-Z0-9-_.]{1,})/(?P<date>\d{8})/(?P<region_name>[a-z0-9-]{1,})/(?P<service_name>[a-z0-9]{1,})/"
163
+
164
+ # Custom resource tag to override the generated resource ID.
165
+ TAG_KEY_CUSTOM_ID = "_custom_id_"
File without changes
@@ -0,0 +1,194 @@
1
+ """Tools for formatting localstack logs."""
2
+
3
+ import logging
4
+ import re
5
+ from functools import lru_cache
6
+ from typing import Any
7
+
8
+ from localstack_cli.utils.numbers import format_bytes
9
+ from localstack_cli.utils.strings import to_bytes
10
+
11
+ MAX_THREAD_NAME_LEN = 12
12
+ MAX_NAME_LEN = 26
13
+
14
+ LOG_FORMAT = f"%(asctime)s.%(msecs)03d %(ls_level)5s --- [%(ls_thread){MAX_THREAD_NAME_LEN}s] %(ls_name)-{MAX_NAME_LEN}s : %(message)s"
15
+ LOG_DATE_FORMAT = "%Y-%m-%dT%H:%M:%S"
16
+ LOG_INPUT_FORMAT = "%(input_type)s(%(input)s, headers=%(request_headers)s)"
17
+ LOG_OUTPUT_FORMAT = "%(output_type)s(%(output)s, headers=%(response_headers)s)"
18
+ LOG_CONTEXT_FORMAT = "%(account_id)s/%(region)s"
19
+
20
+ CUSTOM_LEVEL_NAMES = {
21
+ 50: "FATAL",
22
+ 40: "ERROR",
23
+ 30: "WARN",
24
+ 20: "INFO",
25
+ 10: "DEBUG",
26
+ }
27
+
28
+
29
+ class DefaultFormatter(logging.Formatter):
30
+ """
31
+ A formatter that uses ``LOG_FORMAT`` and ``LOG_DATE_FORMAT``.
32
+ """
33
+
34
+ def __init__(self, fmt=LOG_FORMAT, datefmt=LOG_DATE_FORMAT):
35
+ super().__init__(fmt=fmt, datefmt=datefmt)
36
+
37
+
38
+ class AddFormattedAttributes(logging.Filter):
39
+ """
40
+ Filter that adds three attributes to a log record:
41
+
42
+ - ls_level: the abbreviated loglevel that's max 5 characters long
43
+ - ls_name: the abbreviated name of the logger (e.g., `l.bootstrap.install`), trimmed to ``MAX_NAME_LEN``
44
+ - ls_thread: the abbreviated thread name (prefix trimmed, .e.g, ``omeThread-108``)
45
+ """
46
+
47
+ max_name_len: int
48
+ max_thread_len: int
49
+
50
+ def __init__(self, max_name_len: int = None, max_thread_len: int = None):
51
+ super().__init__()
52
+ self.max_name_len = max_name_len if max_name_len else MAX_NAME_LEN
53
+ self.max_thread_len = max_thread_len if max_thread_len else MAX_THREAD_NAME_LEN
54
+
55
+ def filter(self, record):
56
+ record.ls_level = CUSTOM_LEVEL_NAMES.get(record.levelno, record.levelname)
57
+ record.ls_name = self._get_compressed_logger_name(record.name)
58
+ record.ls_thread = record.threadName[-self.max_thread_len :]
59
+ return True
60
+
61
+ @lru_cache(maxsize=256)
62
+ def _get_compressed_logger_name(self, name):
63
+ return compress_logger_name(name, self.max_name_len)
64
+
65
+
66
+ class MaskSensitiveInputFilter(logging.Filter):
67
+ """
68
+ Filter that hides sensitive from a binary json string in a record input.
69
+ It will find the mathing keys and replace their values with "******"
70
+
71
+ For example, if initialized with `sensitive_keys=["my_key"]`, the input
72
+ b'{"my_key": "sensitive_value"}' would become b'{"my_key": "******"}'.
73
+ """
74
+
75
+ patterns: list[tuple[re.Pattern[bytes], bytes]]
76
+
77
+ def __init__(self, sensitive_keys: list[str]):
78
+ super().__init__()
79
+
80
+ self.patterns = [
81
+ (re.compile(to_bytes(rf'"{key}":\s*"[^"]+"')), to_bytes(f'"{key}": "******"'))
82
+ for key in sensitive_keys
83
+ ]
84
+
85
+ def filter(self, record):
86
+ if record.input and isinstance(record.input, bytes):
87
+ record.input = self.mask_sensitive_msg(record.input)
88
+ return True
89
+
90
+ def mask_sensitive_msg(self, message: bytes) -> bytes:
91
+ for pattern, replacement in self.patterns:
92
+ message = re.sub(pattern, replacement, message)
93
+ return message
94
+
95
+
96
+ def compress_logger_name(name: str, length: int) -> str:
97
+ """
98
+ Creates a short version of a logger name. For example ``my.very.long.logger.name`` with length=17 turns into
99
+ ``m.v.l.logger.name``.
100
+
101
+ :param name: the logger name
102
+ :param length: the max length of the logger name
103
+ :return: the compressed name
104
+ """
105
+ if len(name) <= length:
106
+ return name
107
+
108
+ parts = name.split(".")
109
+ parts.reverse()
110
+
111
+ new_parts = []
112
+
113
+ # we start by assuming that all parts are collapsed
114
+ # x.x.x requires 5 = 2n - 1 characters
115
+ cur_length = (len(parts) * 2) - 1
116
+
117
+ for i in range(len(parts)):
118
+ # try to expand the current part and calculate the resulting length
119
+ part = parts[i]
120
+ next_len = cur_length + (len(part) - 1)
121
+
122
+ if next_len > length:
123
+ # if the resulting length would exceed the limit, add only the first letter of the parts of all remaining
124
+ # parts
125
+ new_parts += [p[0] for p in parts[i:]]
126
+
127
+ # but if this is the first item, that means we would display nothing, so at least display as much of the
128
+ # max length as possible
129
+ if i == 0:
130
+ remaining = length - cur_length
131
+ if remaining > 0:
132
+ new_parts[0] = part[: (remaining + 1)]
133
+
134
+ break
135
+
136
+ # expanding the current part, i.e., instead of using just the one character, we add the entire part
137
+ new_parts.append(part)
138
+ cur_length = next_len
139
+
140
+ new_parts.reverse()
141
+ return ".".join(new_parts)
142
+
143
+
144
+ class TraceLoggingFormatter(logging.Formatter):
145
+ aws_trace_log_format = "; ".join([LOG_FORMAT, LOG_INPUT_FORMAT, LOG_OUTPUT_FORMAT])
146
+ bytes_length_display_threshold = 512
147
+
148
+ def __init__(self):
149
+ super().__init__(fmt=self.aws_trace_log_format, datefmt=LOG_DATE_FORMAT)
150
+
151
+ def _replace_large_payloads(self, input: Any) -> Any:
152
+ """
153
+ Replaces large payloads in the logs with placeholders to avoid cluttering the logs with huge bytes payloads.
154
+ :param input: Input/output extra passed when logging. If it is bytes, it will be replaced if larger than
155
+ bytes_length_display_threshold
156
+ :return: Input, unless it is bytes and longer than bytes_length_display_threshold, then `Bytes(length_of_input)`
157
+ """
158
+ if isinstance(input, bytes) and len(input) > self.bytes_length_display_threshold:
159
+ return f"Bytes({format_bytes(len(input))})"
160
+ return input
161
+
162
+ def format(self, record: logging.LogRecord) -> str:
163
+ record.input = self._replace_large_payloads(record.input)
164
+ record.output = self._replace_large_payloads(record.output)
165
+ return super().format(record=record)
166
+
167
+
168
+ class AwsTraceLoggingFormatter(TraceLoggingFormatter):
169
+ aws_trace_log_format = "; ".join(
170
+ [LOG_FORMAT, LOG_CONTEXT_FORMAT, LOG_INPUT_FORMAT, LOG_OUTPUT_FORMAT]
171
+ )
172
+
173
+ def __init__(self):
174
+ super().__init__()
175
+
176
+ def _copy_service_dict(self, service_dict: dict) -> dict:
177
+ if not isinstance(service_dict, dict):
178
+ return service_dict
179
+ result = {}
180
+ for key, value in service_dict.items():
181
+ if isinstance(value, dict):
182
+ result[key] = self._copy_service_dict(value)
183
+ elif isinstance(value, bytes) and len(value) > self.bytes_length_display_threshold:
184
+ result[key] = f"Bytes({format_bytes(len(value))})"
185
+ elif isinstance(value, list):
186
+ result[key] = [self._copy_service_dict(item) for item in value]
187
+ else:
188
+ result[key] = value
189
+ return result
190
+
191
+ def format(self, record: logging.LogRecord) -> str:
192
+ record.input = self._copy_service_dict(record.input)
193
+ record.output = self._copy_service_dict(record.output)
194
+ return super().format(record=record)
@@ -0,0 +1,142 @@
1
+ import logging
2
+ import sys
3
+ import warnings
4
+
5
+ from localstack_cli import config, constants
6
+
7
+ from ..utils.strings import key_value_pairs_to_dict
8
+ from .format import AddFormattedAttributes, DefaultFormatter
9
+
10
+ # The log levels for modules are evaluated incrementally for logging granularity,
11
+ # from highest (DEBUG) to lowest (TRACE_INTERNAL). Hence, each module below should have
12
+ # higher level which serves as the default.
13
+
14
+ default_log_levels = {
15
+ "asyncio": logging.INFO,
16
+ "boto3": logging.INFO,
17
+ "botocore": logging.ERROR,
18
+ "docker": logging.WARNING,
19
+ "elasticsearch": logging.ERROR,
20
+ "hpack": logging.ERROR,
21
+ "moto": logging.WARNING,
22
+ "requests": logging.WARNING,
23
+ "s3transfer": logging.INFO,
24
+ "urllib3": logging.WARNING,
25
+ "werkzeug": logging.WARNING,
26
+ "rolo": logging.WARNING,
27
+ "parse": logging.WARNING,
28
+ "localstack.aws.accounts": logging.INFO,
29
+ "localstack.aws.protocol.serializer": logging.INFO,
30
+ "localstack.aws.serving.wsgi": logging.WARNING,
31
+ "localstack.request": logging.INFO,
32
+ "localstack.request.internal": logging.WARNING,
33
+ "localstack.state.inspect": logging.INFO,
34
+ "localstack_persistence": logging.INFO,
35
+ }
36
+
37
+ trace_log_levels = {
38
+ "rolo": logging.DEBUG,
39
+ "localstack.aws.protocol.serializer": logging.DEBUG,
40
+ "localstack.aws.serving.wsgi": logging.DEBUG,
41
+ "localstack.request": logging.DEBUG,
42
+ "localstack.request.internal": logging.INFO,
43
+ "localstack.state.inspect": logging.DEBUG,
44
+ }
45
+
46
+ trace_internal_log_levels = {
47
+ "localstack.aws.accounts": logging.DEBUG,
48
+ "localstack.request.internal": logging.DEBUG,
49
+ }
50
+
51
+
52
+ def setup_logging_for_cli(log_level=logging.INFO):
53
+ logging.basicConfig(level=log_level)
54
+
55
+ # set log levels of loggers
56
+ logging.root.setLevel(log_level)
57
+ logging.getLogger("localstack").setLevel(log_level)
58
+ for logger, level in default_log_levels.items():
59
+ logging.getLogger(logger).setLevel(level)
60
+
61
+
62
+ def get_log_level_from_config():
63
+ # overriding the log level if LS_LOG has been set
64
+ if config.LS_LOG:
65
+ log_level = str(config.LS_LOG).upper()
66
+ if log_level.lower() in constants.TRACE_LOG_LEVELS:
67
+ log_level = "DEBUG"
68
+ log_level = logging._nameToLevel[log_level]
69
+ return log_level
70
+
71
+ return logging.DEBUG if config.DEBUG else logging.INFO
72
+
73
+
74
+ def setup_logging_from_config():
75
+ log_level = get_log_level_from_config()
76
+ setup_logging(log_level)
77
+
78
+ if config.is_trace_logging_enabled():
79
+ for name, level in trace_log_levels.items():
80
+ logging.getLogger(name).setLevel(level)
81
+ if config.LS_LOG == constants.LS_LOG_TRACE_INTERNAL:
82
+ for name, level in trace_internal_log_levels.items():
83
+ logging.getLogger(name).setLevel(level)
84
+
85
+ raw_logging_override = config.LOG_LEVEL_OVERRIDES
86
+ if raw_logging_override:
87
+ logging_overrides = key_value_pairs_to_dict(raw_logging_override)
88
+ for logger, level_name in logging_overrides.items():
89
+ level = getattr(logging, level_name, None)
90
+ if not level:
91
+ raise ValueError(
92
+ f"Failed to configure logging overrides ({raw_logging_override}): '{level_name}' is not a valid log level"
93
+ )
94
+ logging.getLogger(logger).setLevel(level)
95
+
96
+
97
+ def create_default_handler(log_level: int):
98
+ log_handler = logging.StreamHandler(stream=sys.stderr)
99
+ log_handler.setLevel(log_level)
100
+ log_handler.setFormatter(DefaultFormatter())
101
+ log_handler.addFilter(AddFormattedAttributes())
102
+ return log_handler
103
+
104
+
105
+ def setup_logging(log_level=logging.INFO) -> None:
106
+ """
107
+ Configures the python logging environment for LocalStack.
108
+
109
+ :param log_level: the optional log level.
110
+ """
111
+ # set create a default handler for the root logger (basically logging.basicConfig but explicit)
112
+ log_handler = create_default_handler(log_level)
113
+
114
+ # replace any existing handlers
115
+ logging.basicConfig(level=log_level, handlers=[log_handler])
116
+
117
+ # disable some logs and warnings
118
+ warnings.filterwarnings("ignore")
119
+ logging.captureWarnings(True)
120
+
121
+ # set log levels of loggers
122
+ logging.root.setLevel(log_level)
123
+ logging.getLogger("localstack").setLevel(log_level)
124
+ for logger, level in default_log_levels.items():
125
+ logging.getLogger(logger).setLevel(level)
126
+
127
+
128
+ def setup_hypercorn_logger(hypercorn_config) -> None:
129
+ """
130
+ Sets the hypercorn loggers, which are created in a peculiar way, to the localstack settings.
131
+
132
+ :param hypercorn_config: a hypercorn.Config object
133
+ """
134
+ logger = hypercorn_config.log.access_logger
135
+ if logger:
136
+ logger.handlers[0].addFilter(AddFormattedAttributes())
137
+ logger.handlers[0].setFormatter(DefaultFormatter())
138
+
139
+ logger = hypercorn_config.log.error_logger
140
+ if logger:
141
+ logger.handlers[0].addFilter(AddFormattedAttributes())
142
+ logger.handlers[0].setFormatter(DefaultFormatter())
@@ -0,0 +1,25 @@
1
+ from .api import (
2
+ InstallTarget,
3
+ NoSuchVersionException,
4
+ Package,
5
+ PackageException,
6
+ PackageInstaller,
7
+ PackagesPlugin,
8
+ package,
9
+ packages,
10
+ )
11
+ from .core import DownloadInstaller, GitHubReleaseInstaller, SystemNotSupportedException
12
+
13
+ __all__ = [
14
+ "Package",
15
+ "PackageInstaller",
16
+ "GitHubReleaseInstaller",
17
+ "DownloadInstaller",
18
+ "InstallTarget",
19
+ "PackageException",
20
+ "NoSuchVersionException",
21
+ "SystemNotSupportedException",
22
+ "PackagesPlugin",
23
+ "package",
24
+ "packages",
25
+ ]