in client/commands/remote_logging.py [0:0]
def log_usage_with_additional_info(command_name: str) -> _DecoratorWithDynamicLogging:
"""
This decorator is a variant of `log_usage`.
With `log_usage`, what to log needs to be determined prior to running the
decorated command. In contrast, `log_usage_with_additional_info` collects what
to log after the decorated command is done executing. Logging content can
therefore depend on the execution result after-the-fact.
In exchange for the flexibility, `log_usage_with_additional_info` requires slightly
more sophisticated setup: the decorated function should not only return a
`commands.ExitCode`, but also attach the dynamically-computed logging dictionary
alongside with the return code. The decorator itself will make sure that the
additional info will be faithfully forwarded when invoking the underlying logging
API.
"""
auxiliary_info: Dict[str, Optional[str]] = {
"cwd": os.getcwd(),
"client_version": version.__version__,
"command_line": " ".join(sys.argv),
"command": command_name,
}
def decorator(
__command: "Callable[Concatenate[configuration_module.Configuration, TParams], ExitCodeWithAdditionalLogging]", # noqa: B950
) -> "Callable[Concatenate[configuration_module.Configuration, TParams], commands.ExitCode]": # noqa: B950
def decorated(
configuration: configuration_module.Configuration,
*args: TParams.args,
**kwargs: TParams.kwargs
) -> commands.ExitCode:
command_timer: timer.Timer = timer.Timer()
def log_success(
exit_code: int, additional_logging: Dict[str, Optional[str]]
) -> None:
statistics_logger.log_with_configuration(
category=statistics_logger.LoggerCategory.USAGE,
configuration=configuration,
integers={
"exit_code": exit_code,
"runtime": int(command_timer.stop_in_millisecond()),
},
normals={**auxiliary_info, **additional_logging},
)
def log_failure(
error: Exception, exit_code: int = commands.ExitCode.FAILURE
) -> None:
statistics_logger.log_with_configuration(
category=statistics_logger.LoggerCategory.USAGE,
configuration=configuration,
integers={
"exit_code": exit_code,
"runtime": int(command_timer.stop_in_millisecond()),
},
normals={
**auxiliary_info,
"client_exception": str(error),
},
)
try:
result = __command(configuration, *args, **kwargs)
exit_code = result.exit_code
log_success(exit_code, result.additional_logging)
return exit_code
except configuration_module.InvalidConfiguration as error:
log_failure(error, exit_code=commands.ExitCode.CONFIGURATION_ERROR)
raise
except Exception as error:
log_failure(error)
raise
return decorated
# pyre-ignore[7]: (T84575843) This should be fine.
return decorator