Skip to content

Commit cdb7fb2

Browse files
author
Juliya Smith
authored
Chore/logging improvements real (#49)
1 parent 68d38e9 commit cdb7fb2

30 files changed

+687
-1150
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
The intended audience of this file is for py42 consumers -- as such, changes that don't affect
99
how a consumer would use the library (e.g. adding unit tests, updating documentation, etc) are not captured here.
1010

11+
## Unreleased
12+
13+
### Added
14+
15+
- Success messages for `profile delete` and `profile update`.
16+
- Additional information in the error log file:
17+
- The full command path for the command that errored.
18+
- User-facing error messages you see during adhoc sessions.
19+
1120
### 0.5.3 - 2020-05-04
1221

1322
### Fixed

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
package_dir={"": "src"},
2222
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4",
2323
install_requires=[
24-
"c42eventextractor==0.2.7",
24+
"c42eventextractor==0.2.9",
2525
"keyring==18.0.1",
2626
"keyrings.alt==3.2.0",
2727
"py42>=1.1.1",

src/code42cli/bulk.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from code42cli.compat import open, str
66
from code42cli.worker import Worker
7-
from code42cli.errors import print_errors_occurred
7+
from code42cli.logger import get_main_cli_logger
88
from code42cli.args import SDK_ARG_NAME, PROFILE_ARG_NAME
99

1010

@@ -21,7 +21,7 @@ def generate_template(handler, path=None):
2121
]
2222

2323
if len(args) <= 1:
24-
print(
24+
get_main_cli_logger().print_info(
2525
u"A blank file was generated because there are no csv headers needed for this command. "
2626
u"Simply enter one {} per line.".format(args[0])
2727
)
@@ -103,9 +103,12 @@ def _process_flat_file_row(self, row):
103103
def _print_result(self):
104104
stats = self.__worker.stats
105105
successes = stats.total - stats.total_errors
106-
print(u"{} processed successfully out of {}.".format(successes, stats.total))
106+
logger = get_main_cli_logger()
107+
logger.print_and_log_info(
108+
u"{} processed successfully out of {}.".format(successes, stats.total)
109+
)
107110
if stats.total_errors:
108-
print_errors_occurred()
111+
logger.print_errors_occurred_message()
109112

110113

111114
class CSVReader(object):

src/code42cli/cmds/detectionlists/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
from code42cli.compat import str
12
from code42cli.cmds.detectionlists.commands import DetectionListCommandFactory
23
from code42cli.bulk import generate_template, run_bulk_process, CSVReader, FlatFileReader
3-
from code42cli.util import print_error
4+
from code42cli.logger import get_main_cli_logger
45
from code42cli.cmds.detectionlists.enums import (
56
BulkCommandType,
67
DetectionLists,
@@ -148,7 +149,6 @@ def _remove_employee(self, sdk, profile, *args, **kwargs):
148149
self.handlers.remove_employee(sdk, profile, *args, **kwargs)
149150

150151

151-
152152
def load_username_description(argument_collection):
153153
"""Loads the arg descriptions for the `username` CLI parameter."""
154154
username = argument_collection.arg_configs[DetectionListUserKeys.USERNAME]
@@ -184,7 +184,7 @@ def get_user_id(sdk, username):
184184
users = sdk.users.get_by_username(username)[u"users"]
185185
if not users:
186186
ex = UserDoesNotExistError(username)
187-
print_error(str(ex))
187+
get_main_cli_logger().print_and_log_error(str(ex))
188188
raise ex
189189
return users[0][u"userUid"]
190190

src/code42cli/cmds/profile.py

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
from __future__ import print_function
2-
31
from getpass import getpass
42

53
import code42cli.profile as cliprofile
4+
from code42cli.compat import str
5+
from code42cli.profile import print_and_log_no_existing_profile
66
from code42cli.args import PROFILE_HELP, PROFILE_ARG_NAME
77
from code42cli.commands import Command
88
from code42cli.sdk_client import validate_connection
9-
from code42cli.util import does_user_agree, print_error, print_no_existing_profile_message
9+
from code42cli.util import does_user_agree
10+
from code42cli.logger import get_main_cli_logger
1011

1112

1213
def load_subcommands():
@@ -79,25 +80,27 @@ def load_subcommands():
7980
def show_profile(name=None):
8081
"""Prints the given profile to stdout."""
8182
c42profile = cliprofile.get_profile(name)
82-
print(u"\n{0}:".format(c42profile.name))
83-
print(u"\t* username = {}".format(c42profile.username))
84-
print(u"\t* authority url = {}".format(c42profile.authority_url))
85-
print(u"\t* ignore-ssl-errors = {}".format(c42profile.ignore_ssl_errors))
83+
logger = get_main_cli_logger()
84+
logger.print_info(u"\n{0}:".format(c42profile.name))
85+
logger.print_info(u"\t* username = {}".format(c42profile.username))
86+
logger.print_info(u"\t* authority url = {}".format(c42profile.authority_url))
87+
logger.print_info(u"\t* ignore-ssl-errors = {}".format(c42profile.ignore_ssl_errors))
8688
if cliprofile.get_stored_password(c42profile.name) is not None:
87-
print(u"\t* A password is set.")
88-
print(u"")
89+
logger.print_info(u"\t* A password is set.")
90+
logger.print_info(u"")
8991

9092

9193
def create_profile(profile, server, username, disable_ssl_errors=False):
9294
cliprofile.create_profile(profile, server, username, disable_ssl_errors)
9395
_prompt_for_allow_password_set(profile)
96+
get_main_cli_logger().print_info(u"Successfully created profile '{}'.".format(profile))
9497

9598

9699
def update_profile(name=None, server=None, username=None, disable_ssl_errors=None):
97100
profile = cliprofile.get_profile(name)
98101
cliprofile.update_profile(profile.name, server, username, disable_ssl_errors)
99102
_prompt_for_allow_password_set(profile.name)
100-
print(u"Profile '{}' has been updated.".format(profile.name))
103+
get_main_cli_logger().print_info(u"Profile '{}' has been updated.".format(profile.name))
101104

102105

103106
def prompt_for_password_reset(name=None):
@@ -110,7 +113,8 @@ def prompt_for_password_reset(name=None):
110113

111114
def _validate_connection(authority, username, password):
112115
if not validate_connection(authority, username, password):
113-
print_error(
116+
logger = get_main_cli_logger()
117+
logger.print_and_log_error(
114118
u"Your credentials failed to validate, so your password was not stored."
115119
u"Check your network connection and the spelling of your username and server URL."
116120
)
@@ -120,11 +124,12 @@ def _validate_connection(authority, username, password):
120124
def list_profiles(*args):
121125
"""Lists all profiles that exist for this OS user."""
122126
profiles = cliprofile.get_all_profiles()
127+
logger = get_main_cli_logger()
123128
if not profiles:
124-
print_no_existing_profile_message()
129+
print_and_log_no_existing_profile()
125130
return
126131
for profile in profiles:
127-
print(profile)
132+
logger.print_info(str(profile))
128133

129134

130135
def use_profile(profile):
@@ -133,28 +138,31 @@ def use_profile(profile):
133138

134139

135140
def delete_profile(name):
141+
logger = get_main_cli_logger()
136142
if cliprofile.is_default_profile(name):
137-
print(u"\n{} is currently the default profile!".format(name))
143+
logger.print_info(u"\n{} is currently the default profile!".format(name))
138144
if not does_user_agree(
139-
u"\nDeleting this profile will also delete any stored passwords and checkpoints. Are you sure? (y/n): "
145+
u"\nDeleting this profile will also delete any stored passwords and checkpoints. "
146+
u"Are you sure? (y/n): "
140147
):
141148
return
142149
cliprofile.delete_profile(name)
143150

144151

145152
def delete_all_profiles():
146153
existing_profiles = cliprofile.get_all_profiles()
154+
logger = get_main_cli_logger()
147155
if existing_profiles:
148-
print(u"\nAre you sure you want to delete the following profiles?")
156+
logger.print_info(u"\nAre you sure you want to delete the following profiles?")
149157
for profile in existing_profiles:
150-
print(u"\t{}".format(profile.name))
158+
logger.print_info(u"\t{}".format(profile.name))
151159
if does_user_agree(
152160
u"\nThis will also delete any stored passwords and checkpoints. (y/n): "
153161
):
154162
for profile in existing_profiles:
155163
cliprofile.delete_profile(profile.name)
156164
else:
157-
print(u"\nNo profiles exist. Nothing to delete.")
165+
logger.print_info(u"\nNo profiles exist. Nothing to delete.")
158166

159167

160168
def _load_optional_profile_description(argument_collection):

src/code42cli/cmds/securitydata/extraction.py

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
from __future__ import print_function
2-
31
import json
42

5-
from c42eventextractor import FileEventHandlers
3+
from c42eventextractor import ExtractionHandlers
64
from c42eventextractor.extractors import FileEventExtractor
75
from py42.sdk.queries.fileevents.filters import *
86

@@ -12,11 +10,10 @@
1210
IS_INCREMENTAL_KEY,
1311
SearchArguments,
1412
)
15-
from code42cli.logger import get_error_logger
1613
from code42cli.cmds.shared.cursor_store import FileEventCursorStore
1714
from code42cli.compat import str
18-
from code42cli.util import is_interactive, print_bold, print_error, print_to_stderr
1915
import code42cli.errors as errors
16+
from code42cli.logger import get_main_cli_logger
2017

2118

2219
_TOTAL_EVENTS = 0
@@ -62,18 +59,20 @@ def _determine_if_advanced_query(args):
6259
for key in given_args:
6360
val = given_args[key]
6461
if not _verify_compatibility_with_advanced_query(key, val):
65-
print_error(u"You cannot use --advanced-query with additional search args.")
62+
logger = get_main_cli_logger()
63+
logger.print_and_log_error(
64+
u"You cannot use --advanced-query with additional search args."
65+
)
6666
exit(1)
6767
return True
6868
return False
6969

7070

7171
def _verify_begin_date_requirements(args, cursor_store):
7272
if _begin_date_is_required(args, cursor_store) and not args.begin:
73-
print_error(u"'begin date' is required.")
74-
print(u"")
75-
print_bold(u"Try using '-b' or '--begin'. Use `-h` for more info.")
76-
print(u"")
73+
logger = get_main_cli_logger()
74+
logger.print_and_log_error(u"'begin date' is required.\n")
75+
logger.print_bold(u"Try using '-b' or '--begin'. Use `-h` for more info.\n")
7776
exit(1)
7877

7978

@@ -94,7 +93,8 @@ def _verify_exposure_types(exposure_types):
9493
options = list(ExposureTypeOptions())
9594
for exposure_type in exposure_types:
9695
if exposure_type not in options:
97-
print_error(u"'{0}' is not a valid exposure type.".format(exposure_type))
96+
logger = get_main_cli_logger()
97+
logger.print_and_log_error(u"'{0}' is not a valid exposure type.".format(exposure_type))
9898
exit(1)
9999

100100

@@ -121,16 +121,16 @@ def _get_event_timestamp_filter(begin_date, end_date):
121121
end_date = end_date.strip() if end_date else None
122122
return date_helper.create_event_timestamp_filter(begin_date, end_date)
123123
except date_helper.DateArgumentException as ex:
124-
print_error(str(ex))
124+
get_main_cli_logger().print_and_log_error(str(ex))
125125
exit(1)
126126

127127

128128
def _create_event_handlers(output_logger, cursor_store):
129-
handlers = FileEventHandlers()
130-
error_logger = get_error_logger()
129+
handlers = ExtractionHandlers()
131130

132131
def handle_error(exception):
133-
error_logger.error(exception)
132+
logger = get_main_cli_logger()
133+
logger.log_error(exception)
134134
errors.ERRORED = True
135135

136136
handlers.handle_error = handle_error
@@ -172,9 +172,17 @@ def _verify_compatibility_with_advanced_query(key, val):
172172
def _handle_result():
173173
# Have to call this explicitly (instead of relying on invoker) because errors are caught in
174174
# `c42eventextractor`.
175-
errors.print_errors_occurred_if_needed()
175+
logger = get_main_cli_logger()
176+
_print_errors_occurred_if_needed(logger)
176177
if not _TOTAL_EVENTS:
177-
print_to_stderr(u"No results found\n")
178+
logger.print_and_log_info(u"No results found.")
179+
180+
181+
def _print_errors_occurred_if_needed(logger):
182+
"""If interactive and errors occurred, it will print a message telling the user how to retrieve
183+
error logs."""
184+
if errors.ERRORED:
185+
logger.print_errors_occurred_message()
178186

179187

180188
def _try_append_exposure_types_filter(filters, include_non_exposure_events, exposure_types):
@@ -185,7 +193,9 @@ def _try_append_exposure_types_filter(filters, include_non_exposure_events, expo
185193

186194
def _create_exposure_type_filter(include_non_exposure_events, exposure_types):
187195
if include_non_exposure_events and exposure_types:
188-
print_error(u"Cannot use exposure types with `--include-non-exposure`.")
196+
get_main_cli_logger().print_and_log_error(
197+
u"Cannot use exposure types with `--include-non-exposure`."
198+
)
189199
exit(1)
190200
if exposure_types:
191201
return ExposureType.is_in(exposure_types)

src/code42cli/cmds/securitydata/logger_factory.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,23 @@
99
from c42eventextractor.logging.handlers import NoPrioritySysLogHandlerWrapper
1010

1111
from code42cli.cmds.securitydata.enums import OutputFormat
12-
from code42cli.util import get_url_parts, print_error
13-
from code42cli.logger import logger_has_handlers, logger_deps_lock, apply_logger_dependencies
12+
from code42cli.util import get_url_parts
13+
from code42cli.logger import (
14+
logger_has_handlers,
15+
logger_deps_lock,
16+
add_handler_to_logger,
17+
get_main_cli_logger,
18+
get_logger_for_stdout as get_stdout_logger,
19+
)
1420

1521

1622
def get_logger_for_stdout(output_format):
1723
"""Gets the stdout logger for the given format.
18-
1924
Args:
2025
output_format: CEF, JSON, or RAW_JSON. Each type results in a different logger instance.
2126
"""
22-
logger = logging.getLogger(u"code42_stdout_{0}".format(output_format.lower()))
23-
if logger_has_handlers(logger):
24-
return logger
25-
26-
with logger_deps_lock:
27-
if not logger_has_handlers(logger):
28-
handler = logging.StreamHandler(sys.stdout)
29-
return _init_logger(logger, handler, output_format)
30-
return logger
27+
formatter = _get_formatter(output_format)
28+
return get_stdout_logger(output_format.lower(), formatter)
3129

3230

3331
def get_logger_for_file(filename, output_format):
@@ -69,7 +67,8 @@ def get_logger_for_server(hostname, protocol, output_format):
6967
url_parts[0], port=port, protocol=protocol
7068
).handler
7169
except:
72-
print_error(u"Unable to connect to {0}.".format(hostname))
70+
logger = get_main_cli_logger()
71+
logger.print_and_log_error(u"Unable to connect to {0}.".format(hostname))
7372
exit(1)
7473
return _init_logger(logger, handler, output_format)
7574
return logger
@@ -78,7 +77,7 @@ def get_logger_for_server(hostname, protocol, output_format):
7877
def _init_logger(logger, handler, output_format):
7978
formatter = _get_formatter(output_format)
8079
logger.setLevel(logging.INFO)
81-
return apply_logger_dependencies(logger, handler, formatter)
80+
return add_handler_to_logger(logger, handler, formatter)
8281

8382

8483
def _get_formatter(output_format):

0 commit comments

Comments
 (0)