Using Different Loggers In Phing

Tuesday, November 17, 2009 - 21:26

When you run a phing script it will print things out to the console. These messages are either system messages (eg. BUILD STARTED) or echo messages that you have put into your build.xml file. All of this output is controlled and created by a logger file. The default logger is called (unsuprsingly) DefaultLogger and will be used as a default. There are a few different types of logger available, all of which can be found in the listener folder in your PEAR\phing directory.

To select a different logger script to be used just use the -logger flag in your phing call. To specify the DefaultLogger use the following:

phing -logger phing.listener.DefaultLogger

To specify an XML logger that will create an XML document of the phing events that occurred in the current working directory use the XmlLogger logger.

phing -logger phing.listener.XmlLogger

So what happens if we want to print out only the echo messages in our build file? There isn't a logger we can use to do this so the solution it to simply make our own. The following code block contains a logger that will only print out echo commands along with any errors that occurred and the time taken for the build to complete. Create a file called EchoLogger.php and put it into the PEAR\phing\listener directory. Many of the comments in this file are from DefaultLogger, I have just changed the parts that were different or not applicable.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
<?php
require_once 'phing/BuildListener.php';
include_once 'phing/BuildEvent.php';
 
/**
 *  Writes all echo messages generated during a build event to the console.
 *
 *  This is the only output generated by the logger with two exceptions. These
 *  are the total time taken for the build to run and any errors that occurred
 *  during the build.
 *
 *  @author    Philip Norton
 *  @see       BuildEvent
 *  @package   phing.listener
 */
class EchoLogger implements BuildListener {
 
    /**
     *  Size of the left column in output. The default char width is 12.
     *  @var int
     */
    const LEFT_COLUMN_SIZE = 12;
 
    /**
     *  The message output level that should be used. The default is
     *  <code>PROJECT_MSG_VERBOSE</code>.
     *  @var int
     */
    protected $msgOutputLevel = PROJECT_MSG_ERR;
 
    /**
     *  Time that the build started
     *  @var int
     */
    protected $startTime;
 
    /**
     *  Char that should be used to seperate lines. Default is the system
     *  property <em>line.seperator</em>.
     *  @var string
     */
    protected $lSep;
 
    /**
     *  Construct a new default logger.
     */
    public function __construct() {
        $this->lSep = Phing::getProperty("line.separator");
    }
 
    /**
     *  Set the msgOutputLevel this logger is to respond to.
     *
     *  Only messages with a message level lower than or equal to the given
     *  level are output to the log.
     *
     *  <p> Constants for the message levels are in Project.php. The order of
     *  the levels, from least to most verbose, is:
     *
     *  <ul>
     *    <li>PROJECT_MSG_ERR</li>
     *    <li>PROJECT_MSG_WARN</li>
     *    <li>PROJECT_MSG_INFO</li>
     *    <li>PROJECT_MSG_VERBOSE</li>
     *    <li>PROJECT_MSG_DEBUG</li>
     *  </ul>
     *
     *  The default message level for DefaultLogger is PROJECT_MSG_ERR.
     *
     *  @param  integer  the logging level for the logger.
     *  @access public
     */
    function setMessageOutputLevel($level) {
        $this->msgOutputLevel = (int) $level;
    }
 
    /**
    *  Sets the start-time when the build started. Used for calculating
    *  the build-time.
    *
    *  @param  object  The BuildEvent
    *  @access public
    */
    function buildStarted(BuildEvent $event) {
        $this->startTime = Phing::currentTimeMillis();
    }
 
    /**
     *  Prints whether the build failed, and any errors that occured during 
     the build. Also outputs the total build-time on completion.
     *
     *  @param  object  The BuildEvent
     *  @access public
     *  @see    BuildEvent::getException()
     */
    function buildFinished(BuildEvent $event) {
        $error = $event->getException();
        if ($error !== null) {
            print($this->lSep . "BUILD FAILED" . $this->lSep);
            if (PROJECT_MSG_VERBOSE <= $this->msgOutputLevel || !($error instanceof BuildException)) {
                print($error->__toString().$this->lSep);
            } else {
                print($error->getMessage());
            }
        }
        print($this->lSep . "Total time: " .$this->_formatTime(Phing::currentTimeMillis() - $this->startTime) . $this->lSep);
    }
 
    /**
     *  Fired when a target has started. We don't need specific action on this
     *  event. So the methods are empty.
     *
     *  @param  object  The BuildEvent
     *  @access public
     *  @see    BuildEvent::getTarget()
     */
    function targetStarted(BuildEvent $event) {}
 
    /**
     *  Fired when a target has finished. We don't need specific action on this
     *  event. So the methods are empty.
     *
     *  @param  object  The BuildEvent
     *  @access public
     *  @see    BuildEvent::getException()
     */
    function targetFinished(BuildEvent $event) {}
 
    /**
     *  Fired when a task is started. We don't need specific action on this
     *  event. So the methods are empty.
     *
     *  @param  object  The BuildEvent
     *  @access public
     *  @see    BuildEvent::getTask()
     */
    function taskStarted(BuildEvent $event) {}
 
    /**
     *  Fired when a task has finished. We don't need specific action on this
     *  event. So the methods are empty.
     *
     *  @param  object  The BuildEvent
     *  @access public
     *  @see    BuildEvent::getException()
     */
    function taskFinished(BuildEvent $event) {}
 
    /**
     *  Print any echo messages to the stdout.
     *
     *  @param  object  The BuildEvent
     *  @access public
     *  @see    BuildEvent::getMessage()
     */
    function messageLogged(BuildEvent $event) {
        if ($event->getPriority() <= $this->msgOutputLevel) {
            $msg = "";
            if ($event->getTask() !== null) {
                $name = $event->getTask();
                $name = $name->getTaskName();
                if ($name == 'echo') {
                    $msg = "[$name] ";
                    $msg .= $event->getMessage();
                    $this->printMessage($msg, $event->getPriority());                    
                }
            }
        }
    }
 
    /**
     *  Formats a time micro integer to human readable format.
     *
     *  @param  integer The time stamp
     *  @access private
     */
    function _formatTime($micros) {
        $seconds = $micros;
        $minutes = $seconds / 60;
        if ($minutes > 1) {
            return sprintf("%1.0f minute%s %0.2f second%s",
                                    $minutes, ($minutes === 1 ? " " : "s "),
                                    $seconds - floor($seconds/60) * 60, ($seconds%60 === 1 ? "" : "s"));
        } else {
            return sprintf("%0.4f second%s", $seconds, ($seconds%60 === 1 ? "" : "s"));
        }
    }
    
    /**
     * Prints a message to console.
     * 
     * @param string $message  The message to print. 
     *                 Should not be <code>null</code>.
     * @param int $priority The priority of the message. 
     *                 (Ignored in this implementation.)
     * @return void
     */
    protected function printMessage($message, $priority) {
        print($message . $this->lSep);
    }    
}

You can now call your new logger by using the following command.

phing -logger phing.listener.EchoLogger

Only echo commands will be printed out, along with the time the script took to run. If any errors are encountered these will be printed in the normal way.

Category: 
philipnorton42's picture

Philip Norton

Phil is the founder and administrator of #! code and is an IT professional working in the North West of the UK.
Google+ | Twitter

Add new comment