1111import os
1212import re
1313import subprocess
14+ import time
1415
1516from celery .canvas import group
1617from django .conf import settings
@@ -162,6 +163,19 @@ def __str__(self):
162163 def url (self ):
163164 return self .id + '.' + self .cluster .domain
164165
166+ def log (self , message ):
167+ """Logs a message to the application's log file.
168+
169+ This is a workaround for how Django interacts with Python's logging module. Each app
170+ needs its own FileHandler instance so it can write to its own log file. That won't work in
171+ Django's case because logging is set up before you run the server and it disables all
172+ existing logging configurations.
173+ """
174+ with open (os .path .join (settings .DEIS_LOG_DIR , self .id + '.log' ), 'a' ) as f :
175+ f .write ('{} deis[api]: {}\n ' .format (
176+ time .strftime ('%Y-%m-%d %H:%M:%S' ),
177+ message ))
178+
165179 def create (self , * args , ** kwargs ):
166180 config = Config .objects .create (owner = self .owner , app = self )
167181 build = Build .objects .create (owner = self .owner , app = self , image = settings .DEFAULT_BUILD )
@@ -209,7 +223,7 @@ def scale(self, **kwargs): # noqa
209223 if container_type not in available_process_types :
210224 raise EnvironmentError (
211225 'Container type {} does not exist in application' .format (container_type ))
212- msg = 'Containers scaled ' + ' ' .join (
226+ msg = 'containers scaled ' + ' ' .join (
213227 "{}={}" .format (k , v ) for k , v in requested_containers .items ())
214228 # iterate and scale by container type (web, worker, etc)
215229 changed = False
@@ -245,6 +259,7 @@ def scale(self, **kwargs): # noqa
245259 subtasks .append (tasks .stop_containers .s (to_remove ))
246260 group (* subtasks ).apply_async ().join ()
247261 log_event (self , msg )
262+ self .log (msg )
248263 return changed
249264
250265 def logs (self ):
@@ -258,7 +273,9 @@ def logs(self):
258273 def run (self , command ):
259274 """Run a one-off command in an ephemeral app container."""
260275 # TODO: add support for interactive shell
261- log_event (self , "deis run '{}'" .format (command ))
276+ msg = "deis run '{}'" .format (command )
277+ log_event (self , msg )
278+ self .log (msg )
262279 c_num = max ([c .num for c in self .container_set .filter (type = 'admin' )] or [0 ]) + 1
263280 c = Container .objects .create (owner = self .owner ,
264281 app = self ,
@@ -654,28 +671,36 @@ def __str__(self):
654671def _log_build_created (** kwargs ):
655672 if kwargs .get ('created' ):
656673 build = kwargs ['instance' ]
657- log_event (build .app , "Build {} created" .format (build ))
674+ log_event (build .app , "build {} created" .format (build ))
658675
659676
660677def _log_release_created (** kwargs ):
661678 if kwargs .get ('created' ):
662679 release = kwargs ['instance' ]
663- log_event (release .app , "Release {} created" .format (release ))
680+ log_event (release .app , "release {} created" .format (release ))
681+ # append release lifecycle logs to the app
682+ release .app .log (release .summary )
664683
665684
666685def _log_config_updated (** kwargs ):
667686 config = kwargs ['instance' ]
668- log_event (config .app , "Config {} updated" .format (config ))
687+ log_event (config .app , "config {} updated" .format (config ))
669688
670689
671690def _log_domain_added (** kwargs ):
672691 domain = kwargs ['instance' ]
673- log_event (domain .app , "Domain {} added" .format (domain ))
692+ msg = "domain {} added" .format (domain )
693+ log_event (domain .app , msg )
694+ # adding a domain does not create a release, so we have to log here
695+ domain .app .log (msg )
674696
675697
676698def _log_domain_removed (** kwargs ):
677699 domain = kwargs ['instance' ]
678- log_event (domain .app , "Domain {} removed" .format (domain ))
700+ msg = "domain {} removed" .format (domain )
701+ log_event (domain .app , msg )
702+ # adding a domain does not create a release, so we have to log here
703+ domain .app .log (msg )
679704
680705
681706def _etcd_publish_key (** kwargs ):
0 commit comments