1<?php
2/**
3 * Licensed to the Apache Software Foundation (ASF) under one or more
4 * contributor license agreements. See the NOTICE file distributed with
5 * this work for additional information regarding copyright ownership.
6 * The ASF licenses this file to You under the Apache License, Version 2.0
7 * (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 *
10 *	   http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * @package log4php
19 */
20
21/**
22 * Serialize events and send them to a network socket.
23 *
24 * This appender can be configured by changing the following attributes:
25 *
26 * - locationInfo       - Sets the location info for the xml layout (true or false)
27 * - log4jNamespace     - Sets the namespace for log4j (true or false)
28 * - port               - Sets the port of the socket.
29 * - remoteHost         - Sets the remote host
30 * - timeout            - Sets the timeout in ms
31 * - useXml             - true, if xml should be transmitted.
32 *                        false, if a serialized php object should be transmitted
33 *
34 * Parameters are {@link $remoteHost}, {@link $port}, {@link $timeout},
35 * {@link $locationInfo}, {@link $useXml} and {@link $log4jNamespace}.
36 *
37 * An example:
38 *
39 * {@example ../../examples/php/appender_socket.php 19}
40 *
41 * {@example ../../examples/resources/appender_socket.properties 18}
42 *
43 * @version $Revision: 883108 $
44 * @package log4php
45 * @subpackage appenders
46 */
47class LoggerAppenderSocket extends LoggerAppender {
48
49	/**
50	 * @var mixed socket connection resource
51	 * @access private
52	 */
53	private $sp = false;
54
55	/**
56	 * Target host. On how to define remote hostaname see
57	 * {@link PHP_MANUAL#fsockopen}
58	 * @var string
59	 */
60	private $remoteHost = '';
61
62	/**
63	 * @var integer the network port.
64	 */
65	private $port = 4446;
66
67	/**
68	 * @var boolean get event's location info.
69	 */
70	private $locationInfo = false;
71
72	/**
73	 * @var integer connection timeout
74	 */
75	private $timeout = 30;
76
77	/**
78	 * @var boolean output events via {@link LoggerXmlLayout}
79	 */
80	private $useXml = false;
81
82	/**
83	 * @var boolean forward this option to {@link LoggerXmlLayout}.
84	 *				Ignored if {@link $useXml} is <i>false</i>.
85	 */
86	private $log4jNamespace = false;
87
88	/**
89	 * @var LoggerXmlLayout
90	 * @access private
91	 */
92	private $xmlLayout = null;
93
94	/** @var indiciates if this appender should run in dry mode */
95	private $dry = false;
96
97	public function __destruct() {
98       $this->close();
99   	}
100
101	/**
102	 * Create a socket connection using defined parameters
103	 */
104	public function activateOptions() {
105		if(!$this->dry) {
106			$this->sp = @fsockopen($this->getRemoteHost(), $this->getPort(), $errno, $errstr, $this->getTimeout());
107			if ($this->sp === false) {
108			    throw new LoggerException("Could not open socket to ".$this->getRemoteHost().":".$this->getPort().": $errstr ($errno)");
109			}
110		}
111		if($this->getUseXml()) {
112			$this->xmlLayout = LoggerReflectionUtils::createObject('LoggerLayoutXml');
113			if($this->xmlLayout === null) {
114				$this->setUseXml(false);
115			} else {
116				$this->xmlLayout->setLocationInfo($this->getLocationInfo());
117				$this->xmlLayout->setLog4jNamespace($this->getLog4jNamespace());
118				$this->xmlLayout->activateOptions();
119			}
120		}
121        $this->closed = false;
122	}
123
124	public function close() {
125		if($this->closed != true) {
126			if(!$this->dry and $this->sp !== false) {
127				fclose($this->sp);
128			}
129			$this->closed = true;
130		}
131	}
132
133	public function setDry($dry) {
134		$this->dry = $dry;
135	}
136
137	/**
138	 * @return string
139	 */
140	public function getHostname() {
141		return $this->getRemoteHost();
142	}
143
144	/**
145	 * @return boolean
146	 */
147	public function getLocationInfo() {
148		return $this->locationInfo;
149	}
150
151	/**
152	 * @return boolean
153	 */
154	public function getLog4jNamespace() {
155		return $this->log4jNamespace;
156	}
157
158	/**
159	 * @return integer
160	 */
161	public function getPort() {
162		return $this->port;
163	}
164
165	public function getRemoteHost() {
166		return $this->remoteHost;
167	}
168
169	/**
170	 * @return integer
171	 */
172	public function getTimeout() {
173		return $this->timeout;
174	}
175
176	/**
177	 * @var boolean
178	 */
179	public function getUseXml() {
180		return $this->useXml;
181	}
182
183	public function reset() {
184		$this->close();
185		parent::reset();
186	}
187
188	/**
189	 * @param mixed
190	 */
191	public function setLocationInfo($flag) {
192		$this->locationInfo = LoggerOptionConverter::toBoolean($flag, $this->getLocationInfo());
193	}
194
195	/**
196	 * @param mixed
197	 */
198	public function setLog4jNamespace($flag) {
199		$this->log4jNamespace = LoggerOptionConverter::toBoolean($flag, $this->getLog4jNamespace());
200	}
201
202	/**
203	 * @param integer
204	 */
205	public function setPort($port) {
206		$port = LoggerOptionConverter::toInt($port, 0);
207		if($port > 0 and $port < 65535) {
208			$this->port = $port;
209		}
210	}
211
212	/**
213	 * @param string
214	 */
215	public function setRemoteHost($hostname) {
216		$this->remoteHost = $hostname;
217	}
218
219	/**
220	 * @param integer
221	 */
222	public function setTimeout($timeout) {
223		$this->timeout = LoggerOptionConverter::toInt($timeout, $this->getTimeout());
224	}
225
226	/**
227	 * @param mixed
228	 */
229	public function setUseXml($flag) {
230		$this->useXml = LoggerOptionConverter::toBoolean($flag, $this->getUseXml());
231	}
232
233	public function append(LoggerLoggingEvent $event) {
234		if($this->sp || $this->dry) {
235			if($this->getLocationInfo()) {
236				$event->getLocationInformation();
237			}
238
239			if(!$this->getUseXml()) {
240				$sEvent = serialize($event);
241				if(!$this->dry) {
242					fwrite($this->sp, $sEvent, strlen($sEvent));
243				} else {
244				    echo "DRY MODE OF SOCKET APPENDER: ".$sEvent;
245				}
246			} else {
247				if(!$this->dry) {
248					fwrite($this->sp, $this->xmlLayout->format($event));
249				} else {
250				    echo "DRY MODE OF SOCKET APPENDER: ".$this->xmlLayout->format($event);
251				}
252			}
253
254			// not sure about it...
255			if(!$this->dry) {
256				fflush($this->sp);
257			}
258		}
259	}
260}
261