Source code for boxsdk.util.log
# coding: utf-8
from __future__ import unicode_literals
from collections import Mapping
import logging
try:
from logging import NullHandler
except ImportError:
class NullHandler(logging.Handler):
def emit(self, record):
pass
import sys
from six import string_types, iteritems
_no_logger = object()
class Logging(object):
_has_setup = False
KEYS_TO_SANITIZE = (
'Authorization',
'access_token',
'refresh_token',
'subject_token',
'token',
'client_id',
'client_secret',
'code',
'shared_link',
'download_url',
'jwt_private_key',
'jwt_private_key_passphrase',
'password',
)
def setup_logging(self, stream_or_file=_no_logger, debug=False, name=None):
if not self._has_setup:
self._has_setup = True
self._setup_logging(stream_or_file, debug, name)
@staticmethod
def _setup_logging(stream_or_file=_no_logger, debug=False, name=None):
logger = logging.getLogger(name)
if isinstance(stream_or_file, string_types):
logger.addHandler(logging.FileHandler(stream_or_file, mode='a'))
elif stream_or_file is not _no_logger:
logger.addHandler(logging.StreamHandler(stream_or_file or sys.stdout))
logger.setLevel(logging.DEBUG if debug else logging.INFO)
@staticmethod
def sanitize_value(value):
return '---{}'.format(value[-4:])
def sanitize_dictionary(self, dictionary):
if not isinstance(dictionary, Mapping):
return dictionary
sanitized_dictionary = {}
for key, value in iteritems(dictionary):
if key in self.KEYS_TO_SANITIZE and isinstance(value, string_types):
sanitized_dictionary[key] = self.sanitize_value(value)
elif isinstance(value, Mapping):
sanitized_dictionary[key] = self.sanitize_dictionary(value)
else:
sanitized_dictionary[key] = value
return sanitized_dictionary
_logging = Logging()
[docs]def setup_logging(stream_or_file=_no_logger, debug=False, name=None):
"""
Create a logger for communicating with the user or writing to log files.
Sets the level to INFO or DEBUG, depending on the debug flag.
If a stream or file is passed (or None is passed to stream_or_file), then
a handler to that stream or file (stdout for None) is added to the logger.
:param stream_or_file:
The destination of the log messages. If None, stdout will be used.
:type stream_or_file:
`unicode` or `file` or None
:param debug:
Whether or not the logger will be at the DEBUG level (if False, the logger will be at the INFO level).
:type debug:
`bool` or None
:param name:
The logging channel. If None, a root logger will be created.
:type name:
`unicode` or None
"""
_logging.setup_logging(stream_or_file, debug, name)
[docs]def sanitize_dictionary(dictionary):
"""
Get a copy of a dictionary that has sensitive information redacted. Should be called on objects that will be
logged or printed.
:param dictionary: Dictionary that may contain sensitive information.
:type dictionary: :class:`Mapping`
:return: Copy of the dictionary with sensitive information redacted.
:rtype: `dict`
"""
return _logging.sanitize_dictionary(dictionary)
logging.getLogger(__name__).addHandler(NullHandler())
__all__ = list(map(str, ['setup_logging', 'sanitize_dictionary']))