877df953fc15dac106f3cb2c81d66cacd9484b53
[platform/framework/web/crosswalk.git] / src / native_client / build / log_tools.py
1 #!/usr/bin/python
2 # Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """Logging related tools."""
7
8 import logging
9 import os
10 import subprocess
11 import sys
12
13 # Module-level configuration
14 LOG_FH = None
15 VERBOSE = False
16
17 def SetupLogging(verbose, file_handle=None):
18   """Set up python logging.
19
20   Args:
21     verbose: If True, log to stderr at DEBUG level and write subprocess output
22              to stdout. Otherwise log to stderr at INFO level and do not print
23              subprocess output unless there is an error.
24     file_handle: If not None, must be a file-like object. All log output will
25                  be written at DEBUG level, and all subprocess output will be
26                  written, regardless of whether there are errors.
27   """
28   # Since one of our handlers always wants debug, set the global level to debug.
29   logging.getLogger().setLevel(logging.DEBUG)
30   stderr_handler = logging.StreamHandler()
31   stderr_handler.setFormatter(
32       logging.Formatter(fmt='%(levelname)s: %(message)s'))
33   if verbose:
34     global VERBOSE
35     VERBOSE = True
36     stderr_handler.setLevel(logging.DEBUG)
37   else:
38     stderr_handler.setLevel(logging.INFO)
39   logging.getLogger().addHandler(stderr_handler)
40
41   if file_handle:
42     global LOG_FH
43     file_handler = logging.StreamHandler(file_handle)
44     file_handler.setLevel(logging.DEBUG)
45     file_handler.setFormatter(
46         logging.Formatter(fmt='%(levelname)s: %(message)s'))
47     logging.getLogger().addHandler(file_handler)
48     LOG_FH = file_handle
49
50
51 def WriteToLog(text):
52   if VERBOSE:
53     sys.stdout.write(text)
54   if LOG_FH:
55     LOG_FH.write(text)
56
57
58 def CheckCall(command, stdout=None, **kwargs):
59   """Modulate command output level based on logging level.
60
61   If a logging file handle is set, always emit all output to it.
62   If the log level is set at debug or lower, also emit all output to stdout.
63   Otherwise, only emit output on error.
64   Args:
65     command: Command to run.
66     stdout (optional): File name to redirect stdout to.
67     **kwargs: Keyword args.
68   """
69   cwd = os.path.abspath(kwargs.get('cwd', os.getcwd()))
70   logging.info('Running: subprocess.check_call(%r, cwd=%r)' % (command, cwd))
71
72   if stdout is None:
73     # Interleave stdout and stderr together and log that.
74     p = subprocess.Popen(command,
75                          stdout=subprocess.PIPE,
76                          stderr=subprocess.STDOUT,
77                          **kwargs)
78     output = p.stdout
79   else:
80     p = subprocess.Popen(command,
81                          stdout=open(stdout, 'w'),
82                          stderr=subprocess.PIPE,
83                          **kwargs)
84     output = p.stderr
85
86   # Capture the output as it comes and emit it immediately.
87   line = output.readline()
88   while line:
89     WriteToLog(line)
90     line = output.readline()
91
92   if p.wait() != 0:
93     raise subprocess.CalledProcessError(cmd=command, returncode=p.returncode)
94
95   # Flush stdout so it does not get interleaved with future log or buildbot
96   # output which goes to stderr.
97   sys.stdout.flush()
98
99
100 def CheckOutput(command, **kwargs):
101   """Capture stdout from a command, while logging its stderr.
102
103   This is essentially subprocess.check_output, but stderr is
104   handled the same way as in log_tools.CheckCall.
105   Args:
106     command: Command to run.
107     **kwargs: Keyword args.
108   """
109   cwd = os.path.abspath(kwargs.get('cwd', os.getcwd()))
110   logging.info('Running: subprocess.check_output(%r, cwd=%r)' % (command, cwd))
111
112   p = subprocess.Popen(command,
113                        stdout=subprocess.PIPE,
114                        stderr=subprocess.PIPE,
115                        **kwargs)
116
117   # Assume the output will not be huge or take a long time to come, so it
118   # is viable to just consume it all synchronously before logging anything.
119   # TODO(mcgrathr): Shovel stderr bits asynchronously if that ever seems
120   # worth the hair.
121   stdout_text, stderr_text = p.communicate()
122
123   WriteToLog(stderr_text)
124
125   if p.wait() != 0:
126     raise subprocess.CalledProcessError(cmd=command, returncode=p.returncode)
127
128   # Flush stdout so it does not get interleaved with future log or buildbot
129   # output which goes to stderr.
130   sys.stdout.flush()
131
132   logging.info('Result: %r' % stdout_text)
133   return stdout_text