Skip to content

Commit cd2db70

Browse files
authored
sdk logging file size & rotation (#3495)
* sdk logging file size & rotation
1 parent 1c4345b commit cd2db70

File tree

8 files changed

+106
-61
lines changed

8 files changed

+106
-61
lines changed

Diff for: .circleci/config.yml

+19-2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ parameters:
2727

2828

2929
references:
30+
environment: &environment
31+
environment:
32+
DEMISTO_SDK_LOG_FILE_SIZE: "1073741824" # 1GB
33+
3034
version_tag_regex: &version_tag_regex
3135
/^v\d+\.\d+\.\d+$/ # version regex vx.x.x (i.e. v1.2.3)
3236

@@ -75,6 +79,7 @@ references:
7579

7680
install_poetry: &install_poetry
7781
- run:
82+
<<: *environment
7883
name: Install Poetry
7984
command: |
8085
# in old images we need to remove existing poetry
@@ -120,6 +125,7 @@ jobs:
120125
type: string
121126
docker:
122127
- image: cimg/python:<< parameters.pythonversion >>-node
128+
<<: *environment
123129
steps:
124130
- checkout
125131
- <<: *install_poetry
@@ -135,7 +141,7 @@ jobs:
135141
command: |
136142
shopt -u globstar
137143
# The first sed expression is to remove test files from under the demisto_sdk/commands/init/templates
138-
# directory from the globbed list of files. Need to manually remove them since the pytest 'ignore'
144+
# directory from the globed list of files. Need to manually remove them since the pytest 'ignore'
139145
# argument in pytest.ini is itself ignored when explicitly passing tests to pytest. The second is to
140146
# remove the integration tests (integration tests as opposed to unit tests) from the list because those
141147
# tests shouldn't be parallelized.
@@ -184,6 +190,7 @@ jobs:
184190
type: string
185191
docker:
186192
- image: cimg/python:<< parameters.pythonversion >>-node
193+
<<: *environment
187194
steps:
188195
- checkout
189196
- <<: *install_neo4j
@@ -230,6 +237,7 @@ jobs:
230237
precommit-checks:
231238
docker:
232239
- image: << pipeline.parameters.global-docker-image >>
240+
<<: *environment
233241
steps:
234242
- checkout
235243
- <<: *install_poetry
@@ -262,6 +270,7 @@ jobs:
262270
checkout-content:
263271
docker:
264272
- image: << pipeline.parameters.global-docker-image >>
273+
<<: *environment
265274
steps:
266275
- checkout
267276
- run:
@@ -279,6 +288,7 @@ jobs:
279288
docker:
280289
- image: << pipeline.parameters.global-docker-image >>
281290
resource_class: large
291+
<<: *environment
282292
steps:
283293
- checkout
284294
- <<: *install_poetry
@@ -317,6 +327,7 @@ jobs:
317327
test-lint:
318328
docker:
319329
- image: << pipeline.parameters.global-docker-image >>
330+
<<: *environment
320331
steps:
321332
- checkout
322333
- <<: *install_poetry
@@ -359,6 +370,7 @@ jobs:
359370
create-content-artifacts:
360371
docker:
361372
- image: << pipeline.parameters.global-docker-image >>
373+
<<: *environment
362374
steps:
363375
- checkout
364376
- <<: *install_poetry
@@ -381,6 +393,7 @@ jobs:
381393
docker:
382394
- image: << pipeline.parameters.global-docker-image >>
383395
resource_class: xlarge
396+
<<: *environment
384397
steps:
385398
- checkout
386399
- <<: *install_poetry
@@ -418,10 +431,11 @@ jobs:
418431
build:
419432
docker:
420433
- image: << pipeline.parameters.global-docker-image >>
434+
<<: *environment
421435
steps:
422436
- checkout
423437
- run:
424-
name: Build Distrubution
438+
name: Build Distribution
425439
command: poetry build
426440
- persist_to_workspace:
427441
root: ~/project
@@ -433,6 +447,7 @@ jobs:
433447
deploy:
434448
docker:
435449
- image: << pipeline.parameters.global-docker-image >>
450+
<<: *environment
436451
steps:
437452
- checkout
438453
- <<: *install_poetry
@@ -445,6 +460,7 @@ jobs:
445460
waiter:
446461
docker:
447462
- image: circleci/node
463+
<<: *environment
448464
steps:
449465
- run: |
450466
while [[ $(curl --location --request GET "https://circleci.com/api/v2/workflow/$CIRCLE_WORKFLOW_ID/job" | jq -r '.items[]|select(.name != "waiter")|.status' | grep -c "running") -gt 0 ]]
@@ -457,6 +473,7 @@ jobs:
457473
slack-notifier:
458474
docker:
459475
- image: cimg/python:<< pipeline.parameters.pythonversion_latest >>-node
476+
<<: *environment
460477
steps:
461478
- checkout
462479
- <<: *install_poetry

Diff for: CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
## Unreleased
33
* Added a period at the end of lines produced by the **generate-docs** command that state the tested version of the product.
44
* Update `RN112` validation's docs reference link.
5+
* Added support to control the maximum file size and log rotation files count in the sdk logger.
6+
* Fixed an issue with where passing the deprecated logging arguments to any command presented an incorrect recommendation for argument substitution.
7+
* Fixed an issue where the documentation of logging arguments was incorrect.
58
* Fixed an issue in calculating content graph hash when creating or updating it.
69
* Calling **graph create** or **graph update** now run the commands with default arguments, instead of showing the command help.
710
* Removed the use of chunks when calculating content relationships.

Diff for: demisto_sdk/__main__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ def main(ctx, config, version, release_notes, **kwargs):
214214
except DistributionNotFound:
215215
__version__ = "dev"
216216
logger.info(
217-
"[yellow]Cound not find the version of the demisto-sdk. This usually happens when running in a development environment.[/yellow]"
217+
"[yellow]Could not find the version of the demisto-sdk. This usually happens when running in a development environment.[/yellow]"
218218
)
219219
else:
220220
last_release = ""

Diff for: demisto_sdk/commands/common/logger.py

+65-39
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import sys
55
from logging.handlers import RotatingFileHandler
66
from pathlib import Path
7+
from typing import Any, Optional, Union
78

89
from demisto_sdk.commands.common.content_constant_paths import CONTENT_PATH
910
from demisto_sdk.commands.common.tools import string_to_bool
@@ -25,18 +26,42 @@
2526
DATE_FORMAT = "%Y-%m-%dT%H:%M:%S"
2627

2728
DEPRECATED_PARAMETERS = {
28-
"-v": "--console-log-threshold or --file-log-threshold",
29-
"-vv": "--console-log-threshold or --file-log-threshold",
30-
"-vvv": "--console-log-threshold or --file-log-threshold",
31-
"--verbose": "--console-log-threshold or --file-log-threshold",
32-
"-q": "--console-log-threshold or --file-log-threshold",
33-
"--quiet": "--console-log-threshold or --file-log-threshold",
34-
"-ln": "--log-path",
35-
"--log-name": "--log-path",
36-
"no_logging": "--console-log-threshold or --file-log-threshold",
29+
"-v": "--console_log_threshold or --file_log_threshold",
30+
"-vv": "--console_log_threshold or --file_log_threshold",
31+
"-vvv": "--console_log_threshold or --file_log_threshold",
32+
"--verbose": "--console_log_threshold or --file_log_threshold",
33+
"-q": "--console_log_threshold or --file_log_threshold",
34+
"--quiet": "--console_log_threshold or --file_log_threshold",
35+
"-ln": "--log_file_path",
36+
"--log-name": "--log_file_path",
37+
"no_logging": "--console_log_threshold or --file_log_threshold",
3738
}
3839

40+
41+
def parse_int_or_default(value: Any, default: int) -> int:
42+
"""
43+
Parse int or return default value
44+
Args:
45+
value: value to parse
46+
default: default value to return if parsing failed
47+
48+
Returns:
49+
int: parsed value or default value
50+
51+
"""
52+
try:
53+
return int(value)
54+
except (ValueError, TypeError):
55+
return default
56+
57+
3958
SUCCESS_LEVEL: int = 25
59+
DEMISTO_SDK_LOG_FILE_SIZE = parse_int_or_default(
60+
os.getenv("DEMISTO_SDK_LOG_FILE_SIZE"), 1_048_576 # 1MB
61+
)
62+
DEMISTO_SDK_LOG_FILE_COUNT = parse_int_or_default(
63+
os.getenv("DEMISTO_SDK_LOG_FILE_COUNT"), 10
64+
)
4065

4166

4267
def handle_deprecated_args(input_args):
@@ -97,10 +122,14 @@ def handle_deprecated_args(input_args):
97122

98123

99124
def get_handler_by_name(logger: logging.Logger, handler_name: str):
100-
for current_handler in logger.handlers:
101-
if current_handler.get_name == handler_name:
102-
return current_handler
103-
return None
125+
return next(
126+
(
127+
current_handler
128+
for current_handler in logger.handlers
129+
if current_handler.get_name == handler_name
130+
),
131+
None,
132+
)
104133

105134

106135
def set_demisto_logger(demisto_logger: logging.Logger):
@@ -124,7 +153,7 @@ def _add_logging_level(
124153
`logging` module or if the method name is already present
125154
Example
126155
-------
127-
>>> addLoggingLevel('TRACE', logging.DEBUG - 5)
156+
>>> _add_logging_level('TRACE', logging.DEBUG - 5)
128157
>>> logging.getLogger(__name__).setLevel("TRACE")
129158
>>> logging.getLogger(__name__).trace('that worked')
130159
>>> logging.trace('so did this')
@@ -144,17 +173,17 @@ def _add_logging_level(
144173
# This method was inspired by the answers to Stack Overflow post
145174
# http://stackoverflow.com/q/2183233/2988730, especially
146175
# http://stackoverflow.com/a/13638084/2988730
147-
def logForLevel(self, message, *args, **kwargs):
176+
def log_for_level(self, message, *args, **kwargs):
148177
if self.isEnabledFor(level_num):
149178
self._log(level_num, message, args, **kwargs)
150179

151-
def logToRoot(message, *args, **kwargs):
180+
def log_to_root(message, *args, **kwargs):
152181
logging.log(level_num, message, *args, **kwargs)
153182

154183
logging.addLevelName(level_num, level_name)
155184
setattr(logging, level_name, level_num)
156-
setattr(logging.getLoggerClass(), method_name, logForLevel)
157-
setattr(logging, method_name, logToRoot)
185+
setattr(logging.getLoggerClass(), method_name, log_for_level)
186+
setattr(logging, method_name, log_to_root)
158187

159188

160189
class ColorConsoleFormatter(logging.Formatter):
@@ -180,10 +209,7 @@ def __init__(
180209
@staticmethod
181210
def _record_contains_escapes(record: logging.LogRecord) -> bool:
182211
message = record.getMessage()
183-
for key in escapes:
184-
if not key.startswith("[/]") and key in message:
185-
return True
186-
return False
212+
return any(not key.startswith("[/]") and key in message for key in escapes)
187213

188214
@staticmethod
189215
def _string_starts_with_escapes(string: str) -> bool:
@@ -203,7 +229,7 @@ def _get_start_escapes(record: logging.LogRecord) -> str:
203229
while ColorConsoleFormatter._string_starts_with_escapes(current_message):
204230

205231
# Record starts with escapes - Extract them
206-
current_escape = current_message[0 : current_message.find("]") + 1]
232+
current_escape = current_message[: current_message.find("]") + 1]
207233
ret_value += current_escape
208234
current_message = current_message[
209235
len(current_escape) : current_message.find("]", len(current_escape)) + 1
@@ -263,16 +289,17 @@ def replace_escapes(self, message):
263289

264290

265291
def logging_setup(
266-
console_log_threshold=logging.INFO,
267-
file_log_threshold=logging.DEBUG,
268-
log_file_path=LOG_FILE_PATH,
292+
console_log_threshold: Union[int, str] = logging.INFO,
293+
file_log_threshold: Union[int, str] = logging.DEBUG,
294+
log_file_path: Optional[Union[str, Path]] = LOG_FILE_PATH,
269295
) -> logging.Logger:
270296
"""Init logger object for logging in demisto-sdk
271297
For more info - https://docs.python.org/3/library/logging.html
272298
273299
Args:
274-
console_log_threshold(int): Minimum console log threshold. Defaults to logging.INFO
275-
file_log_threshold(int): Minimum console log threshold. Defaults to logging.INFO
300+
console_log_threshold: Minimum console log threshold. Defaults to logging.INFO
301+
file_log_threshold: Minimum console log threshold. Defaults to logging.INFO
302+
log_file_path: Path to log file. Defaults to LOG_FILE_PATH
276303
277304
Returns:
278305
logging.Logger: logger object
@@ -287,24 +314,22 @@ def logging_setup(
287314

288315
console_handler = logging.StreamHandler()
289316
console_handler.set_name(CONSOLE_HANDLER)
290-
console_handler.setLevel(
291-
console_log_threshold if console_log_threshold else logging.INFO
292-
)
317+
console_handler.setLevel(console_log_threshold or logging.INFO)
293318

294319
if custom_log_path := os.getenv("DEMISTO_SDK_LOG_FILE_PATH"):
295320
current_log_file_path = Path(custom_log_path)
296321
else:
297-
current_log_file_path = log_file_path or LOG_FILE_PATH
298-
if Path(current_log_file_path).is_dir():
322+
current_log_file_path = Path(log_file_path or LOG_FILE_PATH)
323+
if current_log_file_path.is_dir():
299324
current_log_file_path = current_log_file_path / LOG_FILE_NAME
300325
file_handler = RotatingFileHandler(
301326
filename=current_log_file_path,
302327
mode="a",
303-
maxBytes=1048576,
304-
backupCount=10,
328+
maxBytes=DEMISTO_SDK_LOG_FILE_SIZE,
329+
backupCount=DEMISTO_SDK_LOG_FILE_COUNT,
305330
)
306331
file_handler.set_name(FILE_HANDLER)
307-
file_handler.setLevel(file_log_threshold if file_log_threshold else logging.DEBUG)
332+
file_handler.setLevel(file_log_threshold or logging.DEBUG)
308333

309334
if string_to_bool(os.getenv("DEMISTO_SDK_LOG_NO_COLORS", "False")):
310335
console_handler.setFormatter(fmt=NoColorFileFormatter())
@@ -335,9 +360,10 @@ def logging_setup(
335360
demisto_logger.debug(f"Platform: {platform.system()}")
336361

337362
if not log_file_name_notified:
338-
demisto_logger.info(
339-
f"[yellow]Log file location: {current_log_file_path}[/yellow]"
340-
)
363+
if string_to_bool(os.getenv("DEMISTO_SDK_LOG_NOTIFY_PATH", "True")):
364+
demisto_logger.info(
365+
f"[yellow]Log file location: {current_log_file_path}[/yellow]"
366+
)
341367
log_file_name_notified = True
342368

343369
logger = demisto_logger

Diff for: demisto_sdk/commands/content_graph/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ When the graph creation is completed, it will be available in http://localhost:7
7171

7272
Quiet output, only output results in the end.
7373

74-
* **-lp, --log-path**
74+
* **-lp, --log_file_path**
7575

7676
Path to store all levels of logs.
7777

@@ -124,7 +124,7 @@ When the graph update is completed, it will be available in http://localhost:747
124124

125125
Quiet output, only output results in the end.
126126

127-
* **-lp, --log-path**
127+
* **-lp, --log_file_path**
128128

129129
Path to store all levels of logs.
130130

Diff for: demisto_sdk/commands/generate_modeling_rules/README.md

+3-4
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,9 @@ $ generate-modeling-rules [OPTIONS]
1414
* `-o, --output PATH`: A path to the folder you want to generate the modeling rules in. Best practice is to put the working pack path here. [required]
1515
* `-ve, --vendor TEXT`: The vendor name of the product in snake_case.
1616
* `-p, --product TEXT`: The name of the product in snake_case.
17-
* `-v, --verbose INTEGER RANGE`: Verbosity level -v / -vv / .. / -vvv [Default: 0; x<=3]
18-
* `--quiet / --no-quiet`: Quiet output - sets verbosity to default. [Default: no-quiet]
19-
* `-lp, --log-path PATH`: Path of the directory in which you would like to store all log levels. If not given, then the "log_file_name" command line option will be disregarded, and the log output will be to stdout.
20-
* `-ln, --log-name TEXT`: The file name (including extension) where the log output should be saved to. [Default: generate_modeling_rules.log]
17+
* `-clt, --console_log_threshold`: Minimum logging threshold for the console logger. [default: INFO]
18+
* `-flt --file_log_threshold`: Minimum logging threshold for the file logger. [default: DEBUG]
19+
* `-lp, --log_file_path`: Path to the log file. Default: ./demisto_sdk_debug.log. [default: ./demisto_sdk_debug.log]
2120
* `--install-completion`: Install completion for the current shell.
2221
* `--show-completion`: Show completion for the current shell, to copy it or customize the installation.
2322
* `--help`: Show this message and exit.

Diff for: demisto_sdk/commands/generate_unit_tests/README.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ Also supports generating unit tests for specific commands.
1313
Specific commands name to generate unit test for (e.g. xdr-get-incidents).
1414
* *-o, --output_dir*
1515
Directory to store the command output (generated test file) in (default is the input integration directory).
16-
* *-v, --verbose*
17-
Verbose output - mainly for debugging purposes, logging level will be displayed accordingly.
18-
* *-q, --quiet*
19-
Quiet output, only output results in the end.
20-
* *-lp, --log-path*
21-
Path to store all levels of logs.
16+
* *-clt, --console_log_threshold*
17+
Minimum logging threshold for the console logger. [default: INFO]
18+
* *-flt --file_log_threshold*
19+
Minimum logging threshold for the file logger. [default: DEBUG]
20+
* *-lp, --log_file_path*
21+
Path to the log file. Default: ./demisto_sdk_debug.log. [default: ./demisto_sdk_debug.log]
2222
* *-e, --examples*
2323
One of the following:
2424
- A path for a file containing Integration command examples. Each command example should be in a separate line.

0 commit comments

Comments
 (0)