From 2bcf7d4ce4f54dc826312f6bad3c279357e2e5ce Mon Sep 17 00:00:00 2001 From: Josh Roesslein Date: Thu, 24 Sep 2009 14:43:45 -0500 Subject: [PATCH] Added logging support into tweepy. --- CHANGES | 4 ++++ tweepy/__init__.py | 1 + tweepy/api.py | 4 +++- tweepy/binder.py | 22 +++++++++++++++++- tweepy/logging.py | 58 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 tweepy/logging.py diff --git a/CHANGES b/CHANGES index ee21514..9eb8de0 100644 --- a/CHANGES +++ b/CHANGES @@ -19,6 +19,10 @@ during upgrade will be listed here. get_authorization_url() now takes a boolean that when true uses the "sign in with twitter" flow. See http://apiwiki.twitter.com/Sign-in-with-Twitter ++ Logging + + Added TweepyLogger interface which allows applications + to collect log messages from Tweepy for debugging purposes. + + Dummy, console, and file loggers available + Examples + Appengine demo (oauth) + Documentation of each method in api.py diff --git a/tweepy/__init__.py b/tweepy/__init__.py index 29c9771..e9ed4f1 100644 --- a/tweepy/__init__.py +++ b/tweepy/__init__.py @@ -13,6 +13,7 @@ from . api import API from . cache import Cache, MemoryCache, FileCache, MemCache from . auth import BasicAuthHandler, OAuthHandler from . streaming import Stream, StreamListener +from . logging import TweepyLogger, DummyLogger, ConsoleLogger, FileLogger # Global, unauthenticated instance of API api = API() diff --git a/tweepy/api.py b/tweepy/api.py index 8e0038b..e5c1f92 100644 --- a/tweepy/api.py +++ b/tweepy/api.py @@ -8,6 +8,7 @@ import mimetypes from . binder import bind_api from . error import TweepError from . auth import BasicAuthHandler, OAuthHandler +from . logging import DummyLogger from tweepy.parsers import * @@ -15,7 +16,7 @@ class API(object): """Twitter API""" def __init__(self, auth_handler=None, host='twitter.com', cache=None, - secure=False, api_root='', validate=True): + secure=False, api_root='', validate=True, logger=DummyLogger()): # you may access these freely self.auth_handler = auth_handler self.host = host @@ -23,6 +24,7 @@ class API(object): self.cache = cache self.secure = secure self.validate = validate + self.logger = logger # not a good idea to touch these self._username = None diff --git a/tweepy/binder.py b/tweepy/binder.py index 89626a8..ef48d09 100644 --- a/tweepy/binder.py +++ b/tweepy/binder.py @@ -17,10 +17,16 @@ def bind_api(path, parser, allowed_param=None, method='GET', require_auth=False, if require_auth and not api.auth_handler: raise TweepError('Authentication required!') + # Log some useful infomation + api.logger.debug('Starting request...') + api.logger.debug(' path: %s' % path) + api.logger.debug(' method: %s' % method) + # check for post_data parameter if 'post_data' in kargs: post_data = kargs['post_data'] del kargs['post_data'] + api.logger.debug(' post data: %s' % post_data) else: post_data = None @@ -30,6 +36,7 @@ def bind_api(path, parser, allowed_param=None, method='GET', require_auth=False, del kargs['headers'] else: headers = {} + api.logger.debug(' headers: %s' % headers) # build parameter dict if allowed_param: @@ -51,6 +58,7 @@ def bind_api(path, parser, allowed_param=None, method='GET', require_auth=False, if len(args) > 0 or len(kargs) > 0: raise TweepError('This method takes no parameters!') parameters = None + api.logger.debug(' parameters: %s' % parameters) # Build url with parameters if parameters: @@ -67,7 +75,10 @@ def bind_api(path, parser, allowed_param=None, method='GET', require_auth=False, # Apply authentication if api.auth_handler: - api.auth_handler.apply_auth(scheme + _host + url, method, headers, parameters) + api.auth_handler.apply_auth( + scheme + _host + url, + method, headers, parameters + ) # Check cache if caching enabled and method is GET if api.cache and method == 'GET': @@ -80,6 +91,7 @@ def bind_api(path, parser, allowed_param=None, method='GET', require_auth=False, result._api = api else: cache_result._api = api + api.logger.debug("Cache hit!") return cache_result # Open connection @@ -94,6 +106,9 @@ def bind_api(path, parser, allowed_param=None, method='GET', require_auth=False, # Get response resp = conn.getresponse() + api.logger.debug('Received response...') + api.logger.debug(' headers: %s' % resp.getheaders()) + api.logger.debug(' status code: %s' % resp.status) # If an error was returned, throw an exception if resp.status != 200: @@ -101,12 +116,14 @@ def bind_api(path, parser, allowed_param=None, method='GET', require_auth=False, error_msg = parse_error(resp.read()) except Exception: error_msg = "Twitter error response: status code = %s" % resp.status + api.logger.error(' Error: %s' % error_msg) raise TweepError(error_msg) # Pass returned body into parser and return parser output try: out = parser(resp.read(), api) except Exception: + api.logger.error(" parse error!") raise TweepError("Failed to parse returned data") conn.close() @@ -126,6 +143,9 @@ def bind_api(path, parser, allowed_param=None, method='GET', require_auth=False, # store result in cache if api.cache and method == 'GET': api.cache.store(url, out) + api.logger.debug(" caching result") + + api.logger.debug('request done.') return out diff --git a/tweepy/logging.py b/tweepy/logging.py new file mode 100644 index 0000000..dc57c6f --- /dev/null +++ b/tweepy/logging.py @@ -0,0 +1,58 @@ +# Tweepy +# Copyright 2009 Joshua Roesslein +# See LICENSE + +class TweepyLogger(object): + + DEBUG = 1 + WARNING = 2 + ERROR = 3 + + def debug(self, message): + """Output a debug log message""" + self.log(TweepyLogger.DEBUG, message) + + def warning(self, message): + """Output warning log message""" + self.log(TweepyLogger.WARNING, message) + + def error(self, message): + """Output error log message""" + self.log(TweepyLogger.ERROR, message) + + def log(self, level, message): + """Implement this method to handle log messages""" + raise NotImplementedError + + def format(self, message): + """Override this method to apply custom formating of messages""" + return message + +class DummyLogger(TweepyLogger): + """This logger just discards log messages""" + + def log(self, level, message): + return + +class ConsoleLogger(TweepyLogger): + """Outputs log messages to stdout""" + + def __init__(self, active_log_level=TweepyLogger.DEBUG): + self.active_log_level = active_log_level + + def log(self, level, message): + if level <= self.active_log_level: + print message + +class FileLogger(TweepyLogger): + """Outputs log message to file""" + + def __init__(self, filepath, active_log_level=TweepyLogger.DEBUG): + self.active_log_level = active_log_level + self.file = open(filepath, 'w') + + def log(self, level, message): + if level <= self.active_log_level: + self.file.write(message + '\n') + self.file.flush() + -- 2.25.1