Commit 9a4e8d906ff602bca392076041b54eb11a6f72ca

Authored by decalage2
1 parent a8209d75

msodde: added logging

Showing 1 changed file with 67 additions and 1 deletions
oletools/msodde.py
... ... @@ -50,6 +50,7 @@ from __future__ import print_function
50 50 # 2017-10-24 ES: - group tags and track begin/end tags to keep DDE strings together
51 51 # 2017-10-25 CH: - add json output
52 52 # 2017-10-25 CH: - parse doc
  53 +# PL: - added logging
53 54  
54 55 __version__ = '0.52dev4'
55 56  
... ... @@ -75,6 +76,7 @@ import zipfile
75 76 import os
76 77 import sys
77 78 import json
  79 +import logging
78 80  
79 81 from oletools.thirdparty import olefile
80 82  
... ... @@ -110,6 +112,57 @@ BANNER_JSON = dict(type='meta', version=__version__, name='msodde',
110 112 'Please report any issue at '
111 113 'https://github.com/decalage2/oletools/issues')
112 114  
  115 +# === LOGGING =================================================================
  116 +
  117 +DEFAULT_LOG_LEVEL = "warning" # Default log level
  118 +LOG_LEVELS = {
  119 + 'debug': logging.DEBUG,
  120 + 'info': logging.INFO,
  121 + 'warning': logging.WARNING,
  122 + 'error': logging.ERROR,
  123 + 'critical': logging.CRITICAL
  124 +}
  125 +
  126 +class NullHandler(logging.Handler):
  127 + """
  128 + Log Handler without output, to avoid printing messages if logging is not
  129 + configured by the main application.
  130 + Python 2.7 has logging.NullHandler, but this is necessary for 2.6:
  131 + see https://docs.python.org/2.6/library/logging.html#configuring-logging-for-a-library
  132 + """
  133 + def emit(self, record):
  134 + pass
  135 +
  136 +def get_logger(name, level=logging.CRITICAL+1):
  137 + """
  138 + Create a suitable logger object for this module.
  139 + The goal is not to change settings of the root logger, to avoid getting
  140 + other modules' logs on the screen.
  141 + If a logger exists with same name, reuse it. (Else it would have duplicate
  142 + handlers and messages would be doubled.)
  143 + The level is set to CRITICAL+1 by default, to avoid any logging.
  144 + """
  145 + # First, test if there is already a logger with the same name, else it
  146 + # will generate duplicate messages (due to duplicate handlers):
  147 + if name in logging.Logger.manager.loggerDict:
  148 + #NOTE: another less intrusive but more "hackish" solution would be to
  149 + # use getLogger then test if its effective level is not default.
  150 + logger = logging.getLogger(name)
  151 + # make sure level is OK:
  152 + logger.setLevel(level)
  153 + return logger
  154 + # get a new logger:
  155 + logger = logging.getLogger(name)
  156 + # only add a NullHandler for this logger, it is up to the application
  157 + # to configure its own logging:
  158 + logger.addHandler(NullHandler())
  159 + logger.setLevel(level)
  160 + return logger
  161 +
  162 +# a global logger object used for debugging:
  163 +log = get_logger('msodde')
  164 +
  165 +
113 166 # === ARGUMENT PARSING =======================================================
114 167  
115 168 class ArgParserWithBanner(argparse.ArgumentParser):
... ... @@ -134,6 +187,8 @@ def process_args(cmd_line_args=None):
134 187 parser.add_argument("--json", '-j', action='store_true',
135 188 help="Output in json format")
136 189 parser.add_argument("--nounquote", help="don't unquote values",action='store_true')
  190 + parser.add_argument('-l', '--loglevel', dest="loglevel", action="store", default=DEFAULT_LOG_LEVEL,
  191 + help="logging level debug/info/warning/error/critical (default=warning)")
137 192  
138 193 return parser.parse_args(cmd_line_args)
139 194  
... ... @@ -282,6 +337,7 @@ def process_ole(filepath):
282 337 empty if none were found. dde-links will still being with the dde[auto] key
283 338 word (possibly after some whitespace)
284 339 """
  340 + log.debug('process_ole')
285 341 #print('Looks like ole')
286 342 ole = olefile.OleFileIO(filepath, path_encoding=None)
287 343 text_parts = process_ole_storage(ole)
... ... @@ -289,8 +345,9 @@ def process_ole(filepath):
289 345  
290 346  
291 347 def process_openxml(filepath):
  348 + log.debug('process_openxml')
292 349 all_fields = []
293   - z = zipfile.ZipFile(args.filepath)
  350 + z = zipfile.ZipFile(filepath)
294 351 for filepath in z.namelist():
295 352 if filepath in LOCATIONS:
296 353 data = z.read(filepath)
... ... @@ -387,6 +444,15 @@ def main(cmd_line_args=None):
387 444 """
388 445 args = process_args(cmd_line_args)
389 446  
  447 + # Setup logging to the console:
  448 + # here we use stdout instead of stderr by default, so that the output
  449 + # can be redirected properly.
  450 + logging.basicConfig(level=LOG_LEVELS[args.loglevel], stream=sys.stdout,
  451 + format='%(levelname)-8s %(message)s')
  452 + # enable logging in the modules:
  453 + log.setLevel(logging.NOTSET)
  454 +
  455 +
390 456 if args.nounquote :
391 457 global NO_QUOTES
392 458 NO_QUOTES = True
... ...