Commit 9a4e8d906ff602bca392076041b54eb11a6f72ca
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 | ... | ... |