Revision 75ec29e4

b/snf-django-lib/snf_django/management/commands/__init__.py
31 31
# interpreted as representing official policies, either expressed
32 32
# or implied, of GRNET S.A.
33 33

  
34
import os
35
import datetime
36
import logging
34 37
from optparse import (make_option, OptionParser, OptionGroup,
35 38
                      TitledHelpFormatter)
36 39

  
......
45 48
USER_EMAIL_FIELD = "user.email"
46 49

  
47 50

  
51
class SynnefoOutputWrapper(object):
52
    """Wrapper around stdout/stderr
53

  
54
    This class replaces Django's 'OutputWrapper' which doesn't handle
55
    logging to file.
56

  
57
    Since 'BaseCommand' doesn't initialize the 'stdout' and 'stderr'
58
    attributes at '__init__' but sets them only when it needs to,
59
    this class has to be a descriptor.
60

  
61
    We will use the old 'OutputWrapper' class for print to the screen and
62
    a logger for logging to the file.
63

  
64
    """
65
    def __init__(self):
66
        self.django_wrapper = None
67
        self.logger = None
68

  
69
    def __set__(self, obj, value):
70
        self.django_wrapper = value
71

  
72
    def __getattr__(self, name):
73
        return getattr(self.django_wrapper, name)
74

  
75
    def init_argv(self, argv):
76
        """Initialize this class using the command line
77

  
78
        Takes the command arguments, generate the filename where
79
        we are going to log, initialize our logger and return the
80
        generated filename.
81

  
82
        """
83
        curr_time = datetime.datetime.now()
84
        curr_time = datetime.datetime.strftime(curr_time, "%y%m%d%H%M%S")
85
        command = argv[1]
86
        pid = os.getpid()
87
        basename = "%s_%s_%s.log" % (curr_time, command, pid)
88
        filename = os.path.join("/var/log/synnefo/", basename)
89
        self.init_file(filename)
90
        self.logger.info(" ".join(map(str, argv)) + "\n\n")
91
        return filename
92

  
93
    def init_file(self, filename):
94
        """Create a logger for the filename"""
95

  
96
        basename = os.path.splitext(os.path.basename(filename))[0]
97
        self.logger = logging.getLogger(basename)
98
        self.logger.setLevel(logging.DEBUG)
99
        self.logger.propagate = False
100

  
101
        if not self.logger.handlers:
102
            handler = logging.FileHandler(filename)
103
            self.logger.addHandler(handler)
104
            # Also set all other logger to log to this file
105
            logging.getLogger().addHandler(handler)
106

  
107
    def write(self, msg, *args, **kwargs):
108
        if self.logger is not None:
109
            self.logger.info(msg)
110
        if self.django_wrapper is not None:
111
            self.django_wrapper.write(msg, *args, **kwargs)
112

  
113

  
48 114
class SynnefoCommandFormatter(TitledHelpFormatter):
49 115
    def format_heading(self, heading):
50 116
        if heading == "Options":
......
64 130
                 "csv [comma-separated output]"),
65 131
    )
66 132

  
133
    stdout = SynnefoOutputWrapper()
134
    stderr = SynnefoOutputWrapper()
135

  
136
    def run_from_argv(self, argv):
137
        """Initialize 'SynnefoOutputWrapper' and call super
138

  
139
        The two wrappers have to write to the same filename, so we cannot
140
        initialze both of them (each will create a new filename).  Furthermore
141
        we cannot have only one wrapper (BaseCommand has both 'stdout' and
142
        'stderr'). So call 'init_argv' for the first wrapper and give the
143
        resulting filename to the second.
144

  
145
        XXX: Find a better way to do the above.
146

  
147
        """
148
        filename = self.stdout.init_argv(argv)
149
        self.stderr.init_file(filename)
150
        super(SynnefoCommand, self).run_from_argv(argv)
151

  
67 152
    def create_parser(self, prog_name, subcommand):
68 153
        parser = OptionParser(prog=prog_name, add_help_option=False,
69 154
                              formatter=SynnefoCommandFormatter())
......
295 380
                objects = objects.prefetch_related(*prefetch_related)
296 381
            objects = objects.filter(**self.filters)
297 382
            for key, value in self.excludes.iteritems():
298
                objects = objects.exclude(**{key:value})
383
                objects = objects.exclude(**{key: value})
299 384
        except FieldError as e:
300 385
            raise CommandError(e)
301 386
        except Exception as e:

Also available in: Unified diff