Commits

Alexander Lyabah  committed 7772250

first not sorted

  • Participants

Comments (0)

Files changed (26)

+syntax: glob
+*.pyc
+log.csv
+main
+for writing csv logs in Django. And for tracking and user reporting unhandled exception

File __init__.py

Empty file added.

File djucsvlog/DjLogger.py

+from ucsvlog.Logger import Logger as OriginalLogger
+from ucsvlog.utils import unicoder
+import settings as my_settings
+from django.conf import settings
+from djucsvlog.fields import request as request_fields
+from djucsvlog.fields import response as response_fields
+from djucsvlog.fields import exception_info as exception_fields
+
+if my_settings.PRINT:
+    class Logger(OriginalLogger):
+        def store_row(self,data):
+            print ",".join(map(unicoder,data))
+else:
+    Logger = OriginalLogger
+
+
+class DjLogger(Logger):
+    def_req_log = None #fields, which will be logged in request
+    def_res_log = None #fields, which will be logged in response
+    def __init__(self):
+        self.def_req_log = self.iget_def_req_log() 
+        self.def_res_log = self.iget_def_res_log()
+        super(DjLogger,self).__init__(
+                    self.iget_action_log(),
+                    self.iget_level(),
+                    self.iget_default(),
+                    self.iget_loglev(),
+                    self.iget_func_fields()
+                )
+        self.mid_log,self.mid_a_log,self.mid_c_log = self.get_trio_log(my_settings.MIDDLEWARE_LOG_NAME)
+            
+    def iget_def_req_log(self):
+        return self.arr_lambda_by_name(my_settings.REQUEST_FIELDS,request_fields)
+    def iget_def_res_log(self):
+        return self.arr_lambda_by_name(my_settings.RESPONSE_FIELDS,response_fields)
+    def iget_count_log_fields(self):
+        return my_settings.COUNT_FIELDS or (max(len(self.def_req_log),len(self.def_res_log))+2)
+    def iget_level(self):
+        return my_settings.LOG_NAMES
+    def iget_loglev(self):
+        return my_settings.LOG_NAMES_AV
+    def iget_action_log(self):
+        return settings.UCSVLOG_FILE
+    def iget_default(self):
+        return my_settings.LOG_DEF
+    def iget_func_fields(self):
+        return my_settings.LOG_BASE
+    def iget_exception_vars_max_length(self):
+        return my_settings.EXCEPTION_VARS_MAX_LENGTH
+    
+    
+    def process_request(self,request):
+        self.mid_a_log('REQ',self.arr_funcs(self.def_req_log,request))
+    def process_response(self,request,response):
+        self.mid_c_log('REQ',self.arr_funcs(self.def_res_log,request,response))
+    def process_exception(self,exception,exR,close_name='REQ'):
+        #save head exception information
+        def_exc_log = self.arr_lambda_by_name(my_settings.EXCEPTION_FIELDS,exception_fields)
+        self.err(['TOP']+self.arr_funcs(def_exc_log,exception))
+        
+        #save frames info
+        def_exc_log = self.arr_lambda_by_name(my_settings.EXCEPTION_STACK_FIELDS,exception_fields)
+        frames = exR.get_traceback_frames()
+        frames.reverse()
+        for frame in frames:
+            self.err(['MIDDLE']+self.arr_funcs(def_exc_log,frame,exR))
+        
+        #save close info
+        def_exc_log = self.arr_lambda_by_name(my_settings.EXCEPTION_CLOSE,exception_fields)
+        self.mid_c_log(close_name,self.arr_funcs(def_exc_log,exception,exR))
+
+        
+if my_settings.THREAD_LOCALS:
+    try:
+        from threading import local
+    except ImportError:
+        from django.utils._threading_local import local
+    
+    _thread_locals = local()
+    _thread_locals.aindex_stack = []
+    _thread_locals.aindex = ''
+    
+    def set_aindex(self,val):
+        _thread_locals.aindex = val
+    def get_aindex(self):
+        return _thread_locals.aindex
+    def get_aindex_stack(self):
+        return _thread_locals.aindex_stack
+    
+    DjLogger.set_aindex = set_aindex
+    DjLogger.get_aindex = get_aindex
+    DjLogger.get_aindex_stack = get_aindex_stack
+    

File djucsvlog/__init__.py

+__all__ = ['glog']
+from djucsvlog.middleware import glog

File djucsvlog/components/__init__.py

Empty file added.

File djucsvlog/components/sql.py

+from django.db.backends import util
+from djucsvlog.middleware import glog
+import time
+
+class DatabaseStatTracker(util.CursorDebugWrapper):
+    def execute(self, sql, params=()):
+        start = time.time()
+        try:
+            return self.cursor.execute(sql, params)
+        finally:
+            stop = time.time()
+            glog.dbg(['__SQL__',stop-start,sql,unicode(params)])
+            #print stop-start,sql
+util.CursorDebugWrapper = DatabaseStatTracker

File djucsvlog/fields/__init__.py

+import request
+import response

File djucsvlog/fields/exception_info.py

+from ucsvlog.utils import unicoder 
+
+def estr(exception):
+    return unicoder(exception)
+
+def etype(exception):
+    return unicoder(type(exception))
+
+def sfunction(frame,exR):
+    return unicoder(frame['function'])
+
+def sfilename(frame,exR):
+    return frame['filename']
+
+def slineno(frame,exR):
+    return unicoder(frame['lineno'])
+
+def scontext_line(frame,exR):
+    return frame['context_line']
+
+def unicoder_truncate(var,length):
+    
+    value = unicoder(var)
+    if len(value)>length:
+        return value[0:length]+'...'
+    return value
+
+def svars(frame,exR):
+    from djucsvlog.middleware import glog
+    vars = frame['vars']
+    ret = ''
+    for v in vars:
+        ret += ' - %s:%s\n' %(v[0],unicoder_truncate(v[1],glog.iget_exception_vars_max_length()))
+    return ret
+
+def emeta(exception,exR):
+    return 'meta'

File djucsvlog/fields/request.py

+
+def readable_dict(dd):
+    ret = ''
+    for kd,vd in dd.items():
+        ret += ' - %s:%s\n' %(unicode(kd),vd)
+    return ret
+
+def path(request):
+    return request.path
+
+def language_code(request):
+    return getattr(request,'LANGUAGE_CODE','')
+
+def get(request):
+    return readable_dict(request.GET) 
+
+def post(request):
+    return readable_dict(request.POST)
+
+def files(request):
+    ret = ''
+    for field,file in request.FILES.items():
+        ret += ' - %s %s %s %s\n' %(field,file.name,file.content_type,file.size)
+    return ret
+
+def cookies(request):
+    return readable_dict(request.COOKIES)
+
+def request_form_data(request):
+    ret = ''
+    r_get = get(request)
+    if r_get:
+        ret+=' -- GET --\n'+r_get
+    
+    r_post = post(request)
+    if r_post:
+        ret+=' -- POST --\n'+r_post
+    
+    r_files = files(request)
+    if r_files:
+        ret+=' -- FILES --\n'+r_files
+        
+    return ret
+
+def request_data(request):
+    ret = request_form_data(request)
+    
+    r_cookies = cookies(request)
+    if r_cookies:
+        ret+=' -- COOKIES --\n'+r_cookies
+    
+    return ret
+
+def userid(request):
+    return (request.user.id or '0')
+
+def sessionid(request):
+    if hasattr(request, 'session'):
+        return request.session._session_key
+    return ''
+
+def remote_addr(request):
+    return request.META.get('REMOTE_ADDR','ANONYMOUS')
+
+def http_user_agent(request):
+    meta = request.META
+    ret =  meta.get('HTTP_USER_AGENT','NO USER AGENT')
+    if 'HTTP_ACCEPT_LANGUAGE' in meta:
+        ret+= ' Accept Language:'+meta['HTTP_ACCEPT_LANGUAGE']
+    if 'HTTP_ACCEPT_ENCODING' in meta:
+        ret += ' Accept Encoding:'+meta['HTTP_ACCEPT_ENCODING']
+    return ret

File djucsvlog/fields/response.py

+#response.status_code,response._headers['content-type'][1]
+from djucsvlog import settings
+
+def status(request,response):
+    return response.status_code
+def ctype(request,response):
+    return response._headers['content-type'][1]
+def content(request,response):
+    return response._headers['content-type'][1].lower() in settings.RESPONSE_CONTENT_LOG_TYPES and response.content or ''

File djucsvlog/middleware.py

+import sys
+
+from django.views.debug import ExceptionReporter
+from django.http import Http404
+from django.db import transaction
+
+import settings as my_settings
+from ucsvlog.utils import import_name
+Logger = import_name(my_settings.CLASS)
+glog = Logger()
+
+for mod in my_settings.COMPONENTS:
+    try:
+        __import__(mod, {}, {}, [''])
+    except ImportError,e:
+        raise e
+
+class LogRequestInfo(object):
+    def process_request(self,request):
+        glog.process_request(request)
+    def process_response(self,request,response):
+        glog.process_response(request, response)
+        return response
+    def process_exception(self, request, exception):
+        if exception.__class__ == Http404:
+            return
+        exR = ExceptionReporter(request,*sys.exc_info())
+        try:
+            transaction.rollback()
+        except transaction.TransactionManagementError:
+            pass
+        glog.process_exception(exception,exR)

File djucsvlog/settings.py

+from django.conf import settings
+set_prefix = 'UCSVLOG_' 
+def get(key, default):
+    globals()[key] = getattr(settings, set_prefix+key, default)
+get('MIDDLEWARE_LOG_NAME','log')
+get('REQUEST_FIELDS',['sessionid','userid','remote_addr','path','request_form_data','http_user_agent']) # request logged fields
+get('RESPONSE_FIELDS',['ctype','content']) #response logged fields
+get('RESPONSE_CONTENT_LOG_TYPES',['text/json','text/xml','application/json','application/xml'])
+get('EXCEPTION_FIELDS',['estr','etype'])
+get('EXCEPTION_STACK_FIELDS',['sfunction','sfilename','slineno','svars'])
+get('EXCEPTION_VARS_MAX_LENGTH',100)
+get('EXCEPTION_CLOSE',['emeta'])
+get('COUNT_FIELDS',0) #max count fields in log
+get('LOG_NAMES',['err','imp','inf','log','trc','dbg']) #name of logs, wich will be logged
+get('LOG_NAMES_AV',['err','imp','inf','log','trc','dbg']) # all names of logs, wich already using in code
+get('LOG_DEF','log') #default log name, wich will be called when loggaer used without attributes
+get('COMPONENTS',())
+get('FLUSH_ALL',True)
+get('LOG_BASE',['stacksize','filename','lineno','fname']) # list of fields, which will be show in every log line
+get('USER_REPORT',True)
+get('MAIL_ADMINS',True)
+get('CLASS','djucsvlog.DjLogger.DjLogger')
+get('PRINT',False)
+get('THREAD_LOCALS',False)
+__all__ = ['glog']
+from djucsvlog import glog
+#!/usr/bin/env python
+from django.core.management import execute_manager
+try:
+    import settings # Assumed to be in the same directory.
+except ImportError:
+    import sys
+    sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
+    sys.exit(1)
+
+if __name__ == "__main__":
+    execute_manager(settings)

File myapp/__init__.py

Empty file added.

File myapp/management/__init__.py

Empty file added.

File myapp/management/commands/__init__.py

Empty file added.

File myapp/management/commands/test_exception_command.py

+from django.core.management.base import NoArgsCommand
+from csvlog.management.base import LoggedHandle
+from csvlog import glog
+
+
+class Command(LoggedHandle,NoArgsCommand):
+    def logged_handle(self,*args,**kwargs):
+        glog.imp('Test')
+        raise ValueError('Ig')

File myapp/management/commands/test_logged_command.py

+from django.core.management.base import NoArgsCommand
+from csvlog.management.base import LoggedHandle
+from csvlog import glog
+
+
+class Command(LoggedHandle,NoArgsCommand):
+    def logged_handle(self,*args,**kwargs):
+        glog.imp('Test')

File myapp/models.py

Empty file added.

File myapp/urls.py

Empty file added.

File myapp/views.py

Empty file added.
+# Django settings for django_pay project.
+
+#### THIS BLOCK IS NOT CONTAINED IN BASE settings.py #####
+
+import os.path
+import sys
+PROJECT_ROOT = sys.path[0]
+at_project_root = lambda name: os.path.join(PROJECT_ROOT, name)
+
+#### END OF THIS BLOCK
+# All added rows, which needs for running csvlog are marks "##ADD"
+# All optional setting, wich have default value in file csvlog/settings.py, are marks "##ADD OPTIONAL"
+# and all information about optional setting you can find in ucsvlog/settings.py 
+
+UCSVLOG_FILE = 'log.ucsv'
+UCSVLOG_LOG_NAMES = ['err','imp','inf','dbg','log'] ##ADD OPTIONAL
+UCSVLOG_REQUEST_FIELDS = ['path','language_code','request_form_data','userid','sessionid','remote_addr','http_user_agent']
+UCSVLOG_COMPONENTS = (
+            'djucsvlog.components.sql',
+    )
+UCSVLOG_PRINT = True
+#CSVLOG_OFF = True
+
+DEBUG = True
+TEMPLATE_DEBUG = DEBUG
+
+ADMINS = (
+    # ('Your Name', 'your_email@domain.com'),
+)
+
+MANAGERS = ADMINS
+
+DATABASE_ENGINE = 'sqlite3'           # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
+DATABASE_NAME = 'main'             # Or path to database file if using sqlite3.
+DATABASE_USER = ''             # Not used with sqlite3.
+DATABASE_PASSWORD = ''         # Not used with sqlite3.
+DATABASE_HOST = ''             # Set to empty string for localhost. Not used with sqlite3.
+DATABASE_PORT = ''             # Set to empty string for default. Not used with sqlite3.
+
+# Local time zone for this installation. Choices can be found here:
+# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
+# although not all choices may be available on all operating systems.
+# If running in a Windows environment this must be set to the same as your
+# system time zone.
+TIME_ZONE = 'America/Chicago'
+
+# Language code for this installation. All choices can be found here:
+# http://www.i18nguy.com/unicode/language-identifiers.html
+LANGUAGE_CODE = 'en-us'
+
+SITE_ID = 1
+
+# If you set this to False, Django will make some optimizations so as not
+# to load the internationalization machinery.
+USE_I18N = True
+
+# Absolute path to the directory that holds media.
+# Example: "/home/media/media.lawrence.com/"
+MEDIA_ROOT = ''
+
+# URL that handles the media served from MEDIA_ROOT. Make sure to use a
+# trailing slash if there is a path component (optional in other cases).
+# Examples: "http://media.lawrence.com", "http://example.com/media/"
+MEDIA_URL = ''
+
+# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
+# trailing slash.
+# Examples: "http://foo.com/media/", "/media/".
+ADMIN_MEDIA_PREFIX = '/media/'
+
+# Make this unique, and don't share it with anybody.
+SECRET_KEY = '*1grhgp-)aru9!3(t-ynr_u(yea4me26)^nvb682-zp8!0)#m+'
+
+# List of callables that know how to import templates from various sources.
+TEMPLATE_LOADERS = (
+    'django.template.loaders.filesystem.load_template_source',
+    'django.template.loaders.app_directories.load_template_source',
+#     'django.template.loaders.eggs.load_template_source',
+)
+
+MIDDLEWARE_CLASSES = (
+    'django.middleware.common.CommonMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.middleware.locale.LocaleMiddleware', 
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'djucsvlog.middleware.LogRequestInfo', ##ADD (at the bottom of list)
+)
+
+ROOT_URLCONF = 'django-ucsvlog.urls'
+
+TEMPLATE_DIRS = (
+    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
+    # Always use forward slashes, even on Windows.
+    # Don't forget to use absolute paths, not relative paths.
+)
+
+INSTALLED_APPS = (
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.sites',
+    'myapp', ##for test
+)
+
+
+## AND need to add some changes to urls.py
+from django.conf.urls.defaults import *
+
+# Uncomment the next two lines to enable the admin:
+# from django.contrib import admin
+# admin.autodiscover()
+import views
+urlpatterns = patterns('',
+    ### this requests needs for demonstration of working
+    url(r'^somelog/$',views.somelog), ## how to use logging inside 
+    url(r'^sometreelog/$',views.sometreelog), ## how to use branched logging inside
+    url(r'^sqlselect/$',views.sqlselect), # how to log sql querys
+    url(r'^someerror/$',views.someerror), ## request by this url evokes unhandled exception
+    url(r'^files/$',views.files), ##check logging files
+    url(r'^json-data/$',views.json_data), ##check logging files
+    # Example:
+    # (r'^django_pay/', include('django_pay.foo.urls')),
+
+    # Uncomment the admin/doc line below and add 'django.contrib.admindocs' 
+    # to INSTALLED_APPS to enable admin documentation:
+    # (r'^admin/doc/', include('django.contrib.admindocs.urls')),
+
+    # Uncomment the next line to enable the admin:
+    # (r'^admin/', include(admin.site.urls)),
+)
+#!/usr/bin/python
+# coding: utf-8
+from django.http import HttpResponse
+from glog import glog
+from django.contrib.auth.models import User
+#finlog = glog.get_log_func('inf','fin')
+#fin_money_log  = glog.get_log_func('inf',['fin','money'])
+def somelog(request):
+    #use object of logger as a simple function, for shorter logging
+    glog('executin log by default name')
+    
+    #use different type of logs  
+    glog.err('ERR, some error hapend')
+    glog.imp('IMP, some important information')
+    glog.inf('INF, some information')
+    glog.log('LOG, some log')
+    glog.trc('TRC, some trace')
+    glog.dbg('DBG, debug information')
+    #use utf-8
+    glog.err(u'ERR, И чертовски важный русский текст')
+    
+    #use array for logging
+    glog.inf(['here is array','first','second','tred','log is full, this will be removed'])
+    
+    #use predefined function for logging at the top of the module
+    #finlog('And one my log')
+    #finlog(['two el','one','tree'])
+    #fin_money_log('get 100$')
+    #bad_line = u'Ну шо?'.encode('utf-8')
+    #glog.err(bad_line)
+    return HttpResponse('OK')
+
+def sometreelog(request):
+    #you can use logs as tree
+    
+    #log in the first level
+    glog.inf('inf in my tree')
+    glog.inf('inf in my tree too')
+    
+    # open new level - "ntr" branch
+    glog.alog('ntr',['New Tree NODE'])
+    
+    #log in the second level
+    glog.imp('write in this node')
+    glog.imp('and again')
+    
+    #close "ntr" branch
+    glog.clog('ntr',['AND CLOSE'])
+    
+    #log in the first branch
+    glog.inf('write in glob tree again')
+    return HttpResponse('OK')
+
+def json_data(request):
+    return HttpResponse("{'a':'newar'}",mimetype='application/json')
+
+def sqlselect(request):
+    u = User.objects.get(id=1)
+    return HttpResponse('OK')
+
+def someerror(request):
+    raise ValueError(u'Русская ошибка')
+    return HttpResponse("It's can be")
+
+def files(request):
+    if request.method == 'POST':
+        return HttpResponse('HI')
+    else:
+        return HttpResponse('''
+        <form action="." enctype="multipart/form-data" method="post">
+        <input type="file" name="file" />
+        <input type="submit">
+        </form>
+        ''')