a/Allura/allura/lib/utils.py b/Allura/allura/lib/utils.py
1
import time
1
import time
2
import string
2
import string
3
import hashlib
3
import hashlib
4
import binascii
4
import binascii
5
import logging
5
import logging.handlers
6
import codecs
7
import os.path
8
import datetime
6
import random
9
import random
7
import mimetypes
10
import mimetypes
8
from itertools import groupby
11
from itertools import groupby
9
from logging.handlers import WatchedFileHandler
10
12
11
import tg
13
import tg
12
import pylons
14
import pylons
13
import webob.multidict
15
import webob.multidict
14
from formencode import Invalid
16
from formencode import Invalid
...
...
100
102
101
    def __getattr__(self, name):
103
    def __getattr__(self, name):
102
        if name.startswith('_'): raise AttributeError, name
104
        if name.startswith('_'): raise AttributeError, name
103
        return getattr(self._logger, name)
105
        return getattr(self._logger, name)
104
106
107
class TimedRotatingHandler(logging.handlers.BaseRotatingHandler):
108
109
    def __init__(self, strftime_pattern):
110
        self.pattern = strftime_pattern
111
        self.last_filename = self.current_filename()
112
        logging.handlers.BaseRotatingHandler.__init__(self, self.last_filename, 'a')
113
114
    def current_filename(self):
115
        return os.path.abspath(datetime.datetime.utcnow().strftime(self.pattern))
116
117
    def shouldRollover(self, record):
118
        'Inherited from BaseRotatingFileHandler'
119
        return self.current_filename() != self.last_filename
120
121
    def doRollover(self):
122
        self.stream.close()
123
        self.baseFilename = self.current_filename()
124
        if self.encoding:
125
            self.stream = codecs.open(self.baseFilename, 'w', self.encoding)
126
        else:
127
            self.stream = open(self.baseFilename, 'w')
128
105
class StatsHandler(WatchedFileHandler):
129
class StatsHandler(TimedRotatingHandler):
106
    fields=('action', 'action_type', 'tool_type', 'tool_mount', 'project', 'neighborhood',
130
    fields=('action', 'action_type', 'tool_type', 'tool_mount', 'project', 'neighborhood',
107
            'username', 'url', 'ip_address')
131
            'username', 'url', 'ip_address')
108
132
109
    def __init__(self,
133
    def __init__(self,
110
                 strftime_pattern,
134
                 strftime_pattern,
111
                 module='allura',
135
                 module='allura',
112
                 page=1,
136
                 page=1,
113
                 **kwargs):
137
                 **kwargs):
114
        self.page = page
138
        self.page = page
115
        self.module = module
139
        self.module = module
116
        WatchedFileHandler.__init__(self, strftime_pattern)
140
        TimedRotatingHandler.__init__(self, strftime_pattern)
117
141
118
    def emit(self, record):
142
    def emit(self, record):
119
        if not hasattr(record, 'action'):
143
        if not hasattr(record, 'action'):
120
            return
144
            return
121
        kwpairs = dict(
145
        kwpairs = dict(
...
...
126
        kwpairs.update(getattr(record, 'kwpairs', {}))
150
        kwpairs.update(getattr(record, 'kwpairs', {}))
127
        record.kwpairs = ','.join(
151
        record.kwpairs = ','.join(
128
            '%s=%s' % (k,v) for k,v in sorted(kwpairs.iteritems())
152
            '%s=%s' % (k,v) for k,v in sorted(kwpairs.iteritems())
129
            if v is not None)
153
            if v is not None)
130
        record.exc_info = None # Never put tracebacks in the rtstats log
154
        record.exc_info = None # Never put tracebacks in the rtstats log
131
        WatchedFileHandler.emit(self, record)
155
        TimedRotatingHandler.emit(self, record)
132
156
133
def chunked_find(cls, query=None, pagesize=1024):
157
def chunked_find(cls, query=None, pagesize=1024):
134
    if query is None: query = {}
158
    if query is None: query = {}
135
    page = 0
159
    page = 0
136
    while True:
160
    while True: