new log4j

This commit is contained in:
Alex Huang 2011-06-21 10:15:21 -07:00
parent 83ee4e653c
commit 22d5eac400
2558 changed files with 424484 additions and 22913 deletions

View File

@ -2,6 +2,7 @@
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
<throwableRenderer class="com.cloud.utils.log.CglibThrowableRenderer"/>
<!-- ================================= -->
<!-- Preserve messages in a local file -->
@ -10,7 +11,7 @@
<!-- A regular appender FIXME implement code that will close/reopen logs on SIGHUP by logrotate FIXME make the paths configurable using the build system -->
<appender name="FILE" class="org.apache.log4j.rolling.RollingFileAppender">
<param name="Append" value="true"/>
<param name="Threshold" value="DEBUG"/>
<param name="Threshold" value="TRACE"/>
<rollingPolicy class="org.apache.log4j.rolling.TimeBasedRollingPolicy">
<param name="FileNamePattern" value="@MSLOG@.%d{yyyy-MM-dd}.gz"/>
<param name="ActiveFileName" value="@MSLOG@"/>

2
deps/.classpath vendored
View File

@ -2,7 +2,6 @@
<classpath>
<classpathentry kind="src" path="XenServerJava"/>
<classpathentry exported="true" kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry exported="true" kind="lib" path="cloud-apache-log4j-extras-1.0.jar"/>
<classpathentry exported="true" kind="lib" path="cloud-axis.jar"/>
<classpathentry exported="true" kind="lib" path="cloud-backport-util-concurrent-3.0.jar"/>
<classpathentry exported="true" kind="lib" path="cloud-bcprov-jdk16-1.45.jar"/>
@ -34,5 +33,6 @@
<classpathentry exported="true" kind="lib" path="cloud-xstream-1.3.1.jar"/>
<classpathentry exported="true" kind="lib" path="jetty-6.1.26.jar"/>
<classpathentry exported="true" kind="lib" path="jetty-util-6.1.26.jar"/>
<classpathentry exported="true" kind="lib" path="cloud-log4j-extras.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

Binary file not shown.

BIN
deps/cloud-log4j-extras.jar vendored Normal file

Binary file not shown.

BIN
deps/cloud-log4j.jar vendored

Binary file not shown.

View File

@ -0,0 +1,118 @@
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
=============
Preparing log4j releases.
=============
This is a detailed instruction to reproduce the log4j distribution
either to verify that the release is reproducable or to prepare
a hot-fix.
Apache log4j 1.2.16 was prepared using Ubuntu 9.10.
Preparation of environment:
1. Install Sun Java 6:
$> sudo sed 's/restricted/restricted universe multiverse/' -i /etc/apt/sources.list
$> sudo apt-get update && sudo apt-get -y update
$> sudo apt-get install sun-java6-jdk
$> sudo update-java-alternatives -s java-6-sun
$> export JAVA_HOME=/usr/lib/jvm/java-6-sun
2. Install Maven 2, Subversion, mingw and xemacs21, openssh-server:
$> sudo apt-get install maven2 subversion mingw32 xemacs21 openssh-server
3. Copy Win32 version of jni_md.h for NTEventLogAppender.dll
c:\>cd "\Program Files\Java\jdk_1.6.0_16\include\win32
c:\>scp jni_md.h username@hostname:
$> export JNI_WIN32_INCLUDE_DIR=/home/username
4. Create a local ssh key with no passphrase to enable
"deployment" of site back to the local machine using scp.
$> ssh-keygen
$> cd ~/.ssh
$> cat id_rsa.pub >> authorized_keys
$> ssh localhost
$> exit
From a command prompt:
$ export SVN_EDITOR=xemacs
$ svn co https://svn.apache.org/repos/asf/logging/log4j/tags/v1_2_16
$ cd v1_2_16
$ mvn site assembly:assembly
If you intended to deploy jars to the repo or update the site,
you need to set up ssh to use private keys to access people.apache.org
and create or modify ~/.m2/settings.xml to specify user name and key location.
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
<servers>
<server>
<id>logging.repo</id>
<username>USERNAME for people.apache.org</username>
<privateKey>/home/username/.ssh/id_rsa</privateKey>
<passphrase></passphrase>
</server>
</servers>
</settings>
You should test your ssh connection to people.apache.org
and localhost before attempting a deployment like:
$ ssh -l USERNAME people.apache.org
$ ssh localhost
The release artifacts were originally built by:
$> svn co http://svn.apache.org/repos/asf/logging/log4j/trunk log4j
$> cd log4j
$> mvn package release:prepare
$> mvn release:perform
The release artifacts can be rebuilt by:
$ mvn release:perform -DconnectionUrl=scm:svn:https://svn.apache.org/repos/asf/logging/log4j/tags/v1_2_16
The website content will automatically be staged to the ASF SVN repo by "mvn site-deploy".
This phase checks out https://svn.apache.org/repos/asf/logging/site/trunk/docs/log4j/1.2
into target/site-deploy, copys the generated documentation to that directory using
scp to localhost and then commits the changed content. You will be prompted for an
SVN commit message using the configured SVN_EDITOR. A commit message must be entered or the
site commit will be aborted.
The staged content can be tested by opening
http://svn.apache.org/repos/asf/logging/site/trunk/docs/1.2/index.html,
however some links may be broken due to the staged location.
The staged version can be published to the main public site by executing
"svn update" in /www/logging.apache.org/log4j/1.2 on people.apache.org.

104
thirdparty/apache-log4j-1.2.16/INSTALL vendored Normal file
View File

@ -0,0 +1,104 @@
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
===========
Using log4j
===========
1) First untar or unzip the distribution file.
2) Assuming you chose to extract the distribution in to the
PATH_OF_YOUR_CHOICE, untarring the distribution file should create
a logging-log4j-VERSION directory, where VERSION is the log4j
version number, under PATH_OF_YOUR_CHOICE. We will refer to the
directory PATH_OF_YOUR_CHOICE/apache-log4j-VERSION/ as $LOG4J_HOME/.
3) Add $LOG4J_HOME/log4j-VERSION.jar to your CLASSPATH,
4) You can now test your installation by first compiling the following
simple program.
import org.apache.log4j.Logger;
import org.apache.log4j.BasicConfigurator;
public class Hello {
private static final Logger logger = Logger.getLogger(Hello.class);
public
static
void main(String argv[]) {
BasicConfigurator.configure();
logger.debug("Hello world.");
logger.info("What a beatiful day.");
}
}
After compilation, try it out by issuing the command
java Hello
You should see log statements appearing on the console.
5) Refer to the javadoc documentation and the user manual on how to
include log statements in your own code.
=========
JAR files
=========
The log4j distribution comes with one jar file: log4j-VERSION.jar
under the LOG4J_HOME directory.
This jar file contains all the class files of the log4j project,
except test cases and classes from the "examples" and
"org.apache.log4j.performance" packages.
==============
Building log4j
==============
log4j (as of 1.2.15) is built with Maven 2. To rebuild log4j,
place Maven 2 on the PATH and execute "mvn package". The resulting
jar will be placed in the target subdirectory.
If building with JDK 1.4, one dependency will need to be manually
installed since its license does not allow it to be placed in the
online maven repositories. If not already installed, a build attempt will
describe where to download and how to install the dependency. To
install the dependency:
Download JMX 1.2.1 from http://java.sun.com/products/JavaManagement/download.html.
$ jar xf jmx-1_2_1-ri.zip
$ mvn install:install-file -DgroupId=com.sun.jmx -DartifactId=jmxri \
-Dversion=1.2.1 -Dpackaging=jar -Dfile=jmx-1_2_1-bin/lib/jmxri.jar
The build script will attempt to build NTEventLogAppender.dll if
MinGW is available on the path. If the unit tests are run on Windows
without NTEventLogAppender.dll, many warnings of the missing DLL
will be generated. An installer for MinGW on Windows is
available for download at http://sourceforge.net/project/showfiles.php?group_id=2435.
MinGW is also available through the package managers of many Linux distributions.
In case of problems send an e-mail note to
log4j-user@logging.apache.org. Please do not directly e-mail any
log4j developers. The answer to your question might be useful to other
users. Moreover, there are many knowledgeable users on the log4j-user
mailing lists who can quickly answer your questions.

148
thirdparty/apache-log4j-1.2.16/KEYS vendored Normal file
View File

@ -0,0 +1,148 @@
This file contains the PGP&GPG keys of various Apache developers.
Please don't use them for email unless you have to. Their main
purpose is code signing.
Apache users: pgp < KEYS
Apache developers:
(pgpk -ll <your name> && pgpk -xa <your name>) >> this file.
or
(gpg --fingerprint --list-sigs <your name>
&& gpg --armor --export <your name>) >> this file.
Apache developers: please ensure that your key is also available via the
PGP keyservers (such as pgpkeys.mit.edu).
Type bits /keyID Date User ID
pub 1024D/0C7C4F05 2005/06/10 Mark Dwayne Womack <mwomack@apache.org>
Mark Dwayne Womack <markwomack@womacknet.com>
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: PGP Key Server 0.9.6
mQGiBEKqEj8RBADR8e9Xl0kFJqv8SspvDP8kUsivBxWVZz+HVKf0pL2wOie0LfsF
E0Y3dI7k0k8i8KXtWYmHY3dpJGLUaruqIRxPFen/No56Q7udlK5hj7vKEUb46krx
sLgik1s+WX8+61Yu5cLuGdqnfwRGuNV7uf3JF1Q78VXIyUlS4BFMXGtqjwCg//s6
1m7N3p8AtIgma+U13rEkq9cEAJ6l9eEPgOdRx53nKkCgkVpDxxhpbg90STQ1s94f
rZIc+y5LN7FEERiQSiXvuzCwxiritiv+03sqdjYicxYZux+aladi0mHDIdgZkrAP
MrRJ+8AKs7jv+WXcyaJcja8h3IZLShszgUM6uCW4Wr8mzZ+ns/65ihe4A/jS/Gu+
cD44A/9doNrvOnNXPD+N/R9ME3zS6FY8d5F6f8oxZOEsMll/AG1HhOR4yxOmZMOl
+ZTg9AacHWMtTkjbs6JkT6uA8+tU+txoYjofkaGcJgq/SQYen89ifXZXVkUMWjqL
ioUUKCsu4OQPnH5k3jCQp7DrkpDAgIBGZ5F3QGaYsrkVjxNoE7QnTWFyayBEd2F5
bmUgV29tYWNrIDxtd29tYWNrQGFwYWNoZS5vcmc+iEYEEBECAAYFAkKwy1kACgkQ
vhbJXS4RQyKOYQCfddSBIMCd3kaFPvL90/piH/QIdIgAnRwG83V+KMRltnPRclDH
IcTI5unMiQBOBBARAgAOBQJCqhI/BAsDAgECGQEACgkQErKHWAx8TwWGeACgnN9d
jKDT2mjBKnApaDkMzmAaMvMAoKEcdBBCx62RPNIEBnxZ6zAxH244tC1NYXJrIER3
YXluZSBXb21hY2sgPG1hcmt3b21hY2tAd29tYWNrbmV0LmNvbT6IRgQQEQIABgUC
QrDLXgAKCRC+FsldLhFDIgvLAJ9VsCFN6uBcObkb+UCN70ukHH5VWQCdEjPNvKCs
c4+FGbTTsEoabhoNhsuJAEsEEBECAAsFAkKqFqUECwMCAQAKCRASsodYDHxPBeU1
AKDUIGqVzFZDXgK8PcLW8OlL2dXRmgCgwwxRkgpzuKNMnkphSZNend3VdJa5Ag0E
QqoSPxAIAPZCV7cIfwgXcqK61qlC8wXo+VMROU+28W65Szgg2gGnVqMU6Y9AVfPQ
B8bLQ6mUrfdMZIZJ+AyDvWXpF9Sh01D49Vlf3HZSTz09jdvOmeFXklnN/biudE/F
/Ha8g8VHMGHOfMlm/xX5u/2RXscBqtNbno2gpXI61Brwv0YAWCvl9Ij9WE5J280g
tJ3kkQc2azNsOA1FHQ98iLMcfFstjvbzySPAQ/ClWxiNjrtVjLhdONM0/XwXV0Oj
HRhs3jMhLLUq/zzhsSlAGBGNfISnCnLWhsQDGcgHKXrKlQzZlp+r0ApQmwJG0wg9
ZqRdQZ+cfL2JSyIZJrqrol7DVekyCzsAAgIH/2A8l4YFI5dYs5ZV3OgspEh0Qa/N
qd/JiVWBdygI77zp9TEgUtFBPDItEjmJq8sgnao0Cd5d68l9c+PQJ1xr4fOpdug0
YmYUgIaKutha3SSNRbD+T0WYmtTO5A4wxbsF3hYU7fvBJrt8gnO4tx6KAn/O2rRk
wPfNTZ1EdnKttZDM2Mz4OiK0SsQ9mS7zP+HPx3kzdl1Oj0Vk2tUElD1R1hVjLa/o
v5YgJCrwSD7RfCZAOEoPxXXN6StCqW1zT6HgcSR0clM5BC+ZyBJzczzD9I5+TrlH
d3ISaCOuP5NeYQdTsQ446bjiNk7LT25gNHF6U6WjmLQ3lXCz4kNoBG6fiOKIRgQY
EQIABgUCQqoSPwAKCRASsodYDHxPBQ7wAKD4DO0Se4+SvSqUKDfxhI0lJTgK0gCg
0lICv0KXT6PKyTndK+lr6K2AL4o=
=GKga
-----END PGP PUBLIC KEY BLOCK-----
pub 1024D/2E114322 2005-06-11 [expires: 2010-06-10]
Key fingerprint = A1A2 B554 6D43 31B2 A41E 1C07 BE16 C95D 2E11 4322
uid Curt Arnold <carnold@apache.org>
sig 3 2E114322 2010-02-17 Curt Arnold <carnold@apache.org>
sub 2048g/209ECE57 2005-06-11 [expires: 2010-06-10]
sig 2E114322 2005-06-11 Curt Arnold <carnold@apache.org>
pub 4096R/70C9C3D0 2010-02-17 [expires: 2012-02-17]
Key fingerprint = 28F5 F554 39C7 1A8F 2B1E 58C4 D3EC 4990 70C9 C3D0
uid carnold@apache.org (CODE SIGNING KEY) <carnold@apache.org>
sig 3 70C9C3D0 2010-02-17 carnold@apache.org (CODE SIGNING KEY) <carnold@apache.org>
sig 2E114322 2010-02-17 Curt Arnold <carnold@apache.org>
sub 4096R/0E434FF3 2010-02-17 [expires: 2012-02-17]
sig 70C9C3D0 2010-02-17 carnold@apache.org (CODE SIGNING KEY) <carnold@apache.org>
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG/MacGPG2 v2.0.14 (Darwin)
mQGiBEKrSNQRBAC4J7udOBoC5+gVxBaPAbjXfnq12l5Pau1WD+UothePNGjI2hOp
+Rnzikk3ISgyrjiX3A8ScZYbu3iXvMpF4zknkGLdmerpf4Gz9xGeushwun+UFaFL
MX5u7LWJo9wDKzbcJJit1j/qGEg/HRp5fnVYCh0/l4dLansL60NhxtYdxwCguu2e
wZMZFroaiIXqnce7+cGDRq8D/2HgKGtEJHY3z8OtUqncWbW+RAQqdcT0Z+bMB8o6
0UCHxUoJrFS1lA62qU3kcZ8ACPoh9xDW4X47EgNPELX81alymTI5FdqiDK7RIwzE
JlOH/8JJgC6eSwiUXJ0cOJwpMonitcpMLouxuURuPSpfE5b1mQ1gFzN5MBL8xlZQ
8IO6A/9qWwyWyQBoJud0RDIsVRosdoSBZtw9PHsURgsqfNsS2NXTWK4HjxExw1KO
AXmRlALfrH8yAShy/AyiUrwlKHG2WPTe6Etygjlr4dIxqTiCOoi+qv+H8SXW4Qy3
SnyozJ2RlKoYG0oDTbVMsPhOFdytHjConDLL9vS14j4kN9zWB7QgQ3VydCBBcm5v
bGQgPGNhcm5vbGRAYXBhY2hlLm9yZz6IZwQTEQIAJwIbAwUJCWYBgAIeAQIXgAUC
S3t0VgULCQgHAwUVCgkICwUWAgMBAAAKCRC+FsldLhFDIrS6AJ92lpskwBHNNWLw
XsHLaFSGh9n9tACfT0dOv3wec7oM+lt2x81S0uqcbZq5Ag0EQqtJBRAIAN8maiGI
O44Sdc9Ep3CAm0aXDeR8IQ/F253WcMQtkFBjeHEDd6/+EFT52vswMI6ZJDVV/A7p
e4VMXAdNutFmUG2gy9OJOu8gMuO3jTCLxUXyQYNF/RasOAQJgc7q1N5QgKtXVH2I
nQ21vHvlHM1fVe4rYDPr4JL2lZHe0P8kTzeQ7jI5pQnfYRJmS8I5AMQYFOiM48Pd
7SbsWu/rym7ikcmKUe6ZE59hSioneVP31CDMNRxCAQJVS1mZxTozsAEoh+cvmRjO
D1Es0iXvu6Sfe8+sLRL+7CNUZgixE1UFbdnNxuZGlG9qs0LGP7hDWijT1/Y4SHz4
ovXxk0oocmFtiLcAAwcIAMbY7K99hLAFVaU2ukxCSp1TNPcD+IB3gtpRieKaZvBn
/LGeCO+fNAogkw537lmpLk4nI+JiP/xWohyJ9lyEpW7yD4c9AHKNjqvEWD5Bhpnw
4qKJohQSVQwEeJRsftY4D0jCP9xbgPiq5woBzHWNok3BVaHqLK0fd0/+KygnT+k6
cR22Mus9RsEisXk9Oj5lvC0miDOWof4vk2Ll8/H3xt4CXAr13n5Yj2632HolOHrF
UQXTgwc9v5CNIihOQMEiXFxHh743qbsUZktjxeYH7r8wSCV93/QQ4qELiWoUzndp
kCRTlEKenucAv6f5qqZqG7pVW8S48T99HwzwqgFX5VOITwQYEQIADwUCQqtJBQIb
DAUJCWYBgAAKCRC+FsldLhFDIjnoAJ9ECOIrTH3adnVLOkHZnewyp2ssxwCgtLjl
wZ7/4QtL3W5Id3nKxPFiI+eZAg0ES3tyxgEQAMiGGFkj5EOkQv6EYFtWvd65Y6yn
dpNIbOb/o9SszVu4kO1OHdemWg4OwXERb1+Ozl9NamOvW0ypH8qzFu4rhpoiUev0
DV93afBkhW6Mvd8D459okgnlfb/K7c3H72gHmuJKZkyNmLgyzX63BjgIbpjR83/N
RC578BjoJbYCe0bKR9bCE+MxxCQzUO+tcUrk8o00zEhqycmw1B7gFLWL5MAf50h8
37/gbCcv9Q902kYfqsd5I7wPj4SRPnowN8vPlNtiwqMDqCl5rUmCrulfvSoNaJ/1
bEu7L9+/ptontfnr3kMJksGsoPo+Cf8xkGZL1D+80TxrBRf4CILQRF8dm+K8+4ms
VMsPccCINw/AZh+GkIjJ+SfQpIE4Rx6OMd6JSmCuMnom4O8ZbJ9QYcuS1uf4r32M
C6MQZrENvEFj1MaSZoRPXNdI/vwCKE5Hc1enB7bEHD6yayE3SgIGYVC+YPJkh0Ch
fAANRSlw7arrL13UB6xwzAnzhIK7BzADsbGDMAMmIh+rvb6Xxb6iQCh/q7iGPpRz
AXkmusLsbk6hMP4d8W5puJQTdy7a4t2DIX//9LYpl+DeYCww9DbXTwIays/WLnpo
Jxj8R1G75gfUIC+kvFl+OiIOR7579yw5Ar35DmqG8RIwxW9cv+at3u63WhYwdhqB
4Dm5hujWYluYoAZvABEBAAG0OmNhcm5vbGRAYXBhY2hlLm9yZyAoQ09ERSBTSUdO
SU5HIEtFWSkgPGNhcm5vbGRAYXBhY2hlLm9yZz6JAjwEEwEKACYFAkt7csYCGwMF
CQPCZwAFCwkIBwMFFQoJCAsEFgIBAAIeAQIXgAAKCRDT7EmQcMnD0FNcD/oDWhmZ
sikg42VV4SnaaIGUgjHoNT5NKWHhgeEXWAu44Y1r9X0+a6/xvtr69MfbExn9CJWJ
6vuyY9bpLcNNB49NLxhKD/IEpAUdGYcGGn1+AkkX/Sa7Y2SE5F9snJ2aSn+BctdP
JNHgEQxWGXGHAFPEdw73RudqsDUvcIat+uU8H/ZdrXX1F2NiUp7rjHqYvizXgy5p
Es99n00gCiz3eKg2l816v1ClDRAufFDj/JHghL4Yx+wUJN0cFBOAZHzDZgtcSUuv
Jb2B2f31vjqJ5cGzSQ1KhRIqoIwUm+LYOtuCAbboW9P9GPbib6oavRXRbz/SAoIX
BbYGWnA4aYQGT1r/FrLHZOmY6kw2izOPryXXxu1qAblFDc1C6XNHtNWx3uuTE/TL
haePHai9N0rJLuJCwHSveY5Lc8LF6cE2sV+kFsyMUwzaxLHg4G2XpnVIx5mEM+Fr
Hb89t8rThdE2n+qwUgCzlYgNEjAb1wf/xqUwXL7r/3rwKYkamq7Y7ljY9BTRX6VY
XsDEiCPs2XSNQtZfTajkei/WN0/SJDQZfIbK9wPqQXTA4DxZ5qJaTa5hS/ueksYH
tCK6pH3L8ov92ZbDcfxwq3u9wGl3GT1abFIfyfX53FXaoCXSi+g7F+a3hv6nmy0E
1zT26YXh3xRIPJ2x8gGCATHsGHabfnrRespQeYhGBBARCgAGBQJLe3TDAAoJEL4W
yV0uEUMianUAn1+KjhbSeXIcMrxWK6WaCHojo0StAJ9GiDT+6t4AnRXCIJtob6uZ
tN17tLkCDQRLe3LGARAAq9WmSZRtHLuOG8gmYesNeyfPqTdOgak+dgT4nnMIMnlN
Y23k3oMIgSBeiYyFMDoTXPYsxVZW24mrMhi9D1XhsDygn534iD94ptrLpnDG+56z
0aHdGjS8eUhEK636uNLT47ZEm8997fWCiqQQzX7UP9ttP9DKLkseiZ97jtN5To+7
n5Kmog082k0208p2jJqVw9aqoeXh4520nRaqiD2QQg2onQLCAz7UH7RllVzhqH9Z
G3HcI0RXw3q6FP33XlGNQuxhV9IPna9/43TXHaOsstwtJjvOaPfzGDS7BAmIKZx6
rbL7VYcIheZ+qXuVoRrwb0facxJfkTcLUy8aRQappDxk9FpWByEK2hEsWiw+CkI6
maFoyCvC/io5L3ZwWL3C+7wMZ1Qi8DvT93NbLboxhW5XRZk9gb1vlJSalTMbGNUV
tOiV+SbwfkMQX1xOMFbDx2u5orcJ0h9/Ox1LJEuoTHx68nXLB1e9ioLfQPATM+70
JhXGAHmjp8rkY6Jdua0MbamQtUXfJAZv/pJrukWNWmT5UFYY0DNNcypfaqm0l4g9
ZFwwUaraWrMkcsrvmmZ+6JASSwA1a6RwXYLtsMLX0boaUKEvDPqnIbeF3jJnztLN
MDWsGeW2NXYfuIaHMTUM7oVGgpDP+TG1IlOQU0lrSbw4Sm3AlA25tOF3jgGZtaMA
EQEAAYkCJQQYAQoADwUCS3tyxgIbDAUJA8JnAAAKCRDT7EmQcMnD0MzLEACRQ6Em
nkRbNupza9airUj2vrXj4I5ZN9jvgnvZcBVSmbKDEZR0akHFXaEes4d9AVh95y91
HuOHiiJ1hUZ0TGlk52ML5FEE68dDxvORUven9DiUdTAgLBJ5rUvfzj3tf6R4BNmM
rzyEA0UCAthqTd1nCdjhwIT6z4BiEVGsBHVAN7mYl+blHqssvuRgNAWrdPFRGYJP
cXI7wQc051WCHWXzi6b4h7oiIwlfsx7818S7ITHGM1AxTFl5rIqs9K4oHFTbcg1g
sLbJFM0NJ4l1yQZG/9Vldo0RmDdMSc5KgwPa48nf8LHsL3qtcQuvy/b1CIhf8UqZ
OWabhVa25xQFTRPmN5ND6wAsvx/zYr0/NF7RfJ3gTn8jCif8LZLVtYYP8zj4TgIL
ZhP46YwxaLkyibh+7/R+obszGVt06yqefNYuzfAXpX+2/pDUVQ532AAVD5g4enX7
eAxMda//UAC+WxfCqE6c3CWhXlGaborCsP5auhBg0rbi3/dgPySwMugBfVksa16X
X6y36kjw1MRZuhJi4WQGRLX4yjd6sGnWDoY5c/4G89JZKzjWsuNrSJIZRWrzgn84
NLAXpK81RMPkWukePN4ZQ1WEi0IH6AbBBbmQhIRR1bnGR48ZXH+/piJTNi9yKOPi
wlp15dJcNo0puq0ZbuZjPboQjg8PQaGtlMVN6A==
=EKia
-----END PGP PUBLIC KEY BLOCK-----

5
thirdparty/apache-log4j-1.2.16/NOTICE vendored Normal file
View File

@ -0,0 +1,5 @@
Apache log4j
Copyright 2007 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,71 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
#
# Providing a build.properties file is no longer
# necessary for an Ant build as long as one Maven build
# has previously been performed.
#
# base location of support directories
#
lib.home.dir=/java
# The jaxp interface and a jaxp parser are required
# to build the DOMConfigurator.
#
# modern equivalent is xml-commons-apis.jar
#
jaxp.home=${lib.home.dir}/crimson-1.1.3
jaxp.jaxp.jar=${jaxp.home}/crimson.jar
# JavaMail API Required to build the SMTPAppender
javamail.jar=${lib.home.dir}/javamail-1.3.2/mail.jar
# and JavaBeans Activation Framework
# http://java.sun.com/products/javabeans/jaf/index.jsp
activation.jar=${lib.home.dir}/jaf-1.0.2/activation.jar
# JMS interfaces are required to be on the classpath
# in order to build the JMSAppender.
jms.jar=${lib.home.dir}/jms1.1/lib/jms.jar
# Required to build the org.apache.log4j.jmx package.
jmx.home.dir=${lib.home.dir}/jmx-1_2_1-bin
jmx.jar=${jmx.home.dir}/lib/jmxri.jar
jndi.jar=${lib.home.dir}/jndi-1_2_1/lib/jndi.jar
# Required to run Checkstyle. Available from http://checkstyle.sf.net
checkstyle.jar=${lib.home.dir}/checkstyle-2.2/checkstyle-all-2.2.jar
# Velocity's Anakia task is used in the generation of the documentation
# download from http://jakarta.apache.org
velocity.jar=${lib.home.dir}/velocity-1.4/velocity-dep-1.4.jar
# Velocity's Anakia task requires JDOM,
# but Velocity 1.4 is not compatible with JDOM 1.0, but beta 8 works okay
# download for http://www.jdom.org/dist/binary/archive
jdom.jar=${lib.home.dir}/jdom-b8/build/jdom.jar
#
# CLIRR binary compatibility checker
# http://clirr.sourceforge.net
clirr-core.jar=${lib.home.dir}/clirr-0.6/clirr-core-0.6.jar
# bcel 5.1 will throw NullPointerExceptions
bcel.jar=${lib.home.dir}/bcel-5.2/bcel-5.2.jar

804
thirdparty/apache-log4j-1.2.16/build.xml vendored Normal file
View File

@ -0,0 +1,804 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- This file is an ANT build script. ANT is a Java based build tool. -->
<!-- It is available from http://ant.apache.org -->
<project name="log4j" default="usage" basedir="." >
<!-- The build.properties file defines the path to local jar files -->
<property file="build.properties"/>
<!-- if a Maven build has been attempted,
the Maven repository can provide all the dependencies. -->
<property name="m2_repo" location="${user.home}/.m2/repository"/>
<property name="javamail.jar" location="${m2_repo}/javax/mail/mail/1.4/mail-1.4.jar"/>
<property name="geronimo-jms.jar"
value="${m2_repo}/org/apache/geronimo/specs/geronimo-jms_1.1_spec/1.0/geronimo-jms_1.1_spec-1.0.jar"/>
<available property="jms.jar" value="${geronimo-jms.jar}" file="${geronimo-jms.jar}"/>
<property name="jms.jar" location="${m2_repo}/javax/jms/jms/1.1/jms-1.1.jar"/>
<property name="jmx.jar" location="${m2_repo}/com/sun/jmx/jmxri/1.2.1/jmxri-1.2.1.jar"/>
<!-- Read the system environment variables and stores them in properties, -->
<!-- prefixed with "env". -->
<property environment="env"/>
<property name="version" value="1.2.15"/>
<!-- The base directory relative to which most targets are built -->
<property name="base" value="."/>
<property name="deprecation" value="on"/>
<!-- The directory where java source files are stored. -->
<property name="java.source.dir" value="src/main/java/"/>
<!-- The directory where resource files are stored. -->
<property name="resource.source.dir" value="src/main/resources/"/>
<!-- The directory where javadoc files are stored. -->
<property name="javadoc.source.dir" value="src/main/javadoc/"/>
<!-- The directory where the package-list file is found, ./ or -->
<!-- build/ -->
<property name="packaging.dir" value="build"/>
<!-- distribution directory -->
<property name="dist.dir" value="dist"/>
<!-- Destination for compiled files -->
<property name="javac.dest" value="${dist.dir}/classes"/>
<!-- Destination for generated jar files -->
<property name="jar.dest" value="${dist.dir}/lib"/>
<!-- The jar file that the jar task will generate -->
<property name="jar.filename" value="log4j-${version}.jar"/>
<property name="sources-jar.filename" value="log4j-${version}-sources.jar"/>
<!-- Destination for documentation files -->
<property name="docs.dest" value="./docs"/>
<!-- Source directory for xml docs -->
<property name="xdocs.src" value="./src/xdocs"/>
<!-- Destination for javadoc generated files -->
<property name="javadoc.dest" value="docs/api"/>
<!-- Icons source directory. -->
<property name="icons.source" value="icons"/>
<!-- The stem where most log4j source code is located. -->
<property name="stem" value="org/apache/log4j"/>
<!-- Some targets needs a more precise stem. -->
<property name="BSTEM" value="${java.source.dir}/${stem}"/>
<!-- Directory where release images go. -->
<property name="dist.images" value="${dist.dir}/images"/>
<!-- Directory for temporary files. -->
<property name="dist.tmp" value="${dist.dir}/tmp"/>
<property name="javac.source" value="1.2"/>
<property name="javac.target" value="1.1"/>
<!-- destination for generated documentation on Apache web host -->
<property name="apache.javadoc_dest" value="/www/logging.apache.org/log4j/docs"/>
<!-- Apache web host -->
<property name="apache.host" value="people.apache.org"/>
<!-- destination for Maven generated documentation -->
<property name="svnrepo.url" value="https://svn.apache.org/repos/asf"/>
<property name="svnsite.url" value="${svnrepo.url}/logging/site/trunk/docs/log4j/1.2"/>
<available property="svn-available" file="target/site-deploy/.svn"/>
<!-- Construct compile classpath -->
<path id="compile.classpath">
<pathelement location="${build.home}/classes"/>
<pathelement location="${javamail.jar}"/>
<pathelement location="${activation.jar}"/>
<pathelement location="${jaxp.jaxp.jar}"/>
<pathelement location="${jms.jar}"/>
<pathelement location="${jmx.jar}"/>
<pathelement location="${jndi.jar}"/>
<pathelement location="${javaee-api.jar}"/>
</path>
<!-- ================================================================= -->
<!-- Default target -->
<!-- ================================================================= -->
<target name="usage">
<echo>
These are the targets supported by this ANT build scpript:
build - compile all project files, if a certain library is missing,
then the compilation of its dependents are skipped.
javadoc - build project javadoc files
jar - build log4j-core and log4j jar files
dist - will create a complete distribution in dist/
Setting the env variable NO_JAVADOC will build the distribution
without running the javadoc target.
release - will create a complete distribution in dist/
using stricter settings for public distribution.
</echo>
</target>
<target name="jaxpCheck">
<available classname="javax.xml.parsers.DocumentBuilderFactory"
property="jaxp-present"/>
</target>
<target name="jaxp" depends="jaxpCheck" if="jaxp-present">
<echo message="JAXP present."/>
</target>
<target name="jmxCheck">
<condition property="jmx-present" value="true">
<and>
<available classname="javax.management.MBeanInfo"
classpath="${jmx.jar}"/>
<available classname="com.sun.jdmk.comm.HtmlAdaptorServer">
<classpath>
<pathelement location="${jmx.jar}"/>
<pathelement location="${javaee-api.jar}"/>
</classpath>
</available>
</and>
</condition>
</target>
<target name="jmx" depends="jmxCheck" if="jmx-present">
<echo message="JMX is present."/>
</target>
<target name="jmsCheck">
<available classname="javax.jms.Message" property="jms-present">
<classpath>
<pathelement location="${jms.jar}"/>
<pathelement location="${javaee-api.jar}"/>
</classpath>
</available>
</target>
<target name="jms" depends="jmsCheck" if="jms-present">
<echo message="JMS is present."/>
</target>
<target name="jndiCheck">
<available classname="javax.naming.Context" property="jndi-present"/>
</target>
<target name="jndi" depends="jndiCheck" if="jndi-present">
<echo message="JNDI is present."/>
</target>
<target name="javamailCheck">
<available classname="javax.mail.MessageAware" property="javamail-present">
<classpath>
<pathelement location="${javamail.jar}"/>
<pathelement location="${javaee-api.jar}"/>
</classpath>
</available>
</target>
<target name="javamail" depends="javamailCheck" if="javamail-present">
<echo message="JAVAMAIL is present."/>
</target>
<!-- ================================================================= -->
<!-- Initialize variables -->
<!-- NOTE: all directories are relative to jakarta-log4j/ -->
<!-- ================================================================= -->
<target name="init">
<tstamp />
<property name="javac.includeAntRuntime" value="true"/>
<property name="javac.includeJavaRuntime" value="false"/>
<property name="javac.fork" value="false"/>
</target>
<target name="build" depends="init, build.core, build.examples, build.xml,
build.javamail, build.jms, build.jmx"/>
<target name="build.core" depends="init">
<mkdir dir="${javac.dest}" />
<javac srcdir="${java.source.dir}"
destdir="${javac.dest}"
includes="${stem}/**/*.java,
${stem}/xml/XMLLayout.java"
excludes="misc/*, **/UnitTest*.java,
**/StressCategory.java,
**/doc-files/*,
${stem}/xml/**,
${stem}/test/serialization/**,
${stem}/net/SMTPAppender.java,
${stem}/net/JMS*.java,
${stem}/jmx/*.java,
${stem}/or/jms/*.java"
target="${javac.target}"
source="${javac.source}"
includeAntRuntime="${javac.includeAntRuntime}"
includeJavaRuntime="${javac.includeJavaRuntime}"
fork="${javac.fork}"
deprecation="${deprecation}"
debug="on">
<classpath refid="compile.classpath"/>
</javac>
<copy todir="${javac.dest}">
<fileset dir="${resource.source.dir}" includes="${stem}/lf5/**/*.properties"/>
<fileset dir="${resource.source.dir}" includes="${stem}/lf5/viewer/images/*"/>
</copy>
</target>
<target name="build.examples" depends="build.core">
<mkdir dir="${javac.dest}" />
<javac srcdir="${basedir}"
destdir="${javac.dest}"
includes="examples/**/*.java"
excludes="misc/*"
target="${javac.target}"
source="${javac.source}"
includeAntRuntime="${javac.includeAntRuntime}"
includeJavaRuntime="${javac.includeJavaRuntime}"
fork="${javac.fork}"
deprecation="${deprecation}"
debug="on">
<classpath>
<pathelement path="${classpath}"/>
<fileset file="${jaxp.jaxp.jar}"/>
</classpath>
</javac>
<rmic base="${javac.dest}" classname="examples.NumberCruncherServer"/>
<copy todir="${javac.dest}">
<fileset dir="." includes="examples/lf5/**/*.properties"/>
<fileset dir="." includes="examples/lf5/**/*.xml"/>
</copy>
</target>
<target name="build.xml" depends="init, jaxp" if="jaxp-present">
<javac srcdir="${java.source.dir}"
destdir="${javac.dest}"
includes="${stem}/xml/**/*.java"
excludes="${stem}/xml/examples/doc-files/**.java,
${stem}/xml/Transform.java"
target="${javac.target}"
source="${javac.source}"
includeAntRuntime="${javac.includeAntRuntime}"
includeJavaRuntime="${javac.includeJavaRuntime}"
fork="${javac.fork}"
deprecation="${deprecation}"
classpath="${classpath}">
<classpath refid="compile.classpath"/>
</javac>
<copy file="${resource.source.dir}/${stem}/xml/log4j.dtd" tofile="${javac.dest}/${stem}/xml/log4j.dtd" />
</target>
<target name="build.javamail" depends="init, javamail"
if="javamail-present">
<javac srcdir="${java.source.dir}"
destdir="${javac.dest}"
includes="${stem}/net/SMTPAppender.java"
target="${javac.target}"
source="${javac.source}"
includeAntRuntime="${javac.includeAntRuntime}"
includeJavaRuntime="${javac.includeJavaRuntime}"
fork="${javac.fork}"
deprecation="${deprecation}">
<classpath refid="compile.classpath"/>
</javac>
</target>
<target name="build.jms" depends="init, jms, jndi" if="jms-present">
<javac srcdir="${java.source.dir}"
destdir="${javac.dest}"
includes="${stem}/net/JMS*.java, ${stem}/or/jms/*.java"
target="${javac.target}"
source="${javac.source}"
includeAntRuntime="${javac.includeAntRuntime}"
includeJavaRuntime="${javac.includeJavaRuntime}"
fork="${javac.fork}"
deprecation="${deprecation}">
<classpath refid="compile.classpath"/>
</javac>
</target>
<target name="build.jmx" depends="init, jmx, jndi" if="jmx-present">
<javac srcdir="${java.source.dir}"
destdir="${javac.dest}"
includes="${stem}/jmx/*.java"
excludes="${stem}/jmx/T.java"
target="${javac.target}"
source="${javac.source}"
includeAntRuntime="${javac.includeAntRuntime}"
includeJavaRuntime="${javac.includeJavaRuntime}"
fork="${javac.fork}"
deprecation="${deprecation}">
<classpath refid="compile.classpath"/>
</javac>
</target>
<target name="build.nt" depends="log4j.jar" description="Build NTEventLogAppender.dll">
<mkdir dir="${dist.dir}/object"/>
<ant antfile="src/ntdll/build.xml">
<property name="target.dir" location="${dist.dir}/lib"/>
<property name="object.dir" location="${dist.dir}/object"/>
<property name="classes.dir" location="${javac.dest}" />
<property name="src.dir" location="src/ntdll" />
<property name="jni.include.dir" location="${java.home}/../include" />
</ant>
</target>
<!-- ================================================================= -->
<!-- Remove all generated (compiled) class files. -->
<!-- ================================================================= -->
<target name="clean" depends="init">
<delete dir="${dist.dir}/" />
</target>
<!-- ================================================================= -->
<!-- Runs checkstyle. Available from http://checkstyle.sf.net -->
<!-- ================================================================= -->
<target name="checkstyle" depends="init">
<taskdef resource="checkstyletask.properties"
classpath="${checkstyle.jar}"/>
<!-- by default checkstyle supports the Sun coding standard. -->
<checkstyle lcurlyMethod="nlow"
lcurlyOther="nlow"
lcurlyType="nlow"
maxMethodLen="500"
maxConstructorLen="500">
<fileset dir="src/java/org/apache/log4j/chainsaw" includes="**/*.java"/>
</checkstyle>
</target>
<!-- ================================================================= -->
<!-- Runs Chainsaw -->
<!-- ================================================================= -->
<target name="chainsaw" depends="build">
<!-- Need to fork to avoid problems -->
<java classname="org.apache.log4j.chainsaw.Main" fork="yes"
classpath="${javac.dest};${ant.home}/lib/crimson.jar">
</java>
</target>
<!-- ================================================================= -->
<!-- Remove the temporary manifest file, actual work is done in the -->
<!-- dependencies. -->
<!-- ================================================================= -->
<target name="jar" depends="log4j.jar, log4j-sources.jar">
</target>
<!-- ================================================================= -->
<!-- Create log4j.jar, excluding tests and other odds and ends. -->
<!-- ================================================================= -->
<target name="log4j.jar" depends="build">
<mkdir dir="${jar.dest}"/>
<delete>
<fileset dir="${jar.dest}">
<include name="${jar.filename}"/>
</fileset>
</delete>
<jar jarfile="${jar.dest}/${jar.filename}" basedir="${javac.dest}"
includes="${stem}/*.class,
${stem}/xml/log4j.dtd,
${stem}/config/*.class,
${stem}/helpers/*.class,
${stem}/spi/*.class,
${stem}/net/*.class,
${stem}/jdbc/*.class,
${stem}/varia/*.class,
${stem}/chainsaw/*.class,
${stem}/lf5/**/*.class,
${stem}/lf5/**/*.properties,
${stem}/lf5/**/*.gif,
${stem}/nt/*.class,
${stem}/xml/*.class,
${stem}/jmx/*.class,
${stem}/or/*.class,
${stem}/or/sax/*.class,
${stem}/or/jms/*.class,
${stem}/config/*.class"
excludes="**/UnitTest**">
<manifest>
<section name="org/apache/log4j">
<attribute name="Implementation-Title" value="log4j"/>
<attribute name="Implementation-Version" value="${version}"/>
<attribute name="Implementation-Vendor" value='"Apache Software Foundation"'/>
</section>
</manifest>
<metainf dir="." includes="NOTICE,LICENSE"/>
</jar>
</target>
<!-- ================================================================= -->
<!-- Create log4j-sources.jar -->
<!-- ================================================================= -->
<target name="log4j-sources.jar">
<mkdir dir="${jar.dest}"/>
<delete>
<fileset dir="${jar.dest}" includes="${sources-jar.filename}"/>
</delete>
<jar jarfile="${jar.dest}/${sources-jar.filename}" basedir="${java.source.dir}"
includes="**/*.java">
<manifest>
<section name="org/apache/log4j">
<attribute name="Implementation-Title" value="log4j"/>
<attribute name="Implementation-Version" value="${version}"/>
<attribute name="Implementation-Vendor" value='"Apache Software Foundation"'/>
</section>
</manifest>
<metainf dir="." includes="NOTICE,LICENSE"/>
</jar>
</target>
<!-- ================================================================= -->
<!-- This target builds the javadoc files. -->
<!-- ================================================================= -->
<target name="javadoc" depends="init" unless="env.NO_JAVADOC">
<mkdir dir="${javadoc.dest}" />
<javadoc sourcepath="${java.source.dir}"
destdir="${javadoc.dest}"
packagenames="org.apache.log4j,
org.apache.log4j.config,
org.apache.log4j.helpers,
org.apache.log4j.jmx,
org.apache.log4j.lf5,
org.apache.log4j.net,
org.apache.log4j.nt,
org.apache.log4j.or,
org.apache.log4j.jdbc,
org.apache.log4j.or.sax,
org.apache.log4j.or.jms,
org.apache.log4j.performance,
org.apache.log4j.spi,
org.apache.log4j.varia,
org.apache.log4j.chainsaw,
org.apache.log4j.xml,
org.apache.log4j.xml.examples"
version="true"
protected="true"
author="true"
use="true"
overview="${docs.dest}/overview.html"
doctitle="log4j version ${version}&lt;br&gt;API Specification"
windowtitle="Log4j Version ${version}"
header='&lt;b&gt;Log4j ${version}&lt;/b&gt;&lt;!-- Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the &apos;License&apos;); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an &apos;AS IS&apos; BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--&gt;'
bottom="Copyright 2000-2007 Apache Software Foundation.">
<link href="http://java.sun.com/j2se/1.3/docs/api/"/>
<link href="http://java.sun.com/j2ee/sdk_1.3/techdocs/api/"/>
<classpath refid="compile.classpath"/>
</javadoc>
<!-- Extra files referenced by JavaDocs -->
<copy todir="${javadoc.dest}">
<fileset dir="${javadoc.source.dir}"/>
</copy>
</target>
<!-- ================================================================= -->
<!-- Compare the current API with a previous release -->
<!-- ================================================================= -->
<target name="jdiff" description="Generate comparison to reference API">
<property name="reference-api.version" value="1.2.9"/>
<property name="reference-api.dir" location="${user.home}/logging-log4j-${reference-api.version}"/>
<property name="reference-api.source.dir" location="${user.home}/logging-log4j-${reference-api.version}/src/java"/>
<!-- Must be set to the root of where JDiff is installed. -->
<property name="JDIFF_HOME" value="${user.home}/jdiff"/>
<!-- Just one simple way to tell Ant about the JDiff task -->
<taskdef name="jdiff" classname="jdiff.JDiffAntTask"
classpath="${JDIFF_HOME}/lib/antjdiff.jar"/>
<jdiff verbose="on" destdir="build/jdiff">
<old name="Version ${reference-api.version}">
<dirset dir="${reference-api.source.dir}" includes="org/**"/>
</old>
<new name="Version ${version}">
<dirset dir="${java.source.dir}" includes="org/**" excludes="org/apache/log4j/test/**"/>
</new>
</jdiff>
</target>
<!-- ================================================================= -->
<!-- Compare the current API with a previous release -->
<!-- ================================================================= -->
<target name="clirr" depends="jar" description="Check binary compatibility with arbitrary release">
<property name="clirr.version" value="0.6"/>
<property name="clirr-core.jar" value="${m2_repo}/net/sf/clirr/clirr-core/${clirr.version}/clirr-core-${clirr.version}.jar"/>
<available property="clirr-core.jar-available" file="${clirr-core.jar}"/>
<fail unless="clirr-core.jar-available">clirr-core-${clirr.version}.jar not in maven repo. Run mvn clirr:check to download.</fail>
<property name="bcel.version" value="5.1"/>
<property name="bcel.jar" value="${m2_repo}/bcel/bcel/${bcel.version}/bcel-${bcel.version}.jar"/>
<available property="bcel.jar-available" file="${bcel.jar}"/>
<fail unless="bcel.jar-available">bcel-${bcel.version}.jar not in maven repo. Run mvn clirr:check to download.</fail>
<property name="reference.version" value="1.2.14"/>
<property name="reference.jar" value="${m2_repo}/log4j/log4j/${reference.version}/log4j-${reference.version}.jar"/>
<available property="reference.jar-available" file="${reference.jar}"/>
<fail unless="reference.jar-available">log4j-${reference.version}.jar not in maven repo. Run mvn clirr:check to download.</fail>
<taskdef resource="clirrtask.properties"
classpath="${clirr-core.jar};${bcel.jar}"/>
<delete dir="target/clirr"/>
<mkdir dir="target/clirr/orig"/>
<mkdir dir="target/clirr/new"/>
<copy todir="target/clirr/orig">
<fileset file="${jms.jar}"/>
<fileset file="${jmx.jar}"/>
<fileset file="${reference.jar}"/>
</copy>
<copy todir="target/clirr/new">
<fileset file="${jms.jar}"/>
<fileset file="${jmx.jar}"/>
<fileset dir="${jar.dest}" includes="${jar.filename}"/>
</copy>
<clirr failOnBinError="no" failOnSrcError="no">
<origfiles dir="target/clirr/orig" includes="*.jar"/>
<newfiles dir="target/clirr/new" includes="*.jar"/>
<formatter type="xml" outfile="target/clirr/compatibility.xml"/>
</clirr>
</target>
<!-- ============================================== -->
<!-- Build the site files using Maven -->
<!-- ============================================== -->
<target name="site">
<exec executable="mvn">
<arg value="site"/>
</exec>
</target>
<!-- ================================================================= -->
<!-- Build a complete distribution. Results go to ${dist.images} -->
<!-- ================================================================= -->
<target name="dist" depends="init, clean, javadoc, jar, site, build.nt">
<delete verbose="true">
<fileset dir=".">
<patternset>
<include name="**/*.bak"/>
<include name="${dist.dir}/velocity.log"/>
<include name="${BSTEM}/**/temp*"/>
<include name="${BSTEM}/performance/test"/>
<include name="${BSTEM}/test/current.*"/>
<include name="${BSTEM}/test/current.*"/>
<include name="${BSTEM}/examples/test"/>
<include name="${BSTEM}/test/logging.*"/>
<include name="${BSTEM}/test/log4j.properties"/>
<include name="{$BSTEM}/test/socket.lcf"/>
<include name="${BSTEM}/test/file"/>
<include name="${BSTEM}/test/output.*"/>
<include name="${BSTEM}/net/test/loop.log"/>
<include name="${BSTEM}/net/test/loop.log.1"/>
<include name="${jar.dest}/manifest.mf"/>
<include name="${javac.dest}/*.class"/>
</patternset>
</fileset>
</delete>
<mkdir dir="${dist.images}" />
<mkdir dir="${dist.tmp}/apache-log4j-${version}" />
<copy todir="${dist.tmp}/apache-log4j-${version}">
<fileset dir="${base}"
includes="src/main/java/**,
docs/**,
examples/**,
build/*,
build.xml,
build.properties.sample,
manifest.mf,
INSTALL,
LICENSE,
NOTICE,
${dist.dir}/lib/log4j-${version}.jar,
${dist.dir}/lib/NTEventLogAppender.dll,
${dist.dir}/classes/**,
contribs/**"
excludes="make/make.loc,
**/*.bak, **/goEnv.bat,
**/Makefile, **/goEnv.bat,
docs/pub-support/*,
${dist.dir}/classes/org/**,
src/main/java/org/apache/log4j/test/**/*,
**/.#*,
**/*.o, **/*.res, **/*.h, **/EventLogCategories.rc"/>
</copy>
<fixcrlf srcdir="${dist.tmp}/apache-log4j-${version}"
includes="build.sh" cr="remove"/>
<fixcrlf srcdir="${dist.tmp}/apache-log4j-${version}"
includes="build.bat" cr="add"/>
<chmod dir="${dist.tmp}/apache-log4j-${version}"
includes="build.sh" perm="+x"/>
<tar tarfile="${dist.images}/apache-log4j-${version}.tar.gz"
basedir="${dist.tmp}"
includes="apache-log4j-${version}/**"
compression="gzip" />
<zip zipfile="${dist.images}/apache-log4j-${version}.zip"
basedir="${dist.tmp}"
includes="apache-log4j-${version}/**" />
<delete dir="${dist.tmp}" />
</target>
<!-- ================================================================= -->
<!-- Build a complete distribution for release. -->
<!-- ================================================================= -->
<target name="release">
<property name="javac.includeAntRuntime" value="false"/>
<property name="javac.includeJavaRuntime" value="false"/>
<property name="javac.fork" value="true"/>
<property name="build.compiler" value="classic"/>
<antcall target="clean-site"/>
<antcall target="dist"/>
<!-- check that jar file is not missing
classes due to missing dependencies -->
<available property="jaxp-found"
classname="org.apache.log4j.xml.DOMConfigurator"
classpath="${jar.dest}/${jar.filename}"/>
<fail unless="jaxp-found" message="JAXP was not found."/>
<available property="jmx-found"
classname="org.apache.log4j.jmx.Agent"
classpath="${jar.dest}/${jar.filename}"/>
<fail unless="jmx-found" message="JMX was not found."/>
<available property="jms-found"
classname="org.apache.log4j.net.JMSAppender"
classpath="${jar.dest}/${jar.filename}"/>
<fail unless="jms-found" message="JMS or JNDI was not found."/>
<available property="javamail-found"
classname="org.apache.log4j.net.SMTPAppender"
classpath="${jar.dest}/${jar.filename}"/>
<fail unless="javamail-found" message="JAVAMAIL was not found."/>
<checksum forceOverwrite="yes" fileext=".md5">
<fileset dir="${dist.images}" includes="apache-log4j-${version}.tar.gz apache-log4j-${version}.zip"/>
</checksum>
<checksum forceOverwrite="yes" fileext=".sha1" algorithm="SHA">
<fileset dir="${dist.images}" includes="apache-log4j-${version}.tar.gz apache-log4j-${version}.zip"/>
</checksum>
<exec executable="gpg" dir="${dist.images}">
<arg value="--armor"/>
<arg value="--output"/>
<arg value="apache-log4j-${version}.tar.gz.asc"/>
<arg value="--detach-sig"/>
<arg value="apache-log4j-${version}.tar.gz"/>
</exec>
<exec executable="gpg" dir="${dist.images}">
<arg value="--armor"/>
<arg value="--output"/>
<arg value="apache-log4j-${version}.zip.asc"/>
<arg value="--detach-sig"/>
<arg value="apache-log4j-${version}.zip"/>
</exec>
</target>
<target name="fixcrlf" depends="init"
description="Fixes CR-LF and tabs in source files">
<fixcrlf srcDir="."
includes="**/*.java **/build.xml"
tab="remove"
tablength="3"/>
</target>
<target name="checkout-site" unless="svn-available">
<delete dir="target/site-deploy"/>
<exec executable="svn">
<arg value="co"/>
<arg value="${svnsite.url}"/>
<arg value="target/site-deploy"/>
</exec>
</target>
<target name="update-site" if="svn-available">
<exec executable="svn" dir="target/site-deploy" failonerror="true">
<arg value="update"/>
</exec>
</target>
<target name="post-site" depends="checkout-site, update-site"/>
<target name="mime=html">
<exec executable="svn">
<arg value="propset"/>
<arg value="svn:mime-type"/>
<arg value="text/html"/>
<arg value="${src.html}"/>
</exec>
</target>
<target name="mime=css">
<exec executable="svn">
<arg value="propset"/>
<arg value="svn:mime-type"/>
<arg value="text/css"/>
<arg value="${src.css}"/>
</exec>
</target>
<target name="site-deploy">
<!-- Add any new files (and generate innocuous warnings for the existing content) -->
<delete file="target/site-deploy/svn-commit.tmp~"/>
<exec executable="bash" dir="target/site-deploy" failonerror="true">
<arg line='-c "svn add --force *"'/>
</exec>
<taskdef name="foreach" classname="net.sf.antcontrib.logic.ForEach" />
<foreach target="mime=html" param="src.html">
<path>
<fileset dir="target/site-deploy" includes="**/*.html"/>
</path>
</foreach>
<foreach target="mime=css" param="src.css">
<path>
<fileset dir="target/site-deploy" includes="**/*.css"/>
</path>
</foreach>
<!-- requires that SVN_EDITOR, VISUAL or EDITOR being set to edit commit description -->
<exec executable="svn" dir="target/site-deploy" failonerror="true">
<arg value="commit"/>
</exec>
</target>
</project>

View File

@ -0,0 +1,116 @@
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
----------------------------------------------------------------------
WARNING: The contents of the contribs/ directory is not guaranteed to
work properly. Some files might not even compile.
----------------------------------------------------------------------
Each directory corresponds to the name of an author containing his/her
contributions.
EirikLygre/
==========
DailyFileAppender1.java
DailyFileAppender extends FileAppender to use filenames formatted with
date/time information. The filename is recomputed every day at midnight.
Note that the filename doesn't have to change every day, making it possible
to have logfiles which are per-week or per-month.
JamesHouse/
==========
LogTextPanel.java
LogTextPanelExample.java
TextPanelAppender.java
JimMoore/
========
LoggingOutputStream.java
Allows the user to divert System.out and System.err to log4j.
WARNING: Be sure to read the included e-mails to understand the dangers of
WARNING: redirecting the console to LoggingOutputStream.
LeosLiterak/
===========
TempFileAppender.java
TempFileAppender creates new unique file for each logging statement.
MarkDouglas/
===========
SocketNode2.java
SocketServer2.java
Small changes to SocketServer and SockerNode to allow the client machine name
to be displayed in the logging output. This is important for us as we are
using a single logging server with several clients.
KevinSteppe/
===========
JDBCAppender.java
JDBCTest.java
KitchingSimon/
=============
DatagramStringAppender.java
DatagramStringWriter.java
logconfig.xml
SingleLineTracerPrintWriter.java
udpserver.pl
A set of files that implement an Appender which sends messages to a
remote host/port via UDP (datagram). Message formatting is
performed at the at the client end, mainly so that:
(a) the UDP server application does not have to be in java
(b) non-java clients can send messages to the same UDP server.
ThomasFenner/
============
Yet one more JDBCAppender.
JDBCAppender.java
JDBCConnectionHandler.java
JDBCIDHandler.java
JDBCLogger.java
Log4JTest.java
code_example1.java
code_example2.java
configfile_example.txt
Volker Mentzner/
===============
HTTPRequestHandler.java
Log4jRequestHandler.java
PluggableHTTPServer.java
RootRequestHandler.java
UserDialogRequestHandler.java
Allows users to configure log4j at runtime using a web-browser.

View File

@ -0,0 +1,245 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.apache.log4j.helpers.CyclicBuffer;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.Layout;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.spi.LoggingEvent;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.JScrollPane;
import javax.swing.BoxLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Container;
/**
The AppenderTable illustrates one possible implementation of
an Table possibly containing a great many number of rows.
<p>In this particular example we use a fixed size buffer
(CyclicBuffer) although this data structure could be easily
replaced by dynamically growing one, such as a Vector. The required
properties of the data structure is 1) support for indexed element
access 2) support for the insertion of new elements at the end.
<p>Experimentation on my 1400Mhz AMD machine show that it takes
about 45 micro-seconds to insert an element in the table. This
number does not depend on the size of the buffer. It takes as much
(or as little) time to insert one million elements to a buffer of
size 10 as to a buffer of size 10'000. It takes about 4 seconds to
insert a total of 100'000 elements into the table.
<p>On windows NT the test will run about twice as fast if you give
the focus to the window that runs "java AppenderTable" and not the
window that contains the Swing JFrame. */
public class AppenderTable extends JTable {
static Logger logger = Logger.getLogger(AppenderTable.class);
static public void main(String[] args) {
if(args.length != 2) {
System.err.println(
"Usage: java AppenderTable bufferSize runLength\n"
+" where bufferSize is the size of the cyclic buffer in the TableModel\n"
+" and runLength is the total number of elements to add to the table in\n"
+" this test run.");
return;
}
JFrame frame = new JFrame("JTableAppennder test");
Container container = frame.getContentPane();
AppenderTable tableAppender = new AppenderTable();
int bufferSize = Integer.parseInt(args[0]);
AppenderTableModel model = new AppenderTableModel(bufferSize);
tableAppender.setModel(model);
int runLength = Integer.parseInt(args[1]);
JScrollPane sp = new JScrollPane(tableAppender);
sp.setPreferredSize(new Dimension(250, 80));
container.setLayout(new BoxLayout(container, BoxLayout.X_AXIS));
container.add(sp);
// The "ADD" button is intended for manual testing. It will
// add one new logging event to the table.
JButton button = new JButton("ADD");
container.add(button);
button.addActionListener(new JTableAddAction(tableAppender));
frame.setSize(new Dimension(500,300));
frame.setVisible(true);
long before = System.currentTimeMillis();
int i = 0;
while(i++ < runLength) {
LoggingEvent event = new LoggingEvent("x", logger, Level.ERROR,
"Message "+i, null);
tableAppender.doAppend(event);
}
long after = System.currentTimeMillis();
long totalTime = (after-before);
System.out.println("Total time :"+totalTime+ " milliseconds for "+
"runLength insertions.");
System.out.println("Average time per insertion :"
+(totalTime*1000/runLength)+ " micro-seconds.");
}
public
AppenderTable() {
this.setDefaultRenderer(Object.class, new Renderer());
}
/**
When asked to append we just insert directly into the model. In a
real appender we would use two buffers one for accumulating
events and another to accumalte events but after filtering. Only
the second buffer would be displayed in the table and made
visible to the user.*/
public
void doAppend(LoggingEvent event) {
((AppenderTableModel)getModel()).insert(event);
}
/**
The Renderer is required to display object in a friendlier from.
This particular renderer is just a JTextArea.
<p>The important point to note is that we only need *one*
renderer. */
class Renderer extends JTextArea implements TableCellRenderer {
PatternLayout layout;
public
Renderer() {
layout = new PatternLayout("%r %p %c [%t] - %m");
}
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
// If its a LoggingEvent than format it using our layout.
if(value instanceof LoggingEvent) {
LoggingEvent event = (LoggingEvent) value;
String str = layout.format(event);
setText(str);
} else {
setText(value.toString());
}
return this;
}
}
}
class AppenderTableModel extends AbstractTableModel {
CyclicBuffer cb;
AppenderTableModel(int size) {
cb = new CyclicBuffer(size);
}
/**
Insertion to the model always results in a fireTableDataChanged
method call. Suprisingly enough this has no crippling impact on
performance. */
public
void insert(LoggingEvent event) {
cb.add(event);
fireTableDataChanged();
}
/**
We assume only one column.
*/
public
int getColumnCount() {
return 1;
}
/**
The row count is given by the number of elements in the
buffer. This number is guaranteed to be between 0 and the buffer
size (inclusive). */
public int getRowCount() {
return cb.length();
}
/**
Get the value in a given row and column. We suppose that there is
only one colemn so we are only concerned with the row.
<p>Interesting enough this method returns an object. This leaves
the door open for a TableCellRenderer to render the object in
a variety of ways.
*/
public
Object getValueAt(int row, int col) {
return cb.get(row);
}
}
/**
The JTableAddAction is called when the user clicks on the "ADD"
button.
*/
class JTableAddAction implements ActionListener {
AppenderTable appenderTable;
Logger dummy = Logger.getLogger("x");
int counter = 0;
public
JTableAddAction(AppenderTable appenderTable) {
this.appenderTable = appenderTable;
}
public
void actionPerformed(ActionEvent e) {
counter++;
LoggingEvent event = new LoggingEvent("x", dummy, Level.DEBUG,
"Message "+counter, null);
appenderTable.doAppend(event);
}
}

View File

@ -0,0 +1,219 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.xml;
import org.apache.log4j.Category;
import org.apache.log4j.Layout;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.helpers.DateLayout;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.Attributes;
import org.xml.sax.XMLReader;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.helpers.XMLReaderFactory;
import org.xml.sax.SAXException;
import org.apache.xerces.parsers.SAXParser;
import org.apache.trax.Processor;
import org.apache.trax.TemplatesBuilder;
import org.apache.trax.Templates;
import org.apache.trax.Transformer;
import org.apache.trax.Result;
import org.apache.trax.ProcessorException;
import org.apache.trax.ProcessorFactoryException;
import org.apache.trax.TransformException;
import org.apache.serialize.SerializerFactory;
import org.apache.serialize.Serializer;
import org.apache.serialize.OutputFormat;
import org.xml.sax.helpers.AttributesImpl;
import java.io.FileOutputStream;
import java.io.IOException;
public class Transform {
public static void main(String[] args) throws Exception {
PropertyConfigurator.disableAll();
PropertyConfigurator.configure("x.lcf");
// I. Instantiate a stylesheet processor.
Processor processor = Processor.newInstance("xslt");
// II. Process the stylesheet. producing a Templates object.
// Get the XMLReader.
XMLReader reader = XMLReaderFactory.createXMLReader();
// Set the ContentHandler.
TemplatesBuilder templatesBuilder = processor.getTemplatesBuilder();
reader.setContentHandler(templatesBuilder);
// Set the ContentHandler to also function as a LexicalHandler, which
// includes "lexical" (e.g., comments and CDATA) events. The Xalan
// TemplatesBuilder -- org.apache.xalan.processor.StylesheetHandler -- is
// also a LexicalHandler).
if(templatesBuilder instanceof LexicalHandler) {
reader.setProperty("http://xml.org/sax/properties/lexical-handler",
templatesBuilder);
}
// Parse the stylesheet.
reader.parse(args[0]);
//Get the Templates object from the ContentHandler.
Templates templates = templatesBuilder.getTemplates();
// III. Use the Templates object to instantiate a Transformer.
Transformer transformer = templates.newTransformer();
// IV. Perform the transformation.
// Set up the ContentHandler for the output.
FileOutputStream fos = new FileOutputStream(args[2]);
Result result = new Result(fos);
Serializer serializer = SerializerFactory.getSerializer("xml");
serializer.setOutputStream(fos);
transformer.setContentHandler(serializer.asContentHandler());
// Set up the ContentHandler for the input.
org.xml.sax.ContentHandler chandler = transformer.getInputContentHandler();
DC dc = new DC(chandler);
reader.setContentHandler(dc);
if(chandler instanceof LexicalHandler) {
reader.setProperty("http://xml.org/sax/properties/lexical-handler",
chandler);
} else {
reader.setProperty("http://xml.org/sax/properties/lexical-handler",
null);
}
// Parse the XML input document. The input ContentHandler and
// output ContentHandler work in separate threads to optimize
// performance.
reader.parse(args[1]);
}
}
class DC implements ContentHandler {
static Category cat = Category.getInstance("DC");
ContentHandler chandler;
DC(ContentHandler chandler) {
this.chandler = chandler;
}
public
void characters(char[] ch, int start, int length)
throws org.xml.sax.SAXException {
cat.debug("characters: ["+new String(ch, start, length)+ "] called");
chandler.characters(ch, start, length);
}
public
void endDocument() throws org.xml.sax.SAXException {
cat.debug("endDocument called.");
chandler.endDocument();
}
public
void endElement(String namespaceURI, String localName, String qName)
throws org.xml.sax.SAXException {
cat.debug("endElement("+namespaceURI+", "+localName+", "+qName+") called");
chandler.endElement(namespaceURI, localName, qName);
}
public
void endPrefixMapping(String prefix) throws org.xml.sax.SAXException {
cat.debug("endPrefixMapping("+prefix+") called");
chandler.endPrefixMapping(prefix);
}
public
void ignorableWhitespace(char[] ch, int start, int length)
throws org.xml.sax.SAXException {
cat.debug("ignorableWhitespace called");
chandler.ignorableWhitespace(ch, start, length);
}
public
void processingInstruction(java.lang.String target, java.lang.String data)
throws org.xml.sax.SAXException {
cat.debug("processingInstruction called");
chandler.processingInstruction(target, data);
}
public
void setDocumentLocator(Locator locator) {
cat.debug("setDocumentLocator called");
chandler.setDocumentLocator(locator);
}
public
void skippedEntity(String name) throws org.xml.sax.SAXException {
cat.debug("skippedEntity("+name+") called");
chandler.skippedEntity(name);
}
public
void startDocument() throws org.xml.sax.SAXException {
cat.debug("startDocument called");
chandler.startDocument();
}
public
void startElement(String namespaceURI, String localName, String qName,
Attributes atts) throws org.xml.sax.SAXException {
cat.debug("startElement("+namespaceURI+", "+localName+", "+qName+")called");
if("log4j:event".equals(qName)) {
cat.debug("-------------");
if(atts instanceof org.xml.sax.helpers.AttributesImpl) {
AttributesImpl ai = (AttributesImpl) atts;
int i = atts.getIndex("timestamp");
ai.setValue(i, "hello");
}
String ts = atts.getValue("timestamp");
cat.debug("New timestamp is " + ts);
}
chandler.startElement(namespaceURI, localName, qName, atts);
}
public
void startPrefixMapping(String prefix, String uri)
throws org.xml.sax.SAXException {
cat.debug("startPrefixMapping("+prefix+", "+uri+") called");
chandler.startPrefixMapping(prefix, uri);
}
}

View File

@ -0,0 +1,242 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
import java.io.IOException;
import java.io.Writer;
import java.io.FileWriter;
import java.io.File;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.helpers.QuietWriter;
import org.apache.log4j.helpers.CountingQuietWriter;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.ErrorCode;
/**
DailyFileAppender extends FileAppender to use filenames formatted with
date/time information. The filename is recomputed every day at midnight.
Note that the filename doesn't have to change every day, making it possible
to have logfiles which are per-week or per-month.
The appender computes the proper filename using the formats specified in
<a href="http://java.sun.com/j2se/1.3/docs/api/java/text/SimpleDateFormat.html">
java.text.SimpleDateFormat</a>. The format requires that most static text is
enclosed in single quotes, which are removed. The examples below show how
quotes are used to embed static information in the format.
Sample filenames:
<code>
Filename pattern Filename
"'/logs/trace-'yyyy-MM-dd'.log'" /logs/trace-2000-12-31.log
"'/logs/trace-'yyyy-ww'.log'" /logs/trace-2000-52.log
</code>
@author <a HREF="mailto:eirik.lygre@evita.no">Eirik Lygre</a>
*/
public class DailyFileAppender extends FileAppender {
/**
A string constant used in naming the option for setting the
filename pattern. Current value of this string constant is
<strong>FileNamePattern</strong>.
*/
static final public String FILE_NAME_PATTERN_OPTION = "FilePattern";
/**
The filename pattern
*/
private String fileNamePattern = null;
/**
The actual formatted filename that is currently being written to
*/
private String currentFileName = null;
/**
The timestamp when we shall next recompute the filename
*/
private long nextFilenameComputingMillis = System.currentTimeMillis () - 1;
/**
The default constructor does no longer set a default layout nor a
default output target. */
public
DailyFileAppender() {
}
/**
Instantiate a RollingFileAppender and open the file designated by
<code>filename</code>. The opened filename will become the ouput
destination for this appender.
<p>If the <code>append</code> parameter is true, the file will be
appended to. Otherwise, the file desginated by
<code>filename</code> will be truncated before being opened.
*/
public DailyFileAppender (Layout layout,String filename,boolean append) throws IOException {
super(layout, filename, append);
}
/**
Instantiate a FileAppender and open the file designated by
<code>filename</code>. The opened filename will become the output
destination for this appender.
<p>The file will be appended to. */
public DailyFileAppender (Layout layout,String filename) throws IOException {
super(layout, filename);
}
/**
Set the current output file.
The function will compute a new filename, and open a new file only
when the name has changed.
The function is automatically called once a day, to allow for
daily files -- the purpose of this class.
*/
public
synchronized
void setFile(String fileName, boolean append) throws IOException {
/* Compute filename, but only if fileNamePattern is specified */
if (fileNamePattern == null) {
errorHandler.error("Missing file pattern (" + FILE_NAME_PATTERN_OPTION + ") in setFile().");
return;
}
Date now = new Date();
fileName = new SimpleDateFormat(fileNamePattern).format (now);
if (fileName.equals(currentFileName))
return;
/* Set up next filename checkpoint */
DailyFileAppenderCalendar c = new DailyFileAppenderCalendar();
c.rollToNextDay ();
nextFilenameComputingMillis = c.getTimeInMillis ();
currentFileName = fileName;
super.setFile(fileName, append);
}
/**
This method differentiates RollingFileAppender from its super
class.
*/
protected
void subAppend(LoggingEvent event) {
if (System.currentTimeMillis () >= nextFilenameComputingMillis) {
try {
setFile (super.fileName, super.fileAppend);
}
catch(IOException e) {
System.err.println("setFile(null, false) call failed.");
e.printStackTrace();
}
}
super.subAppend(event);
}
/**
Retuns the option names for this component, namely {@link
#FILE_NAME_PATTERN_OPTION} in
addition to the options of {@link FileAppender#getOptionStrings
FileAppender}.
*/
public
String[] getOptionStrings() {
return OptionConverter.concatanateArrays(super.getOptionStrings(),
new String[] {FILE_NAME_PATTERN_OPTION});
}
/**
Set the options for the appender
*/
public
void setOption(String key, String value) {
super.setOption(key, value);
if(key.equalsIgnoreCase(FILE_NAME_PATTERN_OPTION)) {
fileNamePattern = value;
}
}
/**
If the a value for {@link #FILE_OPTION} is non-null, then {@link
#setFile} is called with the values of {@link #FILE_OPTION} and
{@link #APPEND_OPTION}.
@since 0.8.1 */
public
void activateOptions() {
try {
setFile(null, super.fileAppend);
}
catch(java.io.IOException e) {
errorHandler.error("setFile(null,"+fileAppend+") call failed.",
e, ErrorCode.FILE_OPEN_FAILURE);
}
}
}
/**
DailyFileAppenderCalendar is a helper class to DailyFileAppender. Using
this class, it is easy to compute and access the next Millis()
It subclasses the standard
<a href="http://java.sun.com/j2se/1.3/docs/api/java/text/GregorianCalendar.html">
java.util.GregorianCalendar</a>-object, to allow access to the protected
function getTimeInMillis(), which it then exports.
@author <a HREF="mailto:eirik.lygre@evita.no">Eirik Lygre</a>
*/
class DailyFileAppenderCalendar extends java.util.GregorianCalendar
{
/**
Returns the current time in Millis
*/
public long getTimeInMillis() {
return super.getTimeInMillis();
}
/**
Roll the date to the next hour, with minute, second and millisecond
set to zero.
*/
public void rollToNextDay () {
this.add(java.util.Calendar.DATE, 0);
this.add(java.util.Calendar.HOUR, 0);
this.set(java.util.Calendar.MINUTE, 0);
this.set(java.util.Calendar.SECOND, 0);
this.set(java.util.Calendar.MILLISECOND, 0);
}
}

View File

@ -0,0 +1,44 @@
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Delivered-To: urba-cgu@urbanet.ch
To: Ceki Gulcu <cgu@urbanet.ch>
From: Eirik_Lygre/evita/no%EVITA@evita.no
Subject: Re: Suggestion for new appender "DailyFileAppender"
Date: Thu, 18 Jan 2001 20:18:27 +0100
X-MIMETrack: Serialize by Router on domino1/evita/no(Release 5.0.5 |September 22, 2000) at
18.01.2001 20:18:30
This version subclasses GregorianCalendar, to get access to the
millis-variable used in the Calendar-classes (it is protected).
What do you think?
Eirik
++++++++++
Eirik Lygre
eirik.lygre@evita.no
e-vita as, Stortorvet 3, Oslo
Mobil: (+47) 905 66476
Fax: (+47) 23 35 70 51
DailyFileAppender1.jav

View File

@ -0,0 +1,188 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.gui;
import java.awt.Color;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.BorderLayout;
import javax.swing.*;
import javax.swing.text.StyledDocument;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.StyleConstants;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.Enumeration;
import java.util.ArrayList;
import org.apache.log4j.*;
public class LogTextPanel extends JPanel {
private JScrollBar scrollBar;
private JTextPane textPane;
private JCheckBox cbxTail;
private StyledDocument doc;
private Hashtable fontAttributes;
private int eventBufferMaxSize = 10000;
private ArrayList eventBuffer = new ArrayList(eventBufferMaxSize);
private int eventViewIndex = 0;
public LogTextPanel() {
constructComponents();
createDefaultFontAttributes();
}
private void constructComponents() {
// setup the panel's additional components...
this.setLayout(new BorderLayout());
cbxTail = new JCheckBox();
cbxTail.setSelected(true);
cbxTail.setText("Tail log events");
JPanel bottomPanel = new JPanel();
bottomPanel.add(cbxTail, null);
textPane = new JTextPane();
textPane.setEditable(false);
textPane.setText("");
doc = textPane.getStyledDocument();
scrollBar = new JScrollBar(JScrollBar.VERTICAL);
this.add(bottomPanel, BorderLayout.SOUTH);
this.add(scrollBar, BorderLayout.EAST);
this.add(textPane, BorderLayout.CENTER);
}
public
void setTextBackground(Color color) {
textPane.setBackground(color);
}
public
void setTextBackground(String v) {
textPane.setBackground(parseColor(v));
}
private void createDefaultFontAttributes() {
Priority[] prio = Priority.getAllPossiblePriorities();
fontAttributes = new Hashtable();
for (int i=0; i<prio.length;i++) {
MutableAttributeSet att = new SimpleAttributeSet();
fontAttributes.put(prio[i], att);
//StyleConstants.setFontSize(att,11);
}
setTextColor(Priority.FATAL, Color.red);
setTextColor(Priority.ERROR, Color.magenta);
setTextColor(Priority.WARN, Color.orange);
setTextColor(Priority.INFO, Color.blue);
setTextColor(Priority.DEBUG, Color.black);
}
private
Color parseColor (String v) {
StringTokenizer st = new StringTokenizer(v,",");
int val[] = {255,255,255,255};
int i=0;
while (st.hasMoreTokens()) {
val[i]=Integer.parseInt(st.nextToken());
i++;
}
return new Color(val[0],val[1],val[2],val[3]);
}
void setTextColor(Priority p, String v) {
StyleConstants.setForeground(
(MutableAttributeSet)fontAttributes.get(p),parseColor(v));
}
void setTextColor(Priority p, Color c) {
StyleConstants.setForeground(
(MutableAttributeSet)fontAttributes.get(p),c);
}
void setTextFontSize(int size) {
Enumeration e = fontAttributes.elements();
while (e.hasMoreElements()) {
StyleConstants.setFontSize((MutableAttributeSet)e.nextElement(),size);
}
return;
}
void setTextFontName(String name) {
Enumeration e = fontAttributes.elements();
while (e.hasMoreElements()) {
StyleConstants.setFontFamily((MutableAttributeSet)e.nextElement(),name);
}
return;
}
void setEventBufferSize(int bufferSize) {
eventBufferMaxSize = bufferSize;
}
void newEvents(EventBufferElement[] evts) {
if((eventBuffer.size() + evts.length) >= eventBufferMaxSize) {
for(int i=0; i < evts.length; i++) {
eventBuffer.remove(0);
}
eventViewIndex -= evts.length;
if(eventViewIndex < 0)
eventViewIndex = 0;
}
for(int i=0; i < evts.length; i++)
eventBuffer.add(evts[i]);
if((eventBuffer.size() > maxR) && cbxTail.isSelected()) {
eventViewIndex = (eventBuffer.size() - maxR);
}
// only redraw if new line is visible...
if((maxR < 0) || (eventBuffer.size() >= eventViewIndex && eventBuffer.size() <= (eventViewIndex + maxR)))
drawText();
}
int maxR = -1;
void drawText() {
if(maxR < 0)
maxR = textPane.getHeight() / textPane.getFontMetrics(textPane.getFont()).getHeight();
try {
doc.remove(0, doc.getLength());
} catch(Exception e) { e.printStackTrace(); }
for(int i=eventViewIndex; (i < eventBuffer.size()) && (i < (eventViewIndex + maxR)); i++) {
EventBufferElement evt = (EventBufferElement)eventBuffer.get(i);
try {
doc.insertString(doc.getLength(), evt.text, (MutableAttributeSet)fontAttributes.get(evt.prio));
} catch(Exception e) { e.printStackTrace(); }
}
}
}

View File

@ -0,0 +1,132 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.gui.examples;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import org.apache.log4j.*;
import org.apache.log4j.gui.TextPanelAppender;
public class LogTextPanelExample {
boolean packFrame = false;
String catName = "dum.cat.name";
public LogTextPanelExample() {
// setup the logging
TextPanelAppender tpa = new TextPanelAppender(new PatternLayout("%-5p %d [%t]: %m%n"), "logTextPanel");
tpa.setThreshold(Priority.DEBUG);
Category cat = Category.getInstance(catName);
cat.addAppender(tpa);
LogFrame frame = new LogFrame(tpa);
frame.validate();
//Center the frame (window), and show it
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize = frame.getSize();
if (frameSize.height > screenSize.height) {
frameSize.height = screenSize.height;
}
if (frameSize.width > screenSize.width) {
frameSize.width = screenSize.width;
}
frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);
frame.setVisible(true);
}
/**Main method*/
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch(Exception e) {
e.printStackTrace();
}
LogTextPanelExample foo = new LogTextPanelExample();
new LogTextPanelExampleGenThread(foo.catName);
}
}
class LogFrame extends JFrame {
public LogFrame(TextPanelAppender tpa) {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
JPanel contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(new BorderLayout());
this.setSize(new Dimension(600, 400));
this.setTitle("LogTextPanel Example");
contentPane.add(tpa.getLogTextPanel(), BorderLayout.CENTER);
}
// exit when window is closed
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
}
}
class LogTextPanelExampleGenThread extends Thread {
String catName;
public LogTextPanelExampleGenThread(String catName) {
this.catName = catName;
this.setPriority(Thread.NORM_PRIORITY - 1);
this.start();
}
public void run() {
Category cat = Category.getInstance(catName);
int cnt = 0;
while(true) {
cnt++;
int randEvt = (int)(Math.random() * 125);
if(randEvt < 3)
cat.fatal("{" + cnt + "} Something screwed up bad.");
else if(randEvt < 10)
cat.error("{" + cnt + "} An error occured while trying to delete all of your files.");
else if(randEvt < 25)
cat.warn("{" + cnt + "} It seems as if your hard disk is getting full.");
else if(randEvt < 55)
cat.info("{" + cnt + "} It is now time for tea.");
else if(randEvt < 65)
cat.debug("{" + cnt + "} Something bad is happening on line 565 of com.foo.Crap");
else if(randEvt < 75)
cat.debug("{" + cnt + "} Input value for xe343dd is not equal to xe39dfd!");
else if(randEvt < 85)
cat.debug("{" + cnt + "} Successfully reached line 2312 of com.foo.Goo");
else if(randEvt < 105)
cat.debug("{" + cnt + "} Here is some extra handy debugging information for you.");
else if(randEvt < 115)
cat.debug("{" + cnt + "} The file you are about to write to is not open.");
else if(randEvt < 125)
cat.debug("{" + cnt + "} The input value to the method was <null>.");
try {
Thread.sleep(10);
}
catch(Exception e) {}
}
}
}

View File

@ -0,0 +1,217 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.gui;
import java.awt.Color;
import java.awt.Image;
import java.awt.Toolkit;
import java.io.*;
import java.net.URL;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.util.Hashtable;
import java.util.ArrayList;
import javax.swing.JPanel;
import org.apache.log4j.*;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.helpers.Loader;
import org.apache.log4j.helpers.QuietWriter;
import org.apache.log4j.helpers.TracerPrintWriter;
import org.apache.log4j.helpers.OptionConverter;
/**
*
* @author James House
*/
public class TextPanelAppender extends AppenderSkeleton {
TracerPrintWriter tp;
StringWriter sw;
QuietWriter qw;
LogTextPanel logTextPanel;
LogPublishingThread logPublisher;
final String COLOR_OPTION_FATAL = "Color.Fatal";
final String COLOR_OPTION_ERROR = "Color.Error";
final String COLOR_OPTION_WARN = "Color.Warn";
final String COLOR_OPTION_INFO = "Color.Info";
final String COLOR_OPTION_DEBUG = "Color.Debug";
final String COLOR_OPTION_BACKGROUND = "Color.Background";
final String FONT_NAME_OPTION = "Font.Name";
final String FONT_SIZE_OPTION = "Font.Size";
final String EVENT_BUFFER_SIZE_OPTION = "EventBuffer.Size";
public TextPanelAppender(Layout layout, String name) {
this.layout = layout;
this.name = name;
this.sw = new StringWriter();
this.qw = new QuietWriter(sw, errorHandler);
this.tp = new TracerPrintWriter(qw);
setLogTextPanel(new LogTextPanel());
logPublisher = new LogPublishingThread(logTextPanel, Priority.ERROR, 500);
//logPublisher = new LogPublishingThread(logTextPanel, null, 500);
}
public
void close() {
}
public void append(LoggingEvent event) {
String text = this.layout.format(event);
// Print Stacktrace
// Quick Hack maybe there is a better/faster way?
if (event.throwable!=null) {
event.throwable.printStackTrace(tp);
for (int i=0; i< sw.getBuffer().length(); i++) {
if (sw.getBuffer().charAt(i)=='\t')
sw.getBuffer().replace(i,i+1," ");
}
text += sw.toString();
sw.getBuffer().delete(0,sw.getBuffer().length());
}
else
if(!text.endsWith("\n"))
text += "\n";
logPublisher.publishEvent(event.priority, text);
}
public
JPanel getLogTextPanel() {
return logTextPanel;
}
public
String[] getOptionStrings() {
return new String[] { COLOR_OPTION_FATAL, COLOR_OPTION_ERROR,
COLOR_OPTION_WARN, COLOR_OPTION_INFO, COLOR_OPTION_DEBUG,
COLOR_OPTION_BACKGROUND, FONT_NAME_OPTION, FONT_SIZE_OPTION};
}
public
void setName(String name) {
this.name = name;
}
protected
void setLogTextPanel(LogTextPanel logTextPanel) {
this.logTextPanel = logTextPanel;
logTextPanel.setTextBackground(Color.white);
}
public
void setOption(String option, String value) {
if (option.equalsIgnoreCase(COLOR_OPTION_FATAL))
logTextPanel.setTextColor(Priority.FATAL,value);
if (option.equalsIgnoreCase(COLOR_OPTION_ERROR))
logTextPanel.setTextColor(Priority.ERROR,value);
if (option.equalsIgnoreCase(COLOR_OPTION_WARN))
logTextPanel.setTextColor(Priority.WARN,value);
if (option.equalsIgnoreCase(COLOR_OPTION_INFO))
logTextPanel.setTextColor(Priority.INFO,value);
if (option.equalsIgnoreCase(COLOR_OPTION_DEBUG))
logTextPanel.setTextColor(Priority.DEBUG,value);
if (option.equalsIgnoreCase(COLOR_OPTION_BACKGROUND))
logTextPanel.setTextBackground(value);
if (option.equalsIgnoreCase(FONT_SIZE_OPTION))
logTextPanel.setTextFontSize(Integer.parseInt(value));
if (option.equalsIgnoreCase(FONT_NAME_OPTION))
logTextPanel.setTextFontName(value);
if (option.equalsIgnoreCase(EVENT_BUFFER_SIZE_OPTION))
logTextPanel.setEventBufferSize(Integer.parseInt(value));
return;
}
public
boolean requiresLayout() {
return true;
}
class LogPublishingThread extends Thread {
LogTextPanel logTextPanel;
ArrayList evts;
Priority triggerPrio;
long pubInterval;
public LogPublishingThread(LogTextPanel logTextPanel, Priority triggerPrio, long pubInterval) {
this.logTextPanel = logTextPanel;
this.evts = new ArrayList(1000);
this.triggerPrio = triggerPrio;
this.pubInterval = pubInterval;
//this.setPriority(Thread.NORM_PRIORITY - 1);
this.start();
}
public void run() {
while(true) {
synchronized(evts) {
try {
evts.wait(pubInterval);
}
catch(InterruptedException e) {}
logTextPanel.newEvents((EventBufferElement[])evts.toArray(new EventBufferElement[evts.size()]));
evts.clear();
}
}
}
public void publishEvent(Priority prio, String text) {
synchronized(evts) {
evts.add(new EventBufferElement(prio, text));
if(triggerPrio != null && prio.isGreaterOrEqual(triggerPrio))
evts.notify();
}
}
}
} // TextPaneAppender
class EventBufferElement {
public String text;
public Priority prio;
public int numLines;
EventBufferElement(Priority prio, String text) {
this.prio = prio;
this.text = text;
numLines = 1;
int pos = pos = text.indexOf('\n', 0);
int len = text.length() - 1;
while( (pos > 0) && (pos < len) )
numLines++;
pos = text.indexOf('\n', pos + 1);
}
}

View File

@ -0,0 +1,87 @@
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Delivered-To: urba-cgu@urbanet.ch
From: James House <james.house@medibuy.com>
To: Ceki Gulcu <cgu@urbanet.ch>
Subject: RE: Buffering issues
Date: Tue, 23 Jan 2001 11:38:30 -0800
X-Mailer: Internet Mail Service (5.5.2650.21)
Ceki,
Most of the "speed" issues can be easily solved, as demonstrated in
the new versions of the files that are attached, and as described
here:
The "drawing" of the panel is time consuming. And let's face it: we
will never build a swing component that can re-draw itself thousands
of times per second - nor could the human eye keep up with that anyway
(60-ish redraws per second is the limit of what most humans can
perceive).
I think you'll agree that regardless of which choice of swing
components, the issue of not being able to draw more than 100 times
per second (if that) will be a constant.
Possible solutions to wasting a lot of time redrawing are:
* Redraw every N messages
* Redraw every N milliseconds
* Redraw when a message of a high priority is received
* Only redraw if the changes (new messages) are visible (depending on
scroll-bar position)
I made some very small changes (which are some of what I outlined in
the previous e-mail as things on the to-do list), and you should be
able to see a great difference in performance.
In general the changes are: Use a "queue" to asynchronously deliver
the messages to the panel for updating, rather than having the calling
thread (the one generating the log message) be responsible for
re-drawing the panel - this frees up the thread to continue on without
waiting for the logging mechanism. The "queue" has a thread that
wakes up every N milliseconds, or when a message of a specified
priority arrives. It then delivers all queued messages to the panel,
which then redraws ONCE for the entire batch of queued messages IF the
new messages are visible in the display.
With the "tail" mechanism turned on (so that any new set of messages
forces a redraw, because the last message is always visible), the
panel can now log about a thousand messages in 1 second. With tail
turned off (so that redraw is only required if the panel is showing
the space the new messages will be printed), it can receive over a
100,000 messages in just a few seconds. Also, most of the flicker is
already eliminated.
Again, everything in the code is really "roughed in" - just there to
give the general idea, not necessarily to do things in the best way -
but I really feel that this kind of solution is what you'll have to
end up with in the long term.
James

View File

@ -0,0 +1,241 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.ErrorHandler;
import org.apache.log4j.spi.ErrorCode;
import org.apache.log4j.helpers.LogLog;
import java.util.Hashtable;
import java.util.Properties;
import javax.jms.*;
import javax.naming.InitialContext;
import javax.naming.Context;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
/**
* A Simple JMS (P2P) Queue Appender.
*
* @author Ceki G&uuml;lc&uuml;
* @author Jamie Tsao
*/
public class JMSQueueAppender extends AppenderSkeleton {
protected QueueConnection queueConnection;
protected QueueSession queueSession;
protected QueueSender queueSender;
protected Queue queue;
String initialContextFactory;
String providerUrl;
String queueBindingName;
String queueConnectionFactoryBindingName;
public
JMSQueueAppender() {
}
/**
* The <b>InitialContextFactory</b> option takes a string value.
* Its value, along with the <b>ProviderUrl</b> option will be used
* to get the InitialContext.
*/
public void setInitialContextFactory(String initialContextFactory) {
this.initialContextFactory = initialContextFactory;
}
/**
* Returns the value of the <b>InitialContextFactory</b> option.
*/
public String getInitialContextFactory() {
return initialContextFactory;
}
/**
* The <b>ProviderUrl</b> option takes a string value.
* Its value, along with the <b>InitialContextFactory</b> option will be used
* to get the InitialContext.
*/
public void setProviderUrl(String providerUrl) {
this.providerUrl = providerUrl;
}
/**
* Returns the value of the <b>ProviderUrl</b> option.
*/
public String getProviderUrl() {
return providerUrl;
}
/**
* The <b>QueueConnectionFactoryBindingName</b> option takes a
* string value. Its value will be used to lookup the appropriate
* <code>QueueConnectionFactory</code> from the JNDI context.
*/
public void setQueueConnectionFactoryBindingName(String queueConnectionFactoryBindingName) {
this.queueConnectionFactoryBindingName = queueConnectionFactoryBindingName;
}
/**
* Returns the value of the <b>QueueConnectionFactoryBindingName</b> option.
*/
public String getQueueConnectionFactoryBindingName() {
return queueConnectionFactoryBindingName;
}
/**
* The <b>QueueBindingName</b> option takes a
* string value. Its value will be used to lookup the appropriate
* destination <code>Queue</code> from the JNDI context.
*/
public void setQueueBindingName(String queueBindingName) {
this.queueBindingName = queueBindingName;
}
/**
Returns the value of the <b>QueueBindingName</b> option.
*/
public String getQueueBindingName() {
return queueBindingName;
}
/**
* Overriding this method to activate the options for this class
* i.e. Looking up the Connection factory ...
*/
public void activateOptions() {
QueueConnectionFactory queueConnectionFactory;
try {
Context ctx = getInitialContext();
queueConnectionFactory = (QueueConnectionFactory) ctx.lookup(queueConnectionFactoryBindingName);
queueConnection = queueConnectionFactory.createQueueConnection();
queueSession = queueConnection.createQueueSession(false,
Session.AUTO_ACKNOWLEDGE);
Queue queue = (Queue) ctx.lookup(queueBindingName);
queueSender = queueSession.createSender(queue);
queueConnection.start();
ctx.close();
} catch(Exception e) {
errorHandler.error("Error while activating options for appender named ["+name+
"].", e, ErrorCode.GENERIC_FAILURE);
}
}
protected InitialContext getInitialContext() throws NamingException {
try {
Hashtable ht = new Hashtable();
//Populate property hashtable with data to retrieve the context.
ht.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory);
ht.put(Context.PROVIDER_URL, providerUrl);
return (new InitialContext(ht));
} catch (NamingException ne) {
LogLog.error("Could not get initial context with ["+initialContextFactory + "] and [" + providerUrl + "].");
throw ne;
}
}
protected boolean checkEntryConditions() {
String fail = null;
if(this.queueConnection == null) {
fail = "No QueueConnection";
} else if(this.queueSession == null) {
fail = "No QueueSession";
} else if(this.queueSender == null) {
fail = "No QueueSender";
}
if(fail != null) {
errorHandler.error(fail +" for JMSQueueAppender named ["+name+"].");
return false;
} else {
return true;
}
}
/**
* Close this JMSQueueAppender. Closing releases all resources used by the
* appender. A closed appender cannot be re-opened.
*/
public synchronized // avoid concurrent append and close operations
void close() {
if(this.closed)
return;
LogLog.debug("Closing appender ["+name+"].");
this.closed = true;
try {
if(queueSession != null)
queueSession.close();
if(queueConnection != null)
queueConnection.close();
} catch(Exception e) {
LogLog.error("Error while closing JMSQueueAppender ["+name+"].", e);
}
// Help garbage collection
queueSender = null;
queueSession = null;
queueConnection = null;
}
/**
* This method called by {@link AppenderSkeleton#doAppend} method to
* do most of the real appending work. The LoggingEvent will be
* be wrapped in an ObjectMessage to be put on the JMS queue.
*/
public void append(LoggingEvent event) {
if(!checkEntryConditions()) {
return;
}
try {
ObjectMessage msg = queueSession.createObjectMessage();
msg.setObject(event);
queueSender.send(msg);
} catch(Exception e) {
errorHandler.error("Could not send message in JMSQueueAppender ["+name+"].", e,
ErrorCode.GENERIC_FAILURE);
}
}
public boolean requiresLayout() {
return false;
}
}

View File

@ -0,0 +1,28 @@
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Hi,
I have written a JMSQueueAppender that essentially logs to a JMS Queue
(Point 2 Point). The JMSAppender currently packaged with log4j logs to
a JMS Topic (I would rename it JMSTopicAppender). I also made it so
that the InitialContextFactory and ProviderUrl are configurable appender
options. I would like to submit this to Apache.
Thanks,
Jamie Tsao

View File

@ -0,0 +1,210 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.*;
import org.apache.log4j.*;
/**
* An OutputStream that flushes out to a Category.<p>
*
* Note that no data is written out to the Category until the stream is
* flushed or closed.<p>
*
* Example:<pre>
* // make sure everything sent to System.err is logged
* System.setErr(new PrintStream(new LoggingOutputStream(Category.getRoot(), Priority.WARN), true));
*
* // make sure everything sent to System.out is also logged
* System.setOut(new PrintStream(new LoggingOutputStream(Category.getRoot(), Priority.INFO), true));
* </pre>
*
* @author <a href="mailto://Jim.Moore@rocketmail.com">Jim Moore</a>
* @see Category
*/
public class LoggingOutputStream extends OutputStream {
protected static final String LINE_SEPERATOR = System.getProperty("line.separator");
/**
* Used to maintain the contract of {@link #close()}.
*/
protected boolean hasBeenClosed = false;
/**
* The internal buffer where data is stored.
*/
protected byte[] buf;
/**
* The number of valid bytes in the buffer. This value is always
* in the range <tt>0</tt> through <tt>buf.length</tt>; elements
* <tt>buf[0]</tt> through <tt>buf[count-1]</tt> contain valid
* byte data.
*/
protected int count;
/**
* Remembers the size of the buffer for speed.
*/
private int bufLength;
/**
* The default number of bytes in the buffer. =2048
*/
public static final int DEFAULT_BUFFER_LENGTH = 2048;
/**
* The category to write to.
*/
protected Category category;
/**
* The priority to use when writing to the Category.
*/
protected Priority priority;
private LoggingOutputStream() {
// illegal
}
/**
* Creates the LoggingOutputStream to flush to the given Category.
*
* @param cat the Category to write to
*
* @param priority the Priority to use when writing to the Category
*
* @exception IllegalArgumentException
* if cat == null or priority == null
*/
public LoggingOutputStream(Category cat, Priority priority)
throws IllegalArgumentException {
if (cat == null) {
throw new IllegalArgumentException("cat == null");
}
if (priority == null) {
throw new IllegalArgumentException("priority == null");
}
this.priority = priority;
category = cat;
bufLength = DEFAULT_BUFFER_LENGTH;
buf = new byte[DEFAULT_BUFFER_LENGTH];
count = 0;
}
/**
* Closes this output stream and releases any system resources
* associated with this stream. The general contract of <code>close</code>
* is that it closes the output stream. A closed stream cannot perform
* output operations and cannot be reopened.
*/
public void close() {
flush();
hasBeenClosed = true;
}
/**
* Writes the specified byte to this output stream. The general
* contract for <code>write</code> is that one byte is written
* to the output stream. The byte to be written is the eight
* low-order bits of the argument <code>b</code>. The 24
* high-order bits of <code>b</code> are ignored.
*
* @param b the <code>byte</code> to write
*
* @exception IOException
* if an I/O error occurs. In particular,
* an <code>IOException</code> may be thrown if the
* output stream has been closed.
*/
public void write(final int b) throws IOException {
if (hasBeenClosed) {
throw new IOException("The stream has been closed.");
}
// don't log nulls
if (b == 0) {
return;
}
// would this be writing past the buffer?
if (count == bufLength) {
// grow the buffer
final int newBufLength = bufLength+DEFAULT_BUFFER_LENGTH;
final byte[] newBuf = new byte[newBufLength];
System.arraycopy(buf, 0, newBuf, 0, bufLength);
buf = newBuf;
bufLength = newBufLength;
}
buf[count] = (byte)b;
count++;
}
/**
* Flushes this output stream and forces any buffered output bytes
* to be written out. The general contract of <code>flush</code> is
* that calling it is an indication that, if any bytes previously
* written have been buffered by the implementation of the output
* stream, such bytes should immediately be written to their
* intended destination.
*/
public void flush() {
if (count == 0) {
return;
}
// don't print out blank lines; flushing from PrintStream puts out these
if (count == LINE_SEPERATOR.length()) {
if ( ((char)buf[0]) == LINE_SEPERATOR.charAt(0) &&
( ( count == 1 ) || // <- Unix & Mac, -> Windows
( (count == 2) && ((char)buf[1]) == LINE_SEPERATOR.charAt(1) ) ) ) {
reset();
return;
}
}
final byte[] theBytes = new byte[count];
System.arraycopy(buf, 0, theBytes, 0, count);
category.log(priority, new String(theBytes));
reset();
}
private void reset() {
// not resetting the buffer -- assuming that if it grew that it
// will likely grow similarly again
count = 0;
}
}

View File

@ -0,0 +1,56 @@
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Copied from:
http://www.mail-archive.com/log4j-user@jakarta.apache.org/msg00430.html
--------------------------------------------------------------------------------
diverting System.stderr/stdout into log4j
--------------------------------------------------------------------------------
From: Joseph Panico
Subject: diverting System.stderr/stdout into log4j
Date: Mon, 12 Mar 2001 13:26:41 -0800
--------------------------------------------------------------------------------
Folks,
We use a number of third-party packages that do stderr.print... at various
random places in their code. I'm finding it quite useful to divert these
messages into our log4j heirarchy. I do this by replacing stderr/stdout with
my own PrintStreams that log the lines to a special log4j Category-- as
suggested on this list a while back. The only fly-in-the-ointment with this
scheme is LogLog. If there is a problem with log4j such that it cannot log
for some reason, then log4j internals use LogLog to attempt to print an
error message. This obviously leads to an infinite recursion. Has anyone
else been bothered by this? Would it make sense to add interface to LogLog
which would set the PrintStream it uses to log its error messages to?
thanks for any ideas
joe
_________________________________________________________________
Get your FREE download of MSN Explorer at http://explorer.msn.com
---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: log4j-user-help@jakarta.apache.org

View File

@ -0,0 +1,127 @@
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Copied from:
http://www.mail-archive.com/log4j-user@jakarta.apache.org/msg00433.html
--------------------------------------------------------------------------------
RE: diverting System.stderr/stdout into log4j
--------------------------------------------------------------------------------
From: Jim Moore
Subject: RE: diverting System.stderr/stdout into log4j
Date: Mon, 12 Mar 2001 14:54:13 -0800
--------------------------------------------------------------------------------
It doesn't. I haven't worried about it, since log4j doesn't contain any
bugs and therefore it would never happen... :)
Probably the best way to handle it is to add a
LogLog.setPrintStream(PrintStream) method, so you can do something like:
// remember STDERR
PrintStream se = System.err;
// make sure everything sent to System.err is logged
System.setErr(new PrintStream(new LoggingOutputStream(Category.getRoot(),
Priority.WARN), true));
// make sure everything sent to System.out is also logged
System.setOut(new PrintStream(new LoggingOutputStream(Category.getRoot(),
Priority.INFO), true));
// prevent infinate recursion in LogLog
LogLog.setPrintStream(se);
I can't think of any other way to do it in the current version besides
getting extremely kludgey by checking the stack to see if it's being called
from LogLog and logging out the the "real" STDERR then in the
LoggingOutputStream. It can be done on the theory that LogLog wouldn't be
called very often, but still...
-Jim Moore
-----Original Message-----
From: Ceki Gülcü [mailto:cgu@qos.ch]
Sent: Monday, March 12, 2001 5:15 PM
To: LOG4J Users Mailing List
Subject: RE: diverting System.stderr/stdout into log4j
Jim, Joseph,
Here is a link containing Jim's code:
http://marc.theaimsgroup.com/?l=log4j-user&m=98097669218571&w=2
How does this code handle the infinite recursion problem mentioned by
Joseph? Ceki
At 17:03 12.03.2001 -0500, Jim Moore wrote:
>Go to the mailing list archives (theAimsGroup.com is the best) and search
>for the thread with the subject of "Capturing System.err"
>
>-Jim Moore
>"I think so, Brain; but if we gave peas a chance, won't the lima beans get
>jealous?" - Pinky
>
>
>-----Original Message-----
>From: Joseph Panico [mailto:joe_panico@hotmail.com]
>Sent: Monday, March 12, 2001 4:43 PM
>To: log4j-user@jakarta.apache.org
>Subject: diverting System.stderr/stdout into log4j
>
>
>Folks,
>
>We use a number of third-party packages that do stderr.print... at various
>random places in their code. I'm finding it quite useful to divert these
>messages into our log4j heirarchy. I do this by replacing stderr/stdout
with
>
>my own PrintStreams that log the lines to a special log4j Category-- as
>suggested on this list a while back. The only fly-in-the-ointment with this
>scheme is LogLog. If there is a problem with log4j such that it cannot log
>for some reason, then log4j internals use LogLog to attempt to print an
>error message. This obviously leads to an infinite recursion. Has anyone
>else been bothered by this? Would it make sense to add interface to LogLog
>which would set the PrintStream it uses to log its error messages to?
>
>thanks for any ideas
>
>joe
I hope to see you at my ApacheCon 2001 presentation
entitled "Log4j, A Logging Package for Java".
See http://ApacheCon.Com/2001/US/ for more details.
----
Ceki Gülcü Web: http://qos.ch
av. de Rumine 5 email: cgu@qos.ch (preferred)
CH-1005 Lausanne ceki_gulcu@yahoo.com
Switzerland Tel: ++41 21 351 23 15
---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: log4j-user-help@jakarta.apache.org

View File

@ -0,0 +1,229 @@
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Copied from
http://www.mail-archive.com/log4j-user@jakarta.apache.org/msg00445.html
--------------------------------------------------------------------------------
RE: diverting System.stderr/stdout into log4j
--------------------------------------------------------------------------------
From: Michael Smith
Subject: RE: diverting System.stderr/stdout into log4j
Date: Tue, 13 Mar 2001 06:46:04 -0800
--------------------------------------------------------------------------------
There is another way!
In LogLog, completely ignore System.err. Instead, use the following to get
the standard error stream:
PrintStream err =
new PrintStream(new FileOutputStream(FileDescriptor.err));
When you use System.setErr, it changes System.err, but not
FileDescriptor.err, which maintains a descriptor for the original error
stream.
michael
For a sample program to test this, see below:
import java.io.*;
public class Stderr {
public static void main(String[] args) {
// create a print stream to represent a redirect
PrintStream nonStandardErr =
new PrintStream(new ByteArrayOutputStream());
// Redirect standard out and standard err
System.setOut(nonStandardErr);
System.setErr(nonStandardErr);
// attempt to print something
System.err.println("You should *not* see this on the console!");
// the stuff that would appear in LogLog
PrintStream logLogOut =
new PrintStream(new FileOutputStream(FileDescriptor.err));
// attempt to print something
logLogOut.println("You *should* see this on the console!");
}
}
> -----Original Message-----
> From: Ceki Gülcü [mailto:cgu@qos.ch]
> Sent: Monday, March 12, 2001 7:18 PM
> To: LOG4J Users Mailing List
> Subject: RE: diverting System.stderr/stdout into log4j
>
>
>
> Hate to follow up on myself, but the System.setErr method
> reassigns the System.err variable. This can be deduced without
> experimentation because the user calls the System.err variable
> directly to print to the console, whatever it might be. Thus, the
> reference itself must change to allow the System.err variable to
> point to the new target stream.
>
> The funny part is that the err variable is declared 'public
> final' in the JDK source code. The setErr method makes a call to
> setErr0 which is declared as being 'native'. It looks like the
> native part is circumventing the JDK restrictions. I find this
> quite entertaining. Ceki
>
> At 00:58 13.03.2001 +0100, Ceki Gülcü wrote:
>
> >Running the risk of disappointing you here, although not full of
> bugs, log4j is not bug-free as bugs creep out regularly. They
> just get corrected quickly before many people are affected by them.
> >
> >The PrintStream se = System.err; LogLog.setPrintStream(see);
> combination is simple and rather bright. I initially overlooked
> the PrintStream se = System.err; part, making me think that a
> lot of code needed to be modified to cater for the redirected
> console case. The remedy looked worse than the illness. My fears
> are largely unfounded and the solution should work quite well if
> one is careful.
> >
> >Regards, Ceki
> >
> >ps: I wonder if System.err always refers to the real STDERR or
> if really gets reassigned with the setErr call. It's easy to find out...
> >
> >At 23:20 12.03.2001 +0000, Joseph Panico wrote:
> >>Of course log4j is completely bug free, but that doesn't
> preclude user error. For instance, I neglected to add appenders
> in my config file (actually I intentionally left them out,
> thinking that would simply turn off logging) and then log4j went
> into an infinite loop. The setPrintStream makes sense to me.
> >>
> >>joe
> >>
> >>
> >>>From: Jim Moore <jim.moore@veritas.com>
> >>>Reply-To: "LOG4J Users Mailing List" <log4j-user@jakarta.apache.org>
> >>>To: 'LOG4J Users Mailing List' <log4j-user@jakarta.apache.org>
> >>>Subject: RE: diverting System.stderr/stdout into log4j
> >>>Date: Mon, 12 Mar 2001 18:10:37 -0500
> >>>
> >>>It doesn't. I haven't worried about it, since log4j doesn't
> contain any
> >>>bugs and therefore it would never happen... :)
> >>>
> >>>Probably the best way to handle it is to add a
> >>>LogLog.setPrintStream(PrintStream) method, so you can do
> something like:
> >>>
> >>>// remember STDERR
> >>>PrintStream se = System.err;
> >>>
> >>>// make sure everything sent to System.err is logged
> >>>System.setErr(new PrintStream(new
> LoggingOutputStream(Category.getRoot(),
> >>> Priority.WARN), true));
> >>>
> >>>// make sure everything sent to System.out is also logged
> >>>System.setOut(new PrintStream(new
> LoggingOutputStream(Category.getRoot(),
> >>> Priority.INFO), true));
> >>>
> >>>// prevent infinate recursion in LogLog
> >>>LogLog.setPrintStream(se);
> >>>
> >>>
> >>>I can't think of any other way to do it in the current version besides
> >>>getting extremely kludgey by checking the stack to see if it's
> being called
> >>>from LogLog and logging out the the "real" STDERR then in the
> >>>LoggingOutputStream. It can be done on the theory that LogLog
> wouldn't be
> >>>called very often, but still...
> >>>
> >>>-Jim Moore
> >>>
> >>>
> >>>-----Original Message-----
> >>>From: Ceki Gülcü [mailto:cgu@qos.ch]
> >>>Sent: Monday, March 12, 2001 5:15 PM
> >>>To: LOG4J Users Mailing List
> >>>Subject: RE: diverting System.stderr/stdout into log4j
> >>>
> >>>
> >>>Jim, Joseph,
> >>>
> >>>Here is a link containing Jim's code:
> >>>
> >>>http://marc.theaimsgroup.com/?l=log4j-user&m=98097669218571&w=2
> >>>
> >>>How does this code handle the infinite recursion problem mentioned by
> >>>Joseph? Ceki
> >>>
> >>>At 17:03 12.03.2001 -0500, Jim Moore wrote:
> >>>>Go to the mailing list archives (theAimsGroup.com is the
> best) and search
> >>>>for the thread with the subject of "Capturing System.err"
> >>>>
> >>>>-Jim Moore
> >>>>"I think so, Brain; but if we gave peas a chance, won't the
> lima beans get
> >>>>jealous?" - Pinky
> >>>>
> >>>>
> >>>>-----Original Message-----
> >>>>From: Joseph Panico [mailto:joe_panico@hotmail.com]
> >>>>Sent: Monday, March 12, 2001 4:43 PM
> >>>>To: log4j-user@jakarta.apache.org
> >>>>Subject: diverting System.stderr/stdout into log4j
> >>>>
> >>>>
> >>>>Folks,
> >>>>
> >>>>We use a number of third-party packages that do
> stderr.print... at various
> >>>>random places in their code. I'm finding it quite useful to
> divert these
> >>>>messages into our log4j heirarchy. I do this by replacing
> stderr/stdout
> >>>with
> >>>>
> >>>>my own PrintStreams that log the lines to a special log4j
> Category-- as
> >>>>suggested on this list a while back. The only
> fly-in-the-ointment with this
> >>>
> >>>>scheme is LogLog. If there is a problem with log4j such that
> it cannot log
> >>>>for some reason, then log4j internals use LogLog to attempt
> to print an
> >>>>error message. This obviously leads to an infinite recursion.
> Has anyone
> >>>>else been bothered by this? Would it make sense to add
> interface to LogLog
> >>>>which would set the PrintStream it uses to log its error messages to?
> >>>>
> >>>>thanks for any ideas
> >>>>
> >>>>joe

View File

@ -0,0 +1,707 @@
package org.apache.log4j;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.apache.log4j.RollingCalendar;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.helpers.QuietWriter;
import org.apache.log4j.helpers.CountingQuietWriter;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.LoggingEvent;
import java.util.Date;
import java.io.IOException;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.io.File;
import java.io.FilenameFilter;
/**
* <p>CompositeRollingAppender combines RollingFileAppender and DailyRollingFileAppender<br>
* It can function as either or do both at the same time (making size
* based rolling files like RollingFileAppender until a data/time boundary
* is crossed at which time it rolls all of those files as per the DailyRollingFileAppender)
* based on the setting for <code>rollingStyle</code>.<br>
* <br>
* To use CompositeRollingAppender to roll log files as they reach a certain
* size (like RollingFileAppender), set rollingStyle=1 (@see config.size)<br>
* To use CompositeRollingAppender to roll log files at certain time intervals
* (daily for example), set rollingStyle=2 and a datePattern (@see config.time)<br>
* To have CompositeRollingAppender roll log files at a certain size AND rename those
* according to time intervals, set rollingStyle=3 (@see config.composite)<br>
*
* <p>A of few additional optional features have been added:<br>
* -- Attach date pattern for current log file (@see staticLogFileName)<br>
* -- Backup number increments for newer files (@see countDirection)<br>
* -- Infinite number of backups by file size (@see maxSizeRollBackups)<br>
* <br>
* <p>A few notes and warnings: For large or infinite number of backups
* countDirection > 0 is highly recommended, with staticLogFileName = false if
* time based rolling is also used -- this will reduce the number of file renamings
* to few or none. Changing staticLogFileName or countDirection without clearing
* the directory could have nasty side effects. If Date/Time based rolling
* is enabled, CompositeRollingAppender will attempt to roll existing files
* in the directory without a date/time tag based on the last modified date
* of the base log files last modification.<br>
* <br>
* <p>A maximum number of backups based on date/time boundries would be nice
* but is not yet implemented.<br>
*
* @author Kevin Steppe
* @author Heinz Richter
* @author Eirik Lygre
* @author Ceki G&uuml;lc&uuml;
*/
public class CompositeRollingAppender extends org.apache.log4j.FileAppender
{
// The code assumes that the following 'time' constants are in a increasing
// sequence.
static final int TOP_OF_TROUBLE=-1;
static final int TOP_OF_MINUTE = 0;
static final int TOP_OF_HOUR = 1;
static final int HALF_DAY = 2;
static final int TOP_OF_DAY = 3;
static final int TOP_OF_WEEK = 4;
static final int TOP_OF_MONTH = 5;
/** Style of rolling to use */
static final int BY_SIZE = 1;
static final int BY_DATE = 2;
static final int BY_COMPOSITE = 3;
//Not currently used
static final String S_BY_SIZE = "Size";
static final String S_BY_DATE = "Date";
static final String S_BY_COMPOSITE = "Composite";
/**
The date pattern. By default, the pattern is set to
"'.'yyyy-MM-dd" meaning daily rollover.
*/
private String datePattern = "'.'yyyy-MM-dd";
/** The actual formatted filename that is currently being written to
or will be the file transferred to on roll over
(based on staticLogFileName). */
private String scheduledFilename = null;
/** The timestamp when we shall next recompute the filename. */
private long nextCheck = System.currentTimeMillis () - 1;
/** Holds date of last roll over */
Date now = new Date();
SimpleDateFormat sdf;
/** Helper class to determine next rollover time */
RollingCalendar rc = new RollingCalendar();
/** Current period for roll overs */
int checkPeriod = TOP_OF_TROUBLE;
/** The default maximum file size is 10MB. */
protected long maxFileSize = 10*1024*1024;
/** There is zero backup files by default. */
protected int maxSizeRollBackups = 0;
/** How many sized based backups have been made so far */
protected int curSizeRollBackups = 0;
/** not yet implemented */
protected int maxTimeRollBackups = -1;
protected int curTimeRollBackups = 0;
/** By default newer files have lower numbers. (countDirection < 0)
* ie. log.1 is most recent, log.5 is the 5th backup, etc...
* countDirection > 0 does the opposite ie.
* log.1 is the first backup made, log.5 is the 5th backup made, etc.
* For infinite backups use countDirection > 0 to reduce rollOver costs.
*/
protected int countDirection = -1;
/** Style of rolling to Use. BY_SIZE (1), BY_DATE(2), BY COMPOSITE(3) */
protected int rollingStyle = BY_COMPOSITE;
protected boolean rollDate = true;
protected boolean rollSize = true;
/** By default file.log is always the current file. Optionally
* file.log.yyyy-mm-dd for current formated datePattern can by the currently
* logging file (or file.log.curSizeRollBackup or even
* file.log.yyyy-mm-dd.curSizeRollBackup) This will make time based roll
* overs with a large number of backups much faster -- it won't have to
* rename all the backups!
*/
protected boolean staticLogFileName = true;
/** FileName provided in configuration. Used for rolling properly */
protected String baseFileName;
/** The default constructor does nothing. */
public CompositeRollingAppender() {
}
/**
Instantiate a <code>CompositeRollingAppender</code> and open the
file designated by <code>filename</code>. The opened filename will
become the ouput destination for this appender.
*/
public CompositeRollingAppender (Layout layout, String filename,
String datePattern) throws IOException {
this(layout, filename, datePattern, true);
}
/**
Instantiate a CompositeRollingAppender and open the file designated by
<code>filename</code>. The opened filename will become the ouput
destination for this appender.
<p>If the <code>append</code> parameter is true, the file will be
appended to. Otherwise, the file desginated by
<code>filename</code> will be truncated before being opened.
*/
public CompositeRollingAppender(Layout layout, String filename, boolean append)
throws IOException {
super(layout, filename, append);
}
/**
Instantiate a CompositeRollingAppender and open the file designated by
<code>filename</code>. The opened filename will become the ouput
destination for this appender.
*/
public CompositeRollingAppender (Layout layout, String filename,
String datePattern, boolean append) throws IOException {
super(layout, filename, append);
this.datePattern = datePattern;
activateOptions();
}
/**
Instantiate a CompositeRollingAppender and open the file designated by
<code>filename</code>. The opened filename will become the output
destination for this appender.
<p>The file will be appended to. DatePattern is default.
*/
public CompositeRollingAppender(Layout layout, String filename) throws IOException {
super(layout, filename);
}
/**
The <b>DatePattern</b> takes a string in the same format as
expected by {@link SimpleDateFormat}. This options determines the
rollover schedule.
*/
public void setDatePattern(String pattern) {
datePattern = pattern;
}
/** Returns the value of the <b>DatePattern</b> option. */
public String getDatePattern() {
return datePattern;
}
/**
Returns the value of the <b>maxSizeRollBackups</b> option.
*/
public int getMaxSizeRollBackups() {
return maxSizeRollBackups;
}
/**
Get the maximum size that the output file is allowed to reach
before being rolled over to backup files.
@since 1.1
*/
public long getMaximumFileSize() {
return maxFileSize;
}
/**
<p>Set the maximum number of backup files to keep around based on file size.
<p>The <b>MaxSizeRollBackups</b> option determines how many backup
files are kept before the oldest is erased. This option takes
an integer value. If set to zero, then there will be no
backup files and the log file will be truncated when it reaches
<code>MaxFileSize</code>. If a negative number is supplied then
no deletions will be made. Note that this could result in
very slow performance as a large number of files are rolled over unless
{@link #setCountDirection} up is used.
<p>The maximum applys to -each- time based group of files and -not- the total.
Using a daily roll the maximum total files would be (#days run) * (maxSizeRollBackups)
*/
public void setMaxSizeRollBackups(int maxBackups) {
maxSizeRollBackups = maxBackups;
}
/**
Set the maximum size that the output file is allowed to reach
before being rolled over to backup files.
<p>This method is equivalent to {@link #setMaxFileSize} except
that it is required for differentiating the setter taking a
<code>long</code> argument from the setter taking a
<code>String</code> argument by the JavaBeans {@link
java.beans.Introspector Introspector}.
@see #setMaxFileSize(String)
*/
public void setMaxFileSize(long maxFileSize) {
this.maxFileSize = maxFileSize;
}
/**
Set the maximum size that the output file is allowed to reach
before being rolled over to backup files.
<p>This method is equivalent to {@link #setMaxFileSize} except
that it is required for differentiating the setter taking a
<code>long</code> argument from the setter taking a
<code>String</code> argument by the JavaBeans {@link
java.beans.Introspector Introspector}.
@see #setMaxFileSize(String)
*/
public void setMaximumFileSize(long maxFileSize) {
this.maxFileSize = maxFileSize;
}
/**
Set the maximum size that the output file is allowed to reach
before being rolled over to backup files.
<p>In configuration files, the <b>MaxFileSize</b> option takes an
long integer in the range 0 - 2^63. You can specify the value
with the suffixes "KB", "MB" or "GB" so that the integer is
interpreted being expressed respectively in kilobytes, megabytes
or gigabytes. For example, the value "10KB" will be interpreted
as 10240.
*/
public void setMaxFileSize(String value) {
maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1);
}
protected void setQWForFiles(Writer writer) {
qw = new CountingQuietWriter(writer, errorHandler);
}
//Taken verbatum from DailyRollingFileAppender
int computeCheckPeriod() {
RollingCalendar c = new RollingCalendar();
// set sate to 1970-01-01 00:00:00 GMT
Date epoch = new Date(0);
if(datePattern != null) {
for(int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) {
String r0 = sdf.format(epoch);
c.setType(i);
Date next = new Date(c.getNextCheckMillis(epoch));
String r1 = sdf.format(next);
//LogLog.debug("Type = "+i+", r0 = "+r0+", r1 = "+r1);
if(r0 != null && r1 != null && !r0.equals(r1)) {
return i;
}
}
}
return TOP_OF_TROUBLE; // Deliberately head for trouble...
}
//Now for the new stuff
/**
* Handles append time behavior for CompositeRollingAppender. This checks
* if a roll over either by date (checked first) or time (checked second)
* is need and then appends to the file last.
*/
protected void subAppend(LoggingEvent event) {
if (rollDate) {
long n = System.currentTimeMillis();
if (n >= nextCheck) {
now.setTime(n);
nextCheck = rc.getNextCheckMillis(now);
rollOverTime();
}
}
if (rollSize) {
if ((fileName != null) && ((CountingQuietWriter) qw).getCount() >= maxFileSize) {
rollOverSize();
}
}
super.subAppend(event);
}
public void setFile(String file)
{
baseFileName = file.trim();
fileName = file.trim();
}
/**
* Creates and opens the file for logging. If <code>staticLogFileName</code>
* is false then the fully qualified name is determined and used.
*/
public synchronized void setFile(String fileName, boolean append) throws IOException {
if (!staticLogFileName) {
scheduledFilename = fileName = fileName.trim() + sdf.format(now);
if (countDirection > 0) {
scheduledFilename = fileName = fileName + '.' + (++curSizeRollBackups);
}
}
super.setFile(fileName, append);
if(append) {
File f = new File(fileName);
((CountingQuietWriter) qw).setCount(f.length());
}
}
public int getCountDirection() {
return countDirection;
}
public void setCountDirection(int direction) {
countDirection = direction;
}
public int getRollingStyle () {
return rollingStyle;
}
public void setRollingStyle(int style) {
rollingStyle = style;
switch (rollingStyle) {
case BY_SIZE:
rollDate = false;
rollSize = true;
break;
case BY_DATE:
rollDate = true;
rollSize = false;
break;
case BY_COMPOSITE:
rollDate = true;
rollSize = true;
break;
default:
errorHandler.error("Invalid rolling Style, use 1 (by size only), 2 (by date only) or 3 (both)");
}
}
/*
public void setRollingStyle(String style) {
if (style == S_BY_SIZE) {
rollingStyle = BY_SIZE;
}
else if (style == S_BY_DATE) {
rollingStyle = BY_DATE;
}
else if (style == S_BY_COMPOSITE) {
rollingStyle = BY_COMPOSITE;
}
}
*/
public boolean getStaticLogFileName() {
return staticLogFileName;
}
public void setStaticLogFileName(boolean s) {
staticLogFileName = s;
}
public void setStaticLogFileName(String value) {
setStaticLogFileName(OptionConverter.toBoolean(value, true));
}
/**
* Initializes based on exisiting conditions at time of <code>
* activateOptions</code>. The following is done:<br>
* <br>
* A) determine curSizeRollBackups<br>
* B) determine curTimeRollBackups (not implemented)<br>
* C) initiates a roll over if needed for crossing a date boundary since
* the last run.
*/
protected void existingInit() {
curSizeRollBackups = 0;
curTimeRollBackups = 0;
//part A starts here
String filter;
if (staticLogFileName || !rollDate) {
filter = baseFileName + ".*";
}
else {
filter = scheduledFilename + ".*";
}
File f = new File(baseFileName);
f = f.getParentFile();
if (f == null)
f = new File(".");
LogLog.debug("Searching for existing files in: " + f);
String[] files = f.list();
if (files != null) {
for (int i = 0; i < files.length; i++) {
if (!files[i].startsWith(baseFileName))
continue;
int index = files[i].lastIndexOf(".");
if (staticLogFileName) {
int endLength = files[i].length() - index;
if (baseFileName.length() + endLength != files[i].length()) {
//file is probably scheduledFilename + .x so I don't care
continue;
}
}
try {
int backup = Integer.parseInt(files[i].substring(index + 1, files[i].length()));
LogLog.debug("From file: " + files[i] + " -> " + backup);
if (backup > curSizeRollBackups)
curSizeRollBackups = backup;
}
catch (Exception e) {
//this happens when file.log -> file.log.yyyy-mm-dd which is normal
//when staticLogFileName == false
LogLog.debug("Encountered a backup file not ending in .x " + files[i]);
}
}
}
LogLog.debug("curSizeRollBackups starts at: " + curSizeRollBackups);
//part A ends here
//part B not yet implemented
//part C
if (staticLogFileName && rollDate) {
File old = new File(baseFileName);
if (old.exists()) {
Date last = new Date(old.lastModified());
if (!(sdf.format(last).equals(sdf.format(now)))) {
scheduledFilename = baseFileName + sdf.format(last);
LogLog.debug("Initial roll over to: " + scheduledFilename);
rollOverTime();
}
}
}
LogLog.debug("curSizeRollBackups after rollOver at: " + curSizeRollBackups);
//part C ends here
}
/**
* Sets initial conditions including date/time roll over information, first check,
* scheduledFilename, and calls <code>existingInit</code> to initialize
* the current # of backups.
*/
public void activateOptions() {
//REMOVE removed rollDate from boolean to enable Alex's change
if(datePattern != null) {
now.setTime(System.currentTimeMillis());
sdf = new SimpleDateFormat(datePattern);
int type = computeCheckPeriod();
//printPeriodicity(type);
rc.setType(type);
//next line added as this removes the name check in rollOver
nextCheck = rc.getNextCheckMillis(now);
} else {
if (rollDate)
LogLog.error("Either DatePattern or rollingStyle options are not set for ["+
name+"].");
}
existingInit();
super.activateOptions();
if (rollDate && fileName != null && scheduledFilename == null)
scheduledFilename = fileName + sdf.format(now);
}
/**
Rollover the file(s) to date/time tagged file(s).
Opens the new file (through setFile) and resets curSizeRollBackups.
*/
protected void rollOverTime() {
curTimeRollBackups++;
//delete the old stuff here
if (staticLogFileName) {
/* Compute filename, but only if datePattern is specified */
if (datePattern == null) {
errorHandler.error("Missing DatePattern option in rollOver().");
return;
}
//is the new file name equivalent to the 'current' one
//something has gone wrong if we hit this -- we should only
//roll over if the new file will be different from the old
String dateFormat = sdf.format(now);
if (scheduledFilename.equals(fileName + dateFormat)) {
errorHandler.error("Compare " + scheduledFilename + " : " + fileName + dateFormat);
return;
}
// close current file, and rename it to datedFilename
this.closeFile();
//we may have to roll over a large number of backups here
String from, to;
for (int i = 1; i <= curSizeRollBackups; i++) {
from = fileName + '.' + i;
to = scheduledFilename + '.' + i;
rollFile(from, to);
}
rollFile(fileName, scheduledFilename);
}
try {
// This will also close the file. This is OK since multiple
// close operations are safe.
curSizeRollBackups = 0; //We're cleared out the old date and are ready for the new
//new scheduled name
scheduledFilename = fileName + sdf.format(now);
this.setFile(baseFileName, false);
}
catch(IOException e) {
errorHandler.error("setFile("+fileName+", false) call failed.");
}
}
/** Renames file <code>from</code> to file <code>to</code>. It
* also checks for existence of target file and deletes if it does.
*/
protected static void rollFile(String from, String to) {
File target = new File(to);
if (target.exists()) {
LogLog.debug("deleting existing target file: " + target);
target.delete();
}
File file = new File(from);
file.renameTo(target);
LogLog.debug(from +" -> "+ to);
}
/** Delete's the specified file if it exists */
protected static void deleteFile(String fileName) {
File file = new File(fileName);
if (file.exists()) {
file.delete();
}
}
/**
Implements roll overs base on file size.
<p>If the maximum number of size based backups is reached
(<code>curSizeRollBackups == maxSizeRollBackups</code) then the oldest
file is deleted -- it's index determined by the sign of countDirection.<br>
If <code>countDirection</code> < 0, then files
{<code>File.1</code>, ..., <code>File.curSizeRollBackups -1</code>}
are renamed to {<code>File.2</code>, ...,
<code>File.curSizeRollBackups</code>}. Moreover, <code>File</code> is
renamed <code>File.1</code> and closed.<br>
A new file is created to receive further log output.
<p>If <code>maxSizeRollBackups</code> is equal to zero, then the
<code>File</code> is truncated with no backup files created.
<p>If <code>maxSizeRollBackups</code> < 0, then <code>File</code> is
renamed if needed and no files are deleted.
*/
// synchronization not necessary since doAppend is alreasy synched
protected void rollOverSize() {
File file;
this.closeFile(); // keep windows happy.
LogLog.debug("rolling over count=" + ((CountingQuietWriter) qw).getCount());
LogLog.debug("maxSizeRollBackups = " + maxSizeRollBackups);
LogLog.debug("curSizeRollBackups = " + curSizeRollBackups);
LogLog.debug("countDirection = " + countDirection);
// If maxBackups <= 0, then there is no file renaming to be done.
if (maxSizeRollBackups != 0) {
if (countDirection < 0) {
// Delete the oldest file, to keep Windows happy.
if (curSizeRollBackups == maxSizeRollBackups) {
deleteFile(fileName + '.' + maxSizeRollBackups);
curSizeRollBackups--;
}
// Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2}
for (int i = curSizeRollBackups; i >= 1; i--) {
rollFile((fileName + "." + i), (fileName + '.' + (i + 1)));
}
curSizeRollBackups++;
// Rename fileName to fileName.1
rollFile(fileName, fileName + ".1");
} //REMOVE This code branching for Alexander Cerna's request
else if (countDirection == 0) {
//rollFile based on date pattern
curSizeRollBackups++;
now.setTime(System.currentTimeMillis());
scheduledFilename = fileName + sdf.format(now);
rollFile(fileName, scheduledFilename);
}
else { //countDirection > 0
if (curSizeRollBackups >= maxSizeRollBackups && maxSizeRollBackups > 0) {
//delete the first and keep counting up.
int oldestFileIndex = curSizeRollBackups - maxSizeRollBackups + 1;
deleteFile(fileName + '.' + oldestFileIndex);
}
if (staticLogFileName) {
curSizeRollBackups++;
rollFile(fileName, fileName + '.' + curSizeRollBackups);
}
}
}
try {
// This will also close the file. This is OK since multiple
// close operations are safe.
this.setFile(baseFileName, false);
}
catch(IOException e) {
LogLog.error("setFile("+fileName+", false) call failed.", e);
}
}
}

View File

@ -0,0 +1,97 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.varia.test;
import org.apache.log4j.varia.JDBCAppender;
import org.apache.log4j.*;
public class JDBCTest
{
public static void main (String argv[])
{
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
catch (Exception e)
{
e.printStackTrace();
System.out.println(e.toString());
}
Category rootLog = Category.getRoot();
Layout layout = new PatternLayout("%p [%t] %c - %m%n");
JDBCAppender appender = new JDBCAppender();
appender.setLayout(layout);
appender.setOption(JDBCAppender.URL_OPTION, "jdbc:odbc:someDB");
appender.setOption(JDBCAppender.USER_OPTION, "auser");
appender.setOption(JDBCAppender.PASSWORD_OPTION, "thepassword");
rootLog.addAppender(appender);
try {
Category log = Category.getInstance("main");
log.debug("Debug 1");
Thread.sleep(500);
log.info("info 1");
Thread.sleep(500);
log.warn("warn 1");
Thread.sleep(500);
log.error("error 1");
Thread.sleep(500);
log.fatal("fatal 1");
Thread.sleep(500);
appender.setOption(JDBCAppender.BUFFER_OPTION, "5");
log.debug("Debug 2");
Thread.sleep(500);
log.info("info 2");
Thread.sleep(500);
log.warn("warn 2");
Thread.sleep(500);
log.error("error 2");
Thread.sleep(500);
log.fatal("fatal 2");
Thread.sleep(500);
appender.setOption(JDBCAppender.BUFFER_OPTION, "2");
appender.setThreshold(Priority.WARN);
log.debug("Debug 3");
Thread.sleep(500);
log.info("info 3");
Thread.sleep(500);
log.warn("warn 3");
Thread.sleep(500);
log.error("error 3");
Thread.sleep(500);
log.fatal("fatal 3");
}
catch (InterruptedException e)
{
System.out.println("Interrupted");
}
}
}

View File

@ -0,0 +1,559 @@
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Delivered-To: urba-cgu@urbanet.ch
Mailing-List: contact log4j-user-help@jakarta.apache.org; run by ezmlm
List-Post: <mailto:log4j-user@jakarta.apache.org>
List-Help: <mailto:log4j-user-help@jakarta.apache.org>
List-Unsubscribe: <mailto:log4j-user-unsubscribe@jakarta.apache.org>
List-Subscribe: <mailto:log4j-user-subscribe@jakarta.apache.org>
Reply-To: "LOG4J Users Mailing List" <log4j-user@jakarta.apache.org>
Delivered-To: mailing list log4j-user@jakarta.apache.org
Date: Thu, 01 Feb 2001 14:26:34 -0800
From: Kevin Steppe <ksteppe@pacbell.net>
X-Mailer: Mozilla 4.76 [en] (Windows NT 5.0; U)
X-Accept-Language: en
To: LOG4J Users Mailing List <log4j-user@jakarta.apache.org>
Subject: JDBC Appender
X-Spam-Rating: h31.sny.collab.net 1.6.2 0/1000/N
Ok, here it is. Since there will be differences in database schemas and
connection/execution methods, I wrote this with the intention that those
parts would be overriden by subclasses (that's what I'm doing for my
company), however it will work as is if you have a stored procedure
spLog @msg. I'm sure there are optimizations which could be done.
The code for org.apache.log4j.varia.JDBCAppender and
org.apache.log4j.varia.test.JDBCTest follow and files attached. At the
bottem is the SQL I used to test this on M$ SQL-Server.
I help this proves useful,
Kevin
package org.apache.log4j.varia;
import org.apache.log4j.*;
import org.apache.log4j.spi.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.SQLException;
/**
* Contribution from MD Data Direct.
*
* Implements an ArrayList buffer before storing messages to the DB.
* Override getSQL to fit your database schema (or implement spLog msg
on your DB)
* Override executeSQL to modify how DB connection and SQL execution is
made.
*
* @author: Kevin Steppe
*/
public class JDBCAppender extends org.apache.log4j.AppenderSkeleton
implements org.apache.log4j.Appender
{
protected String databaseURL = "jdbc:odbc:myDB";
protected String databaseUser = "me";
protected String databasePassword = "mypassword";
public static final String URL_OPTION = "URL";
public static final String USER_OPTION = "User";
public static final String PASSWORD_OPTION = "Password";
public static final String BUFFER_OPTION = "Buffer";
protected int bufferSize = 1;
protected List buffer;
public JDBCAppender()
{
super();
buffer = new ArrayList();
}
public void append(LoggingEvent event)
{
buffer.add(event);
if (buffer.size() >= bufferSize)
flushBuffer();
}
public void close()
{
flushBuffer();
this.closed = true;
}
public void setOption(String key, String value)
{
super.setOption(key, value);
if (key.equalsIgnoreCase(URL_OPTION))
databaseURL = value;
else if (key.equalsIgnoreCase(USER_OPTION))
databaseUser = value;
else if (key.equalsIgnoreCase(PASSWORD_OPTION))
databasePassword = value;
else if (key.equalsIgnoreCase(BUFFER_OPTION))
bufferSize = Integer.parseInt(value);
}
/**
* Override this to create the SQL needed for your DB schema
*/
protected String getSQL(LoggingEvent event)
{
String msg = this.layout.format(event);
String sql = "spLog '" + msg + "'";
return sql;
}
/**
* Override this to provide an alertnate method of getting
connections (such as caching)
* This implementation creates a new connection and statement for
every execution which
* is very wastefull. One method to fix this is to open connections
at the start of
* flushBuffer() and close them at the end. MD Data uses a
connection pool outside
* of JDBCAppender which is accessed in the override of this method.
*/
protected void executeSQL(String sql) throws SQLException
{
Connection con = null;
Statement stmt = null;
try {
con = DriverManager.getConnection(databaseURL, databaseUser,
databasePassword);
stmt = con.createStatement();
stmt.executeUpdate(sql);
}
catch (SQLException e)
{
if (con != null)
con.close();
if (stmt != null)
stmt.close();
throw e;
}
stmt.close();
con.close();
}
public void flushBuffer()
{
//Do the actual logging
for (Iterator i = buffer.iterator(); i.hasNext();)
{
try {
String sql = getSQL((LoggingEvent)i.next());
executeSQL(sql);
}
catch (SQLException e)
{
errorHandler.error("Failed to excute sql", e,
ErrorCode.FLUSH_FAILURE);
}
}
buffer.clear();
}
public void finalize()
{
close();
}
public boolean requiresLayout()
{
return true;
}
}
package org.apache.log4j.varia.test;
import org.apache.log4j.varia.JDBCAppender;
import org.apache.log4j.*;
public class JDBCTest
{
public static void main (String argv[])
{
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
catch (Exception e)
{
e.printStackTrace();
System.out.println(e.toString());
}
Category rootLog = Category.getRoot();
Layout layout = new PatternLayout("%p [%t] %c - %m%n");
JDBCAppender appender = new JDBCAppender();
appender.setLayout(layout);
appender.setOption(JDBCAppender.URL_OPTION, "jdbc:odbc:someDB");
appender.setOption(JDBCAppender.USER_OPTION, "auser");
appender.setOption(JDBCAppender.PASSWORD_OPTION, "thepassword");
rootLog.addAppender(appender);
try {
Category log = Category.getInstance("main");
log.debug("Debug 1");
Thread.sleep(500);
log.info("info 1");
Thread.sleep(500);
log.warn("warn 1");
Thread.sleep(500);
log.error("error 1");
Thread.sleep(500);
log.fatal("fatal 1");
Thread.sleep(500);
appender.setOption(JDBCAppender.BUFFER_OPTION, "5");
log.debug("Debug 2");
Thread.sleep(500);
log.info("info 2");
Thread.sleep(500);
log.warn("warn 2");
Thread.sleep(500);
log.error("error 2");
Thread.sleep(500);
log.fatal("fatal 2");
Thread.sleep(500);
appender.setOption(JDBCAppender.BUFFER_OPTION, "2");
appender.setThreshold(Priority.WARN);
log.debug("Debug 3");
Thread.sleep(500);
log.info("info 3");
Thread.sleep(500);
log.warn("warn 3");
Thread.sleep(500);
log.error("error 3");
Thread.sleep(500);
log.fatal("fatal 3");
}
catch (InterruptedException e)
{
System.out.println("Interrupted");
}
}
}
drop table JDBCAppenderTest
go
create table JDBCAppenderTest (EventID int identity, entrytime datetime,
message varchar(255))
drop procedure spLog
go
create procedure spLog (@msg varchar(255)) as
insert into JDBCAppenderTest (message, entrytime) values (@msg,
getdate())
select * from JDBCAppenderTest
drop table JDBCAppenderTest
go
create table JDBCAppenderTest (EventID int identity, entrytime datetime, message varchar(255))
drop procedure spLog
go
create procedure spLog (@msg varchar(255)) as
insert into JDBCAppenderTest (message, entrytime) values (@msg, getdate())
select * from JDBCAppenderTest
package org.apache.log4j.varia;
import org.apache.log4j.*;
import org.apache.log4j.spi.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.SQLException;
/**
* Contribution from MD Data Direct.
*
* Implements an ArrayList buffer before storing messages to the DB.
* Override getSQL to fit your database schema (or implement spLog msg on your DB)
* Override executeSQL to modify how DB connection and SQL execution is made.
*
* @author: Kevin Steppe
*/
public class JDBCAppender extends org.apache.log4j.AppenderSkeleton
implements org.apache.log4j.Appender
{
protected String databaseURL = "jdbc:odbc:myDB";
protected String databaseUser = "me";
protected String databasePassword = "mypassword";
public static final String URL_OPTION = "URL";
public static final String USER_OPTION = "User";
public static final String PASSWORD_OPTION = "Password";
public static final String BUFFER_OPTION = "Buffer";
protected int bufferSize = 1;
protected List buffer;
public JDBCAppender()
{
super();
buffer = new ArrayList();
}
public void append(LoggingEvent event)
{
buffer.add(event);
if (buffer.size() >= bufferSize)
flushBuffer();
}
public void close()
{
flushBuffer();
this.closed = true;
}
public void setOption(String key, String value)
{
super.setOption(key, value);
if (key.equalsIgnoreCase(URL_OPTION))
databaseURL = value;
else if (key.equalsIgnoreCase(USER_OPTION))
databaseUser = value;
else if (key.equalsIgnoreCase(PASSWORD_OPTION))
databasePassword = value;
else if (key.equalsIgnoreCase(BUFFER_OPTION))
bufferSize = Integer.parseInt(value);
}
/**
* Override this to create the SQL needed for your DB schema
*/
protected String getSQL(LoggingEvent event)
{
String msg = this.layout.format(event);
String sql = "spLog '" + msg + "'";
System.out.println(sql); //DEBUG
return sql;
}
/**
* Override this to provide an alertnate method of getting connections (such as caching)
* This implementation creates a new connection and statement for every execution which
* is very wastefull. One method to fix this is to open connections at the start of
* flushBuffer() and close them at the end. MD Data uses a connection pool outside
* of JDBCAppender which is accessed in the override of this method.
*/
protected void executeSQL(String sql) throws SQLException
{
Connection con = null;
Statement stmt = null;
try {
con = DriverManager.getConnection(databaseURL, databaseUser, databasePassword);
stmt = con.createStatement();
stmt.executeUpdate(sql);
}
catch (SQLException e)
{
if (con != null)
con.close();
if (stmt != null)
stmt.close();
throw e;
}
stmt.close();
con.close();
}
public void flushBuffer()
{
//Do the actual logging
for (Iterator i = buffer.iterator(); i.hasNext();)
{
try {
String sql = getSQL((LoggingEvent)i.next());
executeSQL(sql);
}
catch (SQLException e)
{
errorHandler.error("Failed to excute sql", e, ErrorCode.FLUSH_FAILURE);
}
}
buffer.clear();
}
public void finalize()
{
close();
}
public boolean requiresLayout()
{
return true;
}
}package org.apache.log4j.varia.test;
import org.apache.log4j.varia.JDBCAppender;
import org.apache.log4j.*;
public class JDBCTest
{
public static void main (String argv[])
{
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
catch (Exception e)
{
e.printStackTrace();
System.out.println(e.toString());
}
Category rootLog = Category.getRoot();
Layout layout = new PatternLayout("%p [%t] %c - %m%n");
JDBCAppender appender = new JDBCAppender();
appender.setLayout(layout);
appender.setOption(JDBCAppender.URL_OPTION, "jdbc:odbc:someDB");
appender.setOption(JDBCAppender.USER_OPTION, "auser");
appender.setOption(JDBCAppender.PASSWORD_OPTION, "thepassword");
rootLog.addAppender(appender);
try {
Category log = Category.getInstance("main");
log.debug("Debug 1");
Thread.sleep(500);
log.info("info 1");
Thread.sleep(500);
log.warn("warn 1");
Thread.sleep(500);
log.error("error 1");
Thread.sleep(500);
log.fatal("fatal 1");
Thread.sleep(500);
appender.setOption(JDBCAppender.BUFFER_OPTION, "5");
log.debug("Debug 2");
Thread.sleep(500);
log.info("info 2");
Thread.sleep(500);
log.warn("warn 2");
Thread.sleep(500);
log.error("error 2");
Thread.sleep(500);
log.fatal("fatal 2");
Thread.sleep(500);
appender.setOption(JDBCAppender.BUFFER_OPTION, "2");
appender.setThreshold(Priority.WARN);
log.debug("Debug 3");
Thread.sleep(500);
log.info("info 3");
Thread.sleep(500);
log.warn("warn 3");
Thread.sleep(500);
log.error("error 3");
Thread.sleep(500);
log.fatal("fatal 3");
}
catch (InterruptedException e)
{
System.out.println("Interrupted");
}
}
}

View File

@ -0,0 +1,118 @@
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Received: (qmail 12476 invoked from network); 28 Mar 2002 06:19:49 -0000
Date: Wed, 27 Mar 2002 22:28:58 -0800
From: Kevin Steppe <ksteppe@pacbell.net>
Subject: Re: RollingFileAppender and DailyRollingFileAppender
To: Log4J Users List <log4j-user@jakarta.apache.org>
Reply-To: ksteppe@pacbell.net
Message-id: <3CA2B82A.5C366593@pacbell.net>
MIME-version: 1.0
X-Mailer: Mozilla 4.7 [en] (WinNT; I)
Content-type: multipart/mixed; boundary="Boundary_(ID_TnKsnil+d0oYB9TV0P+fgA)"
X-Accept-Language: en
References:
<8DAB344CC3F3FE42A51FA1A8E295F8682ACD14@tepg-server2.tepgsyd.tycoint.com.au>
X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N
I wrote a CompositeRollingAppender last August to do that. I'm attaching that
code and some example config files to you separately.
Ceki... Could you please put these files in the log4j/contribs/KevinSteppe
folder of the available releases? This seems to be coming up occasionally and
it would be more convenient to just point people there.
Thanks,
Kevin
Janusz Dalecki wrote:
> Is there a way of having the mixture of both RollingFileAppender and
> DailyRollingFileAppender options?. I have a requirement to log daily and
> delete old files weekly.
> Thanks,
> Janusz
>
> --
> To unsubscribe, e-mail: <mailto:log4j-user-unsubscribe@jakarta.apache.org>
> For additional commands, e-mail: <mailto:log4j-user-help@jakarta.apache.org>
#Config file for CompositeRollingAppender
#This is an example config to use CompositeRollingAppender in Size based Backups only
log4j.rootCategory=debug, R
log4j.appender.R=org.apache.log4j.CompositeRollingAppender
#How to perform rolling -- 1 = By Size
#Note -- this is the only difference from RollingFileAppender!
log4j.appender.R.RollingStyle=1
#file to log to
log4j.appender.R.File=example.log
#Size Rolling params
log4j.appender.R.MaxFileSize=10MB
log4j.appender.R.MaxSizeRollBackups=10
#layout options
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n
#Config file for CompositeRollingAppender
#This is an example config to use CompositeRollingAppender in Time based Backups only
log4j.rootCategory=debug, R
log4j.appender.R=org.apache.log4j.CompositeRollingAppender
#How to perform rolling -- 2 = By Time
#Note -- this is the only difference from DailyRollingFileAppender!
log4j.appender.R.RollingStyle=2
#file to log to
log4j.appender.R.File=example.log
#Date Rolling params
log4j.appender.R.datePattern='.'yyyy-MM-dd
#layout options
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n
#Default Config file for CompositeRollingAppender
log4j.rootCategory=debug, R
log4j.appender.R=org.apache.log4j.CompositeRollingAppender
#How to perform rolling -- Composite is the default
log4j.appender.R.RollingStyle=3
#Use same file name for all inprocess logging?
log4j.appender.R.staticLogFileName=true
log4j.appender.R.File=example.log
#Size Rolling params
log4j.appender.R.CountDirection=-1
log4j.appender.R.MaxFileSize=5KB
log4j.appender.R.MaxSizeRollBackups=10
#Date Rolling params
log4j.appender.R.datePattern='.'yyyy-MM-dd
#layout options
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n

View File

@ -0,0 +1,284 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.net;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.DatagramPacket;
import java.net.UnknownHostException;
import java.net.SocketException;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.Category;
import org.apache.log4j.Priority;
import org.apache.log4j.Layout;
import org.apache.log4j.helpers.SingleLineTracerPrintWriter;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.helpers.QuietWriter;
/**
Use DatagramStringAppender to send log messages to a remote daemon
which accepts Datagram (UDP) messages.
<p>
The benefits of UDP are that the client is guarunteed not to
slow down if the network or remote log daemon is slow, and that
no permanent TCP connection between client and server exists.
<p>
The disadvantages are that log messages can be lost if the network
or remote daemon are under excessive load.
<p>
This class builts the final message string <b>before</b> sending
the UDP packet, hence the "string" component in the class name. This
means that the receiving application can be written in any language.
The data is transmitted in whatever encoding is specified in the
configuration file; this may be an 8-bit encoding (eg ISO-8859-1, also
known as LATIN-1) or a larger encoding, eg UTF-16.
<p>
An alternative to building the message string within DatagramStringAppender
would be to serialize & send the complete logging event object (perhaps
such a class could be called a DatagramSerialAppender??). The
receiving end could then be configured with appropriate Layout objects
to generate the actual logged messages. This would ensure that the
logging of messages from different sources is done in a consistent
format, and give a central place to configure that format. It would ensure
(by transmitting messages as unicode) that the receiving end could control
the encoding in which the output is generated. It also would possibly allow
he receiving end to use the full log4j flexibility to pass the event to
different appenders at the receiving end, as the category information is
retained, etc. However, this does require that the receiving end is in
java, and that all clients of the logging daemon are java applications.
In contrast, this DatagramStringAppender can send mesages to a log daemon
that accepts messages from a variety of sources.
@author Simon Kitching
*/
public class DatagramStringAppender extends AppenderSkeleton {
/**
A string constant used in naming the option for setting the destination
server for messages. Current value of this string constant is
<b>DatagramHost</b>. */
public static final String DATAGRAM_HOST_OPTION = "DatagramHost";
/**
A string constant used in naming the option for setting the destination
port for messages. Current value of this string constant is
<b>DatagramPort</b>. */
public static final String DATAGRAM_PORT_OPTION = "DatagramPort";
/**
A string constant used in naming the option for setting the character
encoding used when generating the log message. Current value of this
string constant is <b>DatagramEncoding</b>. */
public static final String DATAGRAM_ENCODING_OPTION = "DatagramEncoding";
/**
The default value for the "host" attribute, ie the machine to which
messages are sent. Current value of this string constant is
<b>localhost</b>. */
public static final String DEFAULT_HOST = "localhost";
/**
The default value for the "port" attribute, ie the UDP port to which
messages are sent. Current value of this integer constant is
<b>8200</b>. This value was chosen for no particular reason. */
public static final int DEFAULT_PORT = 8200;
/**
The default value for the "encoding" attribute, ie the way in which
unicode message strings are converted into a stream of bytes before
their transmission as a UDP packet. The current value of this constant
is <b>null</b>, which means that the default platform encoding will
be used. */
public static final String DEFAULT_ENCODING = null;
String host = DEFAULT_HOST;
int port = DEFAULT_PORT;
String encoding = DEFAULT_ENCODING;
SingleLineTracerPrintWriter stp;
QuietWriter qw;
public
DatagramStringAppender() {
this.setDestination(DEFAULT_HOST, DEFAULT_PORT, DEFAULT_ENCODING);
}
public
DatagramStringAppender(Layout layout) {
this.setLayout(layout);
this.setDestination(DEFAULT_HOST, DEFAULT_PORT, DEFAULT_ENCODING);
}
public
DatagramStringAppender(Layout layout, String host, int port) {
this.setLayout(layout);
this.setDestination(host, port, DEFAULT_ENCODING);
}
public
DatagramStringAppender(Layout layout, String host, int port, String encoding) {
this.setLayout(layout);
this.setDestination(host, port, encoding);
}
/**
Release any resources held by this Appender
*/
public
void close() {
closed = true;
// A DatagramWriter is UDP based and needs no opening. Hence, it
// can't be closed. We just unset the variables here.
qw = null;
stp = null;
}
public
void append(LoggingEvent event) {
if(!isAsSevereAsThreshold(event.priority))
return;
// We must not attempt to append if qw is null.
if(qw == null) {
errorHandler.error(
"No host is set for DatagramStringAppender named \""
+ this.name + "\".");
return;
}
String buffer = layout.format(event);
qw.write(buffer);
if(event.throwable != null)
event.throwable.printStackTrace(stp);
else if (event.throwableInformation != null) {
// we must be the receiver of a serialized/deserialized LoggingEvent;
// the event's throwable member is transient, ie becomes null when
// deserialized, but that's ok because throwableInformation should
// have the string equivalent of the same info (ie stack trace)
qw.write(event.throwableInformation);
}
}
/**
Activate the options set via the setOption method.
@see #setOption
*/
public
void activateOptions() {
this.setDestination(this.host, this.port, this.encoding);
}
/**
Returns the option names for this component, namely the string
array consisting of {{@link #DATAGRAM_HOST_OPTION}, {@link
#DATAGRAM_PORT_OPTION}, {@link #DATAGRAM_ENCODING_OPTION} */
public
String[] getOptionStrings() {
return OptionConverter.concatanateArrays(super.getOptionStrings(),
new String[] {
DATAGRAM_HOST_OPTION,
DATAGRAM_PORT_OPTION,
DATAGRAM_ENCODING_OPTION});
}
/**
The DatagramStringAppender requires a layout. Hence, this method return
<code>true</code>.
@since 0.8.4 */
public
boolean requiresLayout() {
return true;
}
/**
Set DatagramStringAppender specific parameters.
<p>
The recognized options are <b>DatagramHost</b>, <b>DatagramPort</b> and
<b>DatagramEncoding</b>, i.e. the values of the string constants
{@link #DATAGRAM_HOST_OPTION}, {@link #DATAGRAM_PORT_OPTION} and
{@link #DATAGRAM_ENCODING_OPTION} respectively.
<p>
<dl>
<p>
<dt><b>DatagramHost</b>
<dd>
The name (or ip address) of the host machine where log output should go.
If the DatagramHost is not set, then this appender will default to
{@link #DEFAULT_HOST}.
<p>
<dt><b>DatagramPort</b>
<dd>
The UDP port number where log output should go. See {@link #DEFAULT_PORT}
<p>
<dt><b>DatagramEncoding</b>
<dd>
The ISO character encoding to be used when converting the Unicode
message to a sequence of bytes within a UDP packet. If not defined, then
the encoding defaults to the default platform encoding.
</dl>
*/
public
void setOption(String option, String value) {
if(value == null) return;
super.setOption(option, value);
if(option.equals(DATAGRAM_HOST_OPTION))
{
this.host = value;
}
else if(option.equals(DATAGRAM_PORT_OPTION))
{
this.port = OptionConverter.toInt(value, DEFAULT_PORT);
}
else if(option.equals(DATAGRAM_ENCODING_OPTION))
{
this.encoding = value;
}
}
public
void setDestination(String host, int port, String encoding) {
if (host==null) {
LogLog.error("setDestination: host is null");
host = DEFAULT_HOST;
}
this.host = host;
this.port = port;
this.encoding = encoding;
this.qw = new QuietWriter(
new DatagramStringWriter(host, port, encoding),
errorHandler);
this.stp = new SingleLineTracerPrintWriter(qw);
}
public
void setLayout(Layout layout) {
this.layout = layout;
}
}

View File

@ -0,0 +1,173 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.net;
import java.io.Writer;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.DatagramPacket;
import java.net.UnknownHostException;
import java.net.SocketException;
import java.io.IOException;
import org.apache.log4j.helpers.LogLog;
/**
* DatagramStringWriter is a wrapper around the java.net.DatagramSocket class
* so that it behaves like a java.io.Writer.
*/
public class DatagramStringWriter extends Writer {
static final int SYSLOG_PORT = 514;
private int port;
private String host;
private String encoding;
private String prefix;
private InetAddress address;
private DatagramSocket ds;
/**
* This constructor assumes that it is sending to a remote syslog daemon
* on the normal syslog port (514), and uses the default platform character
* encoding when converting the message string to a byte sequence.
*/
public
DatagramStringWriter(String host) {
this(host, SYSLOG_PORT, null, null);
}
/**
* This constructor sends messages to the specified host and port, and
* uses the default platform character encoding when converting the message
* string to a byte sequence.
*/
public
DatagramStringWriter(String host, int port) {
this(host, port, null, null);
}
/**
* This constructor sends messages to the specified host and port, and
* uses the specified character encoding when converting the message
* string to a byte sequence.
*/
public
DatagramStringWriter(String host, int port, String encoding) {
this(host, port, null, null);
}
/**
* This constructor sends messages to the specified host and port, and
* uses the specified character encoding when converting the message
* string to a byte sequence; the specified prefix (which may be null)
* is prepended to each message.
*/
public
DatagramStringWriter(String host, int port, String encoding, String prefix) {
this.host = host;
this.port = port;
this.encoding = encoding;
this.prefix = prefix;
try {
this.address = InetAddress.getByName(host);
}
catch (UnknownHostException e) {
LogLog.error("Could not find " + host +
". All logging will FAIL.", e);
}
try {
this.ds = new DatagramSocket();
}
catch (SocketException e) {
e.printStackTrace();
LogLog.error("Could not instantiate DatagramSocket to " + host +
". All logging will FAIL.", e);
}
}
public
void write(char[] buf, int off, int len) throws IOException {
this.write(new String(buf, off, len));
}
public
void write(String string) throws IOException {
if (prefix != null) {
string = prefix + string;
}
byte[] rawData;
if (this.encoding == null)
{
// convert to byte sequence using platform's default encoding
rawData = string.getBytes();
}
else
{
// convert to specified encoding - which may be sequence of
// 8-bit chars, or multi-byte encodings like UTF-8 or UTF-16.
// The receiving end had better be expecting whatever encoding
// is used here on the sending end!
rawData = string.getBytes(encoding);
}
DatagramPacket packet =
new DatagramPacket(
rawData,
rawData.length,
address,
port);
if(this.ds != null)
{
ds.send(packet);
}
else
{
LogLog.error(
"write: failed to create DatagramPacket");
}
}
public
void flush() {}
public
void close() {}
/**
* Set a string to be prefixed to every message sent by this Writer.
* For example, this method could be used to prepend a syslog
* facility/priority code on the front of each message.
* <p>
* Note that this method is not synchronised, so should not be called in
* a situation where other threads may be logging messages at the same
* moment.
* <p>
* @param prefix may be a prefix string, or null which indicates no
* prefix should be added.
*/
public
void setPrefix(String prefix){
this.prefix = prefix;
}
}

View File

@ -0,0 +1,67 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.helpers;
/**
SingleLineTracerPrintWriter overrides the println function in
TracerPrintWriter by replacing the TAB character with spaces.
It also does not print the "\n".
<p>
The default format generated by TracerPrintWriter for exceptions
prints on multiple lines, which does not interact well with some
logging systems. On the other hand, a stack-trace on one line can be a
mite difficult to read, so this class should only be used where really
necessary :-)
<p>
For syslog daemons, tabs in messages are not friendly, hence the
replacement of tabs by spaces here. It shouldn't do any harm to
do this for all messages...
<p>
Perhaps it might be better to enhance TracerPrintWriter to have
a configuration item for one-line or multi-line mode...
*/
public class SingleLineTracerPrintWriter extends TracerPrintWriter {
static String TAB = " ";
public SingleLineTracerPrintWriter(QuietWriter qWriter) {
super(qWriter);
}
/**
Make the first Exception line print properly by omitting the \n at the
end.
*/
public
void println(Object o) {
this.qWriter.write(o.toString());
}
// Note: the Char[] form is handled by the TracerPrinterWriter super
// class
/**
Remove the first character from the string (usually a TAB) and do
not print "\n"
*/
public
void println(String s) {
// remove '^I' and replace it with 4 spaces
this.qWriter.write(TAB+s.substring(1));
}
}

View File

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<configuration configDebug="true">
<appender name="STDOUT" class="org.apache.log4j.FileAppender">
<param name="File" value="System.out" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="aa:%p#%d#%c#%m%n"/>
</layout>
</appender>
<appender name="UDPVENUS" class="org.apache.log4j.net.DatagramStringAppender">
<param name="DatagramHost" value="Venus" />
<param name="DatagramPort" value="8300" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="%p#%d#%c#%m"/>
</layout>
<filter class="org.apache.log4j.filters.PriorityRangeFilter">
<param name="PriorityMin" value="WARN" />
</filter>
</appender>
<category name="org.apache.log4j.xml">
<priority value="INFO" />
</category>
<category name="ch">
<priority value ="DEBUG2" class="ch.orange.log.Priority"/>
</category>
<category name="script">
<priority value ="DEBUG2" class="ch.orange.log.Priority"/>
</category>
<root>
<priority value ="DEBUG2" class="ch.orange.log.Priority"/>
<appender-ref ref="STDOUT" />
<appender-ref ref="UDPVENUS" />
</root>
</configuration>

View File

@ -0,0 +1,107 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
Delivered-To: urba-cgu@urbanet.ch
Mailing-List: contact log4j-dev-help@jakarta.apache.org; run by ezmlm
List-Post: <mailto:log4j-dev@jakarta.apache.org>
List-Help: <mailto:log4j-dev-help@jakarta.apache.org>
List-Unsubscribe: <mailto:log4j-dev-unsubscribe@jakarta.apache.org>
List-Subscribe: <mailto:log4j-dev-subscribe@jakarta.apache.org>
Reply-To: "LOG4J Developers Mailing List" <log4j-dev@jakarta.apache.org>
Delivered-To: mailing list log4j-dev@jakarta.apache.org
From: Kitching Simon <Simon.Kitching@orange.ch>
To: "'log4j-dev@jakarta.apache.org'" <log4j-dev@jakarta.apache.org>
Subject: PATCH: New classes: DatagramStreamAppender & friends
Date: Wed, 7 Feb 2001 12:41:54 +0100
X-Mailer: Internet Mail Service (5.5.2650.21)
X-Spam-Rating: h31.sny.collab.net 1.6.2 0/1000/N
Hi log4j developers....
Here, for your consideration, is a set of files that
implement an Appender which sends messages
to a remote host/port via UDP (datagram).
There was brief discussion of this Appender on the
log4j-user group, about a week ago. Ceki suggested
that the Appender send serialized log event objects
over UDP; while this approach has a number of
advantages, I have decided to instead perform the
message formatting at the client end, mainly so
that:
(a) the UDP server application does not have to be in java
(b) non-java clients can send messages to the same UDP
server.
The appender has been named "DatagramStringAppender"
to allow someone to write a serialization-based version at
some later time, if desired, without any name confusion.
------------------------------
Notes:
DatagramStringAppender is based on SyslogAppender, but
with a fair number of changes.
DatagramStringWriter is based on SyslogWriter, with a few changes.
In particular, it takes an "encoding" parameter, so that the character
encoding used can be specified, and a "port".
SingleLineTracerPrintWriter is almost identical to
SyslogTracerPrintWriter; just the name & some comments
have changed. [I didn't want to call a class called SyslogXXX
from the DatagramStreamAppender classes]
------------------------------
If this patch is accepted, then it may be worth rewriting SyslogAppender
to use the DatagramStringWriter and SingleLineTracerPrintWriter
classes. These classes should be compatible with SyslogAppender,
as they implement the same functionality, or a superset of the
Syslog functionality, and have more "general" names.
------------------------------
<<DatagramStringAppender.java>>
<<DatagramStringWriter.java>>
<<SingleLineTracerPrintWriter.java>>
--------------------------------
And here's a simple perl UDP server, and an xml
config file for testing the appender.
<<logconfig.xml>>
<<udpserver.pl>>
Regards,
Simon

View File

@ -0,0 +1,82 @@
#!/opt/perl5/bin/perl -w
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
use strict;
use Socket;
use IO::Socket;
use Sys::Hostname;
main();
exit(0);
sub main()
{
my $MAX_MSG_SIZE = 16384; # 16KBytes should be enough...
my $svrport = 8300;
my $svriaddr = gethostbyname(hostname());
my $svrproto = getprotobyname('udp');
my $svrpaddr = sockaddr_in($svrport, $svriaddr);
socket(SOCKET, PF_INET, SOCK_DGRAM, $svrproto) || die "socket: $!";
bind(SOCKET, $svrpaddr) || die "bind: $!";
my $rin = '';
vec($rin, fileno(SOCKET), 1) = 1;
# timeout after 10.0 seconds
# at some time, I'm going to add signal handlers so that signals can be
# sent to cause logfile rollover, or tidy exit...then the timeout will
# come in useful..
my $exit = 0;
while (!$exit)
{
my $rout = $rin;
# select(readvec, writevec, exceptionvec, timeout)
# : returns # of selected filehandles, modifies
# vector parameters so that set bits indicate
# filehandles which are readable, writable or have
# an exception state
my $nSelected = select($rout, undef, undef, 10.0);
if ($nSelected == 0)
{
# timedout : go back to start of loop
next;
}
my $msgData = '';
my $clientpaddr = recv(SOCKET, $msgData, $MAX_MSG_SIZE, 0);
if (!$clientpaddr)
{
die "recv: $!";
}
my ($clientport, $clientiaddr) = sockaddr_in($clientpaddr);
my $clienthost = gethostbyaddr($clientiaddr, AF_INET);
if (!$clienthost)
{
# unable to determine name for client : show raw ip address
$clienthost = inet_ntoa($clientiaddr);
}
print "$clienthost:$msgData\n";
}
}

View File

@ -0,0 +1,198 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j;
import java.io.File;
import java.io.Writer;
import java.io.FileWriter;
import java.io.BufferedWriter;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.spi.ErrorHandler;
/**
TempFileAppender creates new unique file for each logging statement.
@author <a HREF="mailto:leos.literak@12snap.com">Leos Literak</a>
@author Ceki G&uuml;lc&uuml;
*/
public class TempFileAppender extends AppenderSkeleton {
/**
A string constant used in naming the option for setting the
directory where the log files will be created. Current value
of this string constant is <b>Path</b>. java.io.tmpdir directory
will be used, if ommited.
*/
static final public String PATH_OPTION = "Path";
/**
The default path is actual directory.
*/
protected String path = null;
/**
A string constant used in naming the option for setting the
prefix of the log files. It has to have at least 3 characters!
Current value of this string constant is <b>Prefix</b>.
*/
static final public String PREFIX_OPTION = "Prefix";
/**
The default path is actual directory.
*/
protected String prefix = "l4j_";
/**
A string constant used in naming the option for setting the
suffix of the log files. Current value of this string constant
is <b>Suffix</b>.
*/
static final public String SUFFIX_OPTION = "Suffix";
/**
The default path is actual directory.
*/
protected String suffix = ".tmp";
/**
Default dir
*/
protected File dir = null;
/**
The default constructor simply calls its parent's constructor.
*/
public TempFileAppender() {
super();
}
/**
Retuns the option names for this component
*/
public String[] getOptionStrings() {
return OptionConverter.concatanateArrays(super.getOptionStrings(),
new String[] {PATH_OPTION,PREFIX_OPTION,SUFFIX_OPTION});
}
/**
Set TempFileAppender specific options.
The recognized options are <b>Path</b>, <b>Prefix</b> and <b>Suffix</b>,
i.e. the values of the string constants {@link #PATH_OPTION},
{@link #PREFIX_OPTION} and respectively {@link #SUFFIX_OPTION}.
The options of the super class {@link AppenderSkeleton} are also
recognized.
*/
public void setOption(String key, String value) {
super.setOption(key, value);
if(key.equalsIgnoreCase(PATH_OPTION)) {
path = value;
if(path==null) {
errorHandler.error("Path cannot be empty!",null,0);
}
dir = new File(path);
if(!(dir.exists() && dir.isDirectory() && dir.canWrite())) {
errorHandler.error("Cannot write to directory " + path + "!",null,0);
}
}
else if(key.equalsIgnoreCase(PREFIX_OPTION)) {
if(value!=null && value.length()>=3) {
prefix = value;
} else {
errorHandler.error("Prefix cannot be shorter than 3 characters!",
null,0);
}
}
else if(key.equalsIgnoreCase(SUFFIX_OPTION)) {
if(value!=null && value.length()>=1) {
suffix = value;
} else {
errorHandler.error("Suffix cannot be empty!",null,0);
}
}
}
/**
This method is called by {@link AppenderSkeleton#doAppend}
method.
<p>Whenever this method is called, new unique file is created
with specified prefix and suffix. The file is closed afterwards.
<p>The format of the output will depend on this appender's
layout.
*/
public void append(LoggingEvent event) {
if(!checkEntryConditions()) {
return;
}
subAppend(event);
}
/**
This method determines if there is a sense in attempting to append.
*/
protected boolean checkEntryConditions() {
return true;
}
/**
This method does actual writing
*/
protected void subAppend(LoggingEvent event) {
try {
File tmp = File.createTempFile(prefix,suffix,dir);
Writer out = new BufferedWriter(new FileWriter(tmp));
out.write(event.message);
out.close();
/* this Appender is not supposed to be used for logging of Exceptions */
} catch (Exception e) {
errorHandler.error("Error during creation of temporary File!",e,1);
}
}
public boolean requiresLayout() {
return false;
}
public void close() {
/* nothing to do */
}
}
/*
* @author $Author: carnold $
* @version $Revision: 511036 $
* @since $Date: 2007-02-23 11:48:53 -0600 (Fri, 23 Feb 2007) $
*
* $Log$
* Revision 1.1.2.1 2005/05/27 03:27:54 mwomack
* Fix for #35032. Added license header to .java files that did not already have a license.
*
* Revision 1.1 2001/04/20 17:38:31 ceki
*
* Added LeosLiterak's TempFileAppender.java
*
*/

View File

@ -0,0 +1,58 @@
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
To: ceki@apache.org
Subject: TempFileAppender
Hi Ceki,
I have created one small Appender, which puts each
logging statement into separate file. We use it
for storing incomming messages into second process'es
spool directory. If you like it, please include it
into Log4j with APL license.
Usage:
log4j.appender.A1=org.apache.log4j.TempFileAppender
log4j.appender.A1.Path=spool_dir
log4j.appender.A1.Prefix=out_
log4j.appender.A1.Suffix=.msg
Leo
-----------------------------------------------------
Leos Literak
Software Engineer
12snap s.r.o.
Pstrossova 24
110 00 Praha 1
Czech Republic
mobile: ?605-849-087
phone: ?2-21-970-239
fax: ?2-21-970-241
e-mail: leos.literak@12snap.com

View File

@ -0,0 +1,33 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
INFO ( Server:main ) systemsunion.LoggingServer.SocketServer2 - Connected to client at RDDSOWE2/129.153.78.195
INFO ( Server:main ) systemsunion.LoggingServer.SocketServer2 - Starting new socket node.
INFO ( Server:main ) systemsunion.LoggingServer.SocketServer2 - Waiting to accept a new client.
INFO ( RDDSOWE2:main ) systemsunion.SSTS.system - ClosedownController: starting
INFO ( Server:main ) systemsunion.LoggingServer.SocketServer2 - Connected to client at RDDSOWE2/129.153.78.195
INFO ( Server:main ) systemsunion.LoggingServer.SocketServer2 - Starting new socket node.
INFO ( Server:main ) systemsunion.LoggingServer.SocketServer2 - Waiting to accept a new client.
INFO ( RDDSOWE2:main ) systemsunion.SSTS.system - ClosedownController: starting
INFO ( RDDSOWE2:AWT-EventQueue-0) systemsunion.SSTS.components - Packing component Operator
INFO ( RDDSOWE2:AWT-EventQueue-0) systemsunion.SSTS.components - Packing class file d:/SSDev/SSTS/components\Operator\Operator.class for component Operator
INFO ( RDDSOWE2:AWT-EventQueue-0) systemsunion.SSTS.components - Packing class file d:/SSDev/SSTS/components\Operator\Operator.class for component Operator
INFO ( RDDSOWE2:AWT-EventQueue-0) systemsunion.SSTS.components - Packing proxy class file d:/SSDev/SSTS/components\Operator\OperatorProxy.class for component Operator
INFO ( RDDSOWE2:AWT-EventQueue-0) systemsunion.SSTS.components - Packing class file d:/SSDev/SSTS/components\Operator\OperatorProxy.class for component Operator
INFO ( RDDSOWE2:AWT-EventQueue-0) systemsunion.SSTS.components - Packing test XML page file d:/SSDev/SSTS/components\Operator\Operator.XML for component Operator
INFO ( RDDSOWE2:AWT-EventQueue-0) systemsunion.SSTS.components - Packing class file d:/SSDev/SSTS/components\Operator\Operator.XML for component Operator
INFO ( RDDSOWE2:AWT-EventQueue-0) systemsunion.SSTS.components - Packing descriptor file d:/SSDev/SSTS/components\Operator\OperatorDeploymentDescriptor.XML for component Operator
INFO ( RDDSOWE2:AWT-EventQueue-0) systemsunion.SSTS.components - Packing class file d:/SSDev/SSTS/components\Operator\OperatorDeploymentDescriptor.XML for component Operator

View File

@ -0,0 +1,118 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.systemsunion.LoggingServer;
import java.net.InetAddress;
import java.net.Socket;
import java.net.ServerSocket;
import java.io.InputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import org.apache.log4j.Category;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.Priority;
import org.apache.log4j.NDC;
// Contributors: Moses Hohman <mmhohman@rainbow.uchicago.edu>
/**
Read {@link LoggingEvent} objects sent from a remote client using
Sockets (TCP). These logging events are logged according to local
policy, as if they were generated locally.
<p>For example, the socket node might decide to log events to a
local file and also resent them to a second socket node.
@author Ceki G&uuml;lc&uuml;
@since 0.8.4
*/
public class SocketNode2 implements Runnable {
Socket socket;
ObjectInputStream ois;
static Category cat = Category.getInstance(SocketNode2.class.getName());
public
SocketNode2(Socket socket) {
this.socket = socket;
try {
ois = new ObjectInputStream(socket.getInputStream());
}
catch(Exception e) {
cat.error("Could not open ObjectInputStream to "+socket, e);
}
}
//public
//void finalize() {
//System.err.println("-------------------------Finalize called");
// System.err.flush();
//}
public void run() {
LoggingEvent event;
Category remoteCategory;
String strClientName;
// Get the client name.
InetAddress addr = socket.getInetAddress();
strClientName = addr.getHostName();
if(strClientName == null || strClientName.length() == 0)
{
strClientName = addr.getHostAddress();
}
try {
while(true) {
event = (LoggingEvent) ois.readObject();
if(event.ndc != null)
{
event.ndc = strClientName + ":" + event.ndc;
}
else
{
event.ndc = strClientName;
}
remoteCategory = Category.getInstance(event.categoryName);
remoteCategory.callAppenders(event);
}
}
catch(java.io.EOFException e) {
cat.info("Caught java.io.EOFException will close conneciton.", e);
}
catch(java.net.SocketException e) {
cat.info("Caught java.net.SocketException, will close conneciton.", e);
}
catch(Exception e) {
cat.error("Unexpected exception. Closing conneciton.", e);
}
try {
ois.close();
}
catch(Exception e) {
cat.info("Could not close connection.", e);
}
}
}

View File

@ -0,0 +1,99 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.systemsunion.LoggingServer;
import java.net.Socket;
import java.net.ServerSocket;
import java.io.IOException;
import org.apache.log4j.Category;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.NDC;
/**
A simple {@link SocketNode} based server.
<pre>
<b>Usage:</b> java org.apache.log4j.net.SocketServer port configFile
where <em>port</em> is a part number where the server listens and
<em>configFile</em> is a configuration file fed to the {@link
PropertyConfigurator}.
</pre>
@author Ceki G&uuml;lc&uuml;
@since 0.8.4 */
public class SocketServer2 {
static Category cat = Category.getInstance(SocketServer2.class.getName());
static int port;
public
static
void main(String argv[]) {
if(argv.length == 2)
init(argv[0], argv[1]);
else
usage("Wrong number of arguments.");
try {
cat.info("Listening on port " + port);
ServerSocket serverSocket = new ServerSocket(port);
while(true) {
cat.info("Waiting to accept a new client.");
Socket socket = serverSocket.accept();
cat.info("Connected to client at " + socket.getInetAddress());
cat.info("Starting new socket node.");
new Thread(new SocketNode2(socket)).start();
}
}
catch(Exception e) {
e.printStackTrace();
}
}
static
void usage(String msg) {
System.err.println(msg);
System.err.println(
"Usage: java " + SocketServer2.class.getName() + " port configFile");
System.exit(1);
}
static
void init(String portStr, String configFile) {
try {
port = Integer.parseInt(portStr);
}
catch(java.lang.NumberFormatException e) {
e.printStackTrace();
usage("Could not interpret port number ["+ portStr +"].");
}
PropertyConfigurator.configure(configFile);
NDC.push("Server");
}
}

View File

@ -0,0 +1,66 @@
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Delivered-To: urba-cgu@urbanet.ch
From: Mark Douglas <Mark_Douglas@systemsunion.com>
To: "'cgu@urbanet.ch'" <cgu@urbanet.ch>
Subject: Enhanced SocketServer and SocketNode classes
Date: Wed, 17 Jan 2001 09:57:38 -0000
X-Mailer: Internet Mail Service (5.5.2650.21)
Hi Ceki,
I have made small changes to SocketServer and SockerNode to allow the client
machine name to be displayed in the logging output. This is important for
us as we are using a single logging server with several clients.
The new SocketServer2 and SocketNode2 classes (couldn't think of better
names) prepends the NDC string with the clients Host Name (or IP address if
the HostName can not be found). I thought the NDC string was a good place
to add this information, but you may have a better place?
I have created an NDC entry for the server such that server logging messages
can easily be identified.
I have included the two new source files plus a short example of the output.
The output was generated with the following layout: %-6p (%9x:%-10t)
%-40c{3} - %m%n
<<Log.txt>> <<SocketNode2.java>> <<SocketServer2.java>>
Note: I have changed the package names for the two classes to fit with our
package names - sorry. Also, I find it difficult to follow the coding
style, so again, sorry.
If you think this may be useful to others, please feel free to include it as
an addition in the next release or change the current SocketServer and
SocketNode objects to include this new behaviour by default.
Mark Douglas
Systems Union Group plc

View File

@ -0,0 +1,365 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.gui;
import org.apache.log4j.helpers.CyclicBuffer;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.Priority;
import org.apache.log4j.Category;
import org.apache.log4j.Layout;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.spi.LoggingEvent;
import javax.swing.JList;
import javax.swing.AbstractListModel;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import javax.swing.BoxLayout;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Container;
import javax.swing.ImageIcon;
import java.awt.Image;
import java.awt.Toolkit;
import java.net.URL;
import java.awt.Rectangle;
public class JListView extends JList {
static Category cat = Category.getInstance(JListView.class.getName());
//JListViewModel model;
PatternLayout layout;
static LoggingEvent proto = new LoggingEvent("x", cat, Priority.ERROR,
"Message ", new Throwable());
public
JListView(JListViewModel model) {
super(model);
layout = new PatternLayout("%r %p %c [%t] - %m");
//this.setModel(model);
this.setCellRenderer(new MyCellRenderer());
// setFixedCellWidth(10);
//setFixedCellHeight(20);
}
public
void add(LoggingEvent event) {
((JListViewModel)getModel()).add(event);
}
/*
public
Dimension getPreferredSize() {
System.out.println("getPreferredSize() called");
return super.getPreferredSize();
}
public
int getScrollableUnitIncrement(Rectangle visibleRect, int orientation,
int direction) {
System.out.println("getScrollableUnitIncrement called with " + visibleRect +
"orientation: "+orientation+", direction: "+direction);
return super.getScrollableUnitIncrement(visibleRect, orientation,
direction);
}
public
int getScrollableBlockIncrement(Rectangle visibleRect, int orientation,
int direction) {
System.out.println("getScrollableBlockIncrement called with " +
visibleRect + "orientation: "+orientation+
", direction: "+direction);
return super.getScrollableBlockIncrement(visibleRect, orientation,
direction);
}
*/
//public
//boolean getScrollableTracksViewportWidth() {
//System.out.println("getScrollableTracksViewportWidth called.");
//return true;
//boolean b = super.getScrollableTracksViewportWidth();
//System.out.println("result is: "+b);
//return b;
//}
//public
//boolean getScrollableTracksViewportHeight() {
// System.out.println("getScrollableTracksViewportHeight called.");
// return true;
//boolean b = super.getScrollableTracksViewportHeight();
//System.out.println("result is: "+b);
//return b;
//}
//public
//int getFirstVisibleIndex() {
//int r = getFirstVisibleIndex();
// System.out.println("----------getFirstVisibleIndex called, result: "+r);
//return r;
//}
//public
//Object getPrototypeCellValue() {
//return proto;
//}
static public void main(String[] args) {
JFrame frame = new JFrame("JListView test");
Container container = frame.getContentPane();
JListView view = new JListView(new JListViewModel(Integer.parseInt(args[0])));
JScrollPane sp = new JScrollPane(view);
sp.setPreferredSize(new Dimension(250, 80));
container.setLayout(new BoxLayout(container, BoxLayout.X_AXIS));
//container.add(view);
container.add(sp);
JButton b1 = new JButton("Add 1");
JButton b10 = new JButton("Add 10");
JButton b100 = new JButton("Add 100");
JButton b1000 = new JButton("Add 1000");
JButton b10000 = new JButton("Add 10000");
JPanel panel = new JPanel(new GridLayout(0,1));
container.add(panel);
panel.add(b1);
panel.add(b10);
panel.add(b100);
panel.add(b1000);
panel.add(b10000);
AddAction a1 = new AddAction(view, 1);
AddAction a10 = new AddAction(view, 10);
AddAction a100 = new AddAction(view, 100);
AddAction a1000 = new AddAction(view, 1000);
AddAction a10000 = new AddAction(view, 10000);
b1.addActionListener(a1);
b10.addActionListener(a10);
b100.addActionListener(a100);
b1000.addActionListener(a1000);
b10000.addActionListener(a10000);
frame.setVisible(true);
frame.setSize(new Dimension(700,700));
long before = System.currentTimeMillis();
int RUN = 1000;
int i = 0;
while(i++ < RUN) {
LoggingEvent event0 = new LoggingEvent("x", cat, Priority.ERROR,
"Message "+i, null);
Throwable t = new Exception("hello "+i);
LoggingEvent event1 = new LoggingEvent("x", cat, Priority.ERROR,
"Message "+i, t);
if(i % 10 == 0) {
event1.getThreadName();
view.add(event1);
} else {
event0.getThreadName();
view.add(event0);
}
}
long after = System.currentTimeMillis();
System.out.println("Time taken :"+ ((after-before)*1000/RUN));
}
class MyCellRenderer extends JTextArea implements ListCellRenderer {
Object o = new Object();
int i = 0;
final ImageIcon longIcon = new ImageIcon("RedFlag.gif");
public
MyCellRenderer() {
System.out.println("----------------------");
}
public
int getTabSize() {
return 2;
}
public Image loadIcon ( String path ) {
Image img = null;
try {
URL url = ClassLoader.getSystemResource(path);
img = (Image) (Toolkit.getDefaultToolkit()).getImage(url);
} catch (Exception e) {
System.out.println("Exception occured: " + e.getMessage() +
" - " + e );
}
return (img);
}
public Component getListCellRendererComponent(JList list,
Object value,
int index, // cell index
boolean isSelected,
boolean cellHasFocus) {
// System.out.println(o + " ============== " + i++);
//LogLog.error("=======", new Exception());
//setIcon(longIcon);
if(value instanceof LoggingEvent) {
LoggingEvent event = (LoggingEvent) value;
String str = layout.format(event);
String t = event.getThrowableInformation();
if(t != null) {
setText(str + Layout.LINE_SEP + t);
} else {
setText(str);
}
} else {
setText(value.toString());
}
return this;
}
}
}
class JListViewModel extends AbstractListModel {
CyclicBuffer cb;
JListViewModel(int size) {
cb = new CyclicBuffer(size);
}
public
void add(LoggingEvent event) {
//System.out.println("JListViewModel.add called");
cb.add(event);
int j = cb.length();
fireContentsChanged(this, 0, j);
}
public
Object getElementAt(int index) {
return cb.get(index);
}
public
int getSize() {
return cb.length();
}
}
class AddAction implements ActionListener {
Thread t;
static int counter = 0;
public
AddAction(JListView view, int burst) {
this.t = new AddThread(view, burst);
t.start();
}
public
void actionPerformed(ActionEvent e) {
System.out.println("Action occured");
synchronized(t) {
t.notify();
}
}
class AddThread extends Thread {
int burst;
JListView view;
Category cat = Category.getInstance("x");
AddThread(JListView view, int burst) {
super();
this.burst = burst;
this.view = view;
setName("AddThread"+burst);
}
public
void run() {
while(true) {
synchronized(this) {
try {
this.wait();
} catch(Exception e) {
}
}
for(int i = 0; i < burst; i++) {
LoggingEvent event = new LoggingEvent("x", cat, Priority.DEBUG,
"Message "+counter, null);
event.getThreadName();
if(counter % 50 == 0) {
//event.throwable = new Exception("hello "+counter);
}
counter++;
view.add(event);
}
}
}
}
}

View File

@ -0,0 +1,237 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.gui;
import org.apache.log4j.helpers.CyclicBuffer;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.Priority;
import org.apache.log4j.Category;
import org.apache.log4j.Layout;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.spi.LoggingEvent;
import javax.swing.JList;
import javax.swing.AbstractListModel;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import java.awt.Component;
import java.awt.FlowLayout;
import javax.swing.BoxLayout;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Container;
import javax.swing.ImageIcon;
import java.awt.Image;
import java.awt.Toolkit;
import java.net.URL;
import java.awt.Rectangle;
public class JTableAppender extends JTable {
static Category cat = Category.getInstance(JTableAppender.class.getName());
PatternLayout layout;
public
JTableAppender() {
layout = new PatternLayout("%r %p %c [%t] - %m");
this.setDefaultRenderer(Object.class, new Renderer());
}
public
void add(LoggingEvent event) {
((JTableAppenderModel)getModel()).add(event);
}
public
Dimension getPreferredSize() {
System.out.println("getPreferredSize() called");
return super.getPreferredSize();
}
static public void main(String[] args) {
JFrame frame = new JFrame("JListView test");
Container container = frame.getContentPane();
JTableAppender appender = new JTableAppender();
JTableAppenderModel model = new
JTableAppenderModel(Integer.parseInt(args[0]));
appender.setModel(model);
//appender.createDefaultColumnsFromModel();
JScrollPane sp = new JScrollPane(appender);
sp.setPreferredSize(new Dimension(250, 80));
container.setLayout(new BoxLayout(container, BoxLayout.X_AXIS));
//container.add(view);
container.add(sp);
JButton button = new JButton("ADD");
container.add(button);
button.addActionListener(new JTableAddAction(appender));
frame.setVisible(true);
frame.setSize(new Dimension(700,700));
long before = System.currentTimeMillis();
int RUN = 10000;
int i = 0;
while(i++ < RUN) {
LoggingEvent event = new LoggingEvent("x", cat, Priority.ERROR,
"Message "+i, null);
event.getThreadName();
if(i % 10 == 0) {
//event.throwable = new Exception("hello "+i);
}
appender.add(event);
}
long after = System.currentTimeMillis();
System.out.println("Time taken :"+ ((after-before)*1000/RUN));
}
class Renderer extends JTextArea implements TableCellRenderer {
Object o = new Object();
int i = 0;
public
Renderer() {
System.out.println("Render() called ----------------------");
}
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
System.out.println(o + " ============== " + i++);
//LogLog.error("=======", new Exception());
//setIcon(longIcon);
if(value instanceof LoggingEvent) {
LoggingEvent event = (LoggingEvent) value;
String str = layout.format(event);
String t = event.getThrowableInformation();
if(t != null) {
System.out.println("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee");
setText(str + Layout.LINE_SEP + t);
} else {
setText(str);
}
} else {
setText(value.toString());
}
return this;
}
}
}
class JTableAppenderModel extends AbstractTableModel {
CyclicBuffer cb;
JTableAppenderModel(int size) {
cb = new CyclicBuffer(size);
}
public
void add(LoggingEvent event) {
//System.out.println("JListViewModel.add called");
cb.add(event);
int j = cb.length();
fireTableDataChanged();
}
public
int getColumnCount() {
return 1;
}
public int getRowCount() {
return cb.length();
}
//public
//Class getColumnClass(int index) {
// System.out.println("getColumnClass called " + index);
// return LoggingEvent.class;
//}
public
Object getValueAt(int row, int col) {
return cb.get(row);
}
}
class JTableAddAction implements ActionListener {
int j;
JTableAppender appender;
Category cat = Category.getInstance("x");
public
JTableAddAction(JTableAppender appender) {
this.appender = appender;
j = 0;
}
public
void actionPerformed(ActionEvent e) {
System.out.println("Action occured");
LoggingEvent event = new LoggingEvent("x", cat, Priority.DEBUG,
"Message "+j, null);
if(j % 5 == 0) {
//event.throwable = new Exception("hello "+j);
}
j++;
appender.add(event);
}
}

View File

@ -0,0 +1,355 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.gui;
import java.awt.Color;
import java.awt.Image;
import java.awt.Toolkit;
import java.io.*;
import java.net.URL;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.util.Hashtable;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JTextPane;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import javax.swing.text.TabSet;
import javax.swing.text.TabStop;
import org.apache.log4j.*;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.helpers.Loader;
import org.apache.log4j.helpers.QuietWriter;
import org.apache.log4j.helpers.TracerPrintWriter;
import org.apache.log4j.helpers.OptionConverter;
/**
* <b>Experimental</b> TextPaneAppender. <br>
*
*
* Created: Sat Feb 26 18:50:27 2000 <br>
*
* @author Sven Reimers
*/
public class TextPaneAppender extends AppenderSkeleton {
JTextPane textpane;
StyledDocument doc;
TracerPrintWriter tp;
StringWriter sw;
QuietWriter qw;
Hashtable attributes;
Hashtable icons;
private String label;
private boolean fancy;
final String LABEL_OPTION = "Label";
final String COLOR_OPTION_FATAL = "Color.Emerg";
final String COLOR_OPTION_ERROR = "Color.Error";
final String COLOR_OPTION_WARN = "Color.Warn";
final String COLOR_OPTION_INFO = "Color.Info";
final String COLOR_OPTION_DEBUG = "Color.Debug";
final String COLOR_OPTION_BACKGROUND = "Color.Background";
final String FANCY_OPTION = "Fancy";
final String FONT_NAME_OPTION = "Font.Name";
final String FONT_SIZE_OPTION = "Font.Size";
public static Image loadIcon ( String path ) {
Image img = null;
try {
URL url = ClassLoader.getSystemResource(path);
img = (Image) (Toolkit.getDefaultToolkit()).getImage(url);
} catch (Exception e) {
System.out.println("Exception occured: " + e.getMessage() +
" - " + e );
}
return (img);
}
public TextPaneAppender(Layout layout, String name) {
this();
this.layout = layout;
this.name = name;
setTextPane(new JTextPane());
createAttributes();
createIcons();
}
public TextPaneAppender() {
super();
setTextPane(new JTextPane());
createAttributes();
createIcons();
this.label="";
this.sw = new StringWriter();
this.qw = new QuietWriter(sw, errorHandler);
this.tp = new TracerPrintWriter(qw);
this.fancy =true;
}
public
void close() {
}
private void createAttributes() {
Priority prio[] = Priority.getAllPossiblePriorities();
attributes = new Hashtable();
for (int i=0; i<prio.length;i++) {
MutableAttributeSet att = new SimpleAttributeSet();
attributes.put(prio[i], att);
StyleConstants.setFontSize(att,14);
}
StyleConstants.setForeground((MutableAttributeSet)attributes.get(Priority.ERROR),Color.red);
StyleConstants.setForeground((MutableAttributeSet)attributes.get(Priority.WARN),Color.orange);
StyleConstants.setForeground((MutableAttributeSet)attributes.get(Priority.INFO),Color.gray);
StyleConstants.setForeground((MutableAttributeSet)attributes.get(Priority.DEBUG),Color.black);
}
private void createIcons() {
Priority prio[] = Priority.getAllPossiblePriorities();
icons = new Hashtable();
for (int i=0; i<prio.length;i++) {
if (prio[i].equals(Priority.FATAL))
icons.put(prio[i],new ImageIcon(loadIcon("icons/RedFlag.gif")));
if (prio[i].equals(Priority.ERROR))
icons.put(prio[i],new ImageIcon(loadIcon("icons/RedFlag.gif")));
if (prio[i].equals(Priority.WARN))
icons.put(prio[i],new ImageIcon(loadIcon("icons/BlueFlag.gif")));
if (prio[i].equals(Priority.INFO))
icons.put(prio[i],new ImageIcon(loadIcon("icons/GreenFlag.gif")));
if (prio[i].equals(Priority.DEBUG))
icons.put(prio[i],new ImageIcon(loadIcon("icons/GreenFlag.gif")));
}
}
public void append(LoggingEvent event) {
String text = this.layout.format(event);
String trace="";
// Print Stacktrace
// Quick Hack maybe there is a better/faster way?
if (event.throwable!=null) {
event.throwable.printStackTrace(tp);
for (int i=0; i< sw.getBuffer().length(); i++) {
if (sw.getBuffer().charAt(i)=='\t')
sw.getBuffer().replace(i,i+1," ");
}
trace = sw.toString();
sw.getBuffer().delete(0,sw.getBuffer().length());
}
try {
if (fancy) {
textpane.setEditable(true);
textpane.insertIcon((ImageIcon)icons.get(event.priority));
textpane.setEditable(false);
}
doc.insertString(doc.getLength(),text+trace,
(MutableAttributeSet)attributes.get(event.priority));
}
catch (BadLocationException badex) {
System.err.println(badex);
}
textpane.setCaretPosition(doc.getLength());
}
public
JTextPane getTextPane() {
return textpane;
}
private
static
Color parseColor (String v) {
StringTokenizer st = new StringTokenizer(v,",");
int val[] = {255,255,255,255};
int i=0;
while (st.hasMoreTokens()) {
val[i]=Integer.parseInt(st.nextToken());
i++;
}
return new Color(val[0],val[1],val[2],val[3]);
}
private
static
String colorToString(Color c) {
// alpha component emitted only if not default (255)
String res = ""+c.getRed()+","+c.getGreen()+","+c.getBlue();
return c.getAlpha() >= 255 ? res : res + ","+c.getAlpha();
}
public
void setLayout(Layout layout) {
this.layout=layout;
}
public
void setName(String name) {
this.name = name;
}
public
void setTextPane(JTextPane textpane) {
this.textpane=textpane;
textpane.setEditable(false);
textpane.setBackground(Color.lightGray);
this.doc=textpane.getStyledDocument();
}
private
void setColor(Priority p, String v) {
StyleConstants.setForeground(
(MutableAttributeSet)attributes.get(p),parseColor(v));
}
private
String getColor(Priority p) {
Color c = StyleConstants.getForeground(
(MutableAttributeSet)attributes.get(p));
return c == null ? null : colorToString(c);
}
/////////////////////////////////////////////////////////////////////
// option setters and getters
public
void setLabel(String label) {
this.label = label;
}
public
String getLabel() {
return label;
}
public
void setColorEmerg(String color) {
setColor(Priority.FATAL, color);
}
public
String getColorEmerg() {
return getColor(Priority.FATAL);
}
public
void setColorError(String color) {
setColor(Priority.ERROR, color);
}
public
String getColorError() {
return getColor(Priority.ERROR);
}
public
void setColorWarn(String color) {
setColor(Priority.WARN, color);
}
public
String getColorWarn() {
return getColor(Priority.WARN);
}
public
void setColorInfo(String color) {
setColor(Priority.INFO, color);
}
public
String getColorInfo() {
return getColor(Priority.INFO);
}
public
void setColorDebug(String color) {
setColor(Priority.DEBUG, color);
}
public
String getColorDebug() {
return getColor(Priority.DEBUG);
}
public
void setColorBackground(String color) {
textpane.setBackground(parseColor(color));
}
public
String getColorBackground() {
return colorToString(textpane.getBackground());
}
public
void setFancy(boolean fancy) {
this.fancy = fancy;
}
public
boolean getFancy() {
return fancy;
}
public
void setFontSize(int size) {
Enumeration e = attributes.elements();
while (e.hasMoreElements()) {
StyleConstants.setFontSize((MutableAttributeSet)e.nextElement(),size);
}
return;
}
public
int getFontSize() {
AttributeSet attrSet = (AttributeSet) attributes.get(Priority.INFO);
return StyleConstants.getFontSize(attrSet);
}
public
void setFontName(String name) {
Enumeration e = attributes.elements();
while (e.hasMoreElements()) {
StyleConstants.setFontFamily((MutableAttributeSet)e.nextElement(),name);
}
return;
}
public
String getFontName() {
AttributeSet attrSet = (AttributeSet) attributes.get(Priority.INFO);
return StyleConstants.getFontFamily(attrSet);
}
public
boolean requiresLayout() {
return true;
}
} // TextPaneAppender

View File

@ -0,0 +1,111 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.log4j.gui.examples;
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
import org.apache.log4j.*;
import org.apache.log4j.gui.*;
public class TextPaneAppenderExample implements ActionListener {
JFrame mainframe;
ButtonGroup priorities;
TextPaneAppender tpa;
Category gui;
Priority prio[];
JTabbedPane logview;
public TextPaneAppenderExample () {
mainframe = new JFrame("Testing the TextPaneAppender...");
mainframe.setSize(300,300);
logview = new JTabbedPane();
createLogger();
createMenuBar();
mainframe.setVisible(true);
mainframe.getContentPane().add(logview);
}
public void createLogger() {
tpa = new TextPaneAppender(new PatternLayout("%-5p %d [%t]: %m%n"),"Debug");
logview.addTab("Events ...",new JScrollPane(tpa.getTextPane()));
gui = Category.getInstance(this.getClass().getName());
gui.addAppender(tpa);
}
public void createMenuBar() {
JMenu file = new JMenu("File");
JMenuItem exit = new JMenuItem("Exit");
exit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
System.exit(0);
}
});
file.add(exit);
JMenuBar mb = new JMenuBar();
mb.add(file);
JMenu logevent = new JMenu("LoggingEvents");
JMenu selectprio = new JMenu("Priority");
prio = Priority.getAllPossiblePriorities();
JRadioButtonMenuItem priority[]= new JRadioButtonMenuItem[prio.length];
priorities = new ButtonGroup();
for (int i=0; i<prio.length;i++) {
if (i==0)
priority[i] = new JRadioButtonMenuItem(prio[i].toString(),true);
else
priority[i] = new JRadioButtonMenuItem(prio[i].toString());
priority[i].setActionCommand(prio[i].toString());
selectprio.add(priority[i]);
priorities.add(priority[i]);
}
logevent.add(selectprio);
JMenuItem lognow = new JMenuItem("LogIt!");
lognow.addActionListener(this);
logevent.add(lognow);
mb.add(logevent);
mainframe.setJMenuBar(mb);
}
public void actionPerformed(ActionEvent ae){
String logtext = JOptionPane.showInputDialog("Text to log");
if (logtext == null) logtext="NO Input";
int i=0;
String name = priorities.getSelection().getActionCommand();
while (!prio[i].toString().equals(name))
i=i+1;
gui.log(prio[i],logtext);
}
static public void main(String args[]) {
TextPaneAppenderExample tpex = new TextPaneAppenderExample();
}
}

View File

@ -0,0 +1,601 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.klopotek.utils.log;
import java.sql.*;
import java.util.*;
import org.apache.log4j.*;
import org.apache.log4j.helpers.*;
import org.apache.log4j.spi.*;
/**
The JDBCAppender, writes messages into a database
<p><b>The JDBCAppender is configurable at runtime by setting options in two alternatives : </b></p>
<dir>
<p><b>1. Use a configuration-file</b></p>
<p>Define the options in a file (<A HREF="configfile_example.txt">example</A>) and call a <code>PropertyConfigurator.configure(filename)</code> in your code.</p>
<p><b>2. Use the methods of JDBCAppender to do it</b></p>
<p>Call <code>JDBCAppender::setOption(JDBCAppender.xxx_OPTION, String value)</code> to do it analogically without a configuration-file (<A HREF="code_example2.java">example</A>)</p>
</dir>
<p>All available options are defined as static String-constants in JDBCAppender named xxx_OPTION.</p>
<p><b>Here is a description of all available options :</b></p>
<dir>
<p><b>1. Database-options to connect to the database</b></p>
<p>- <b>URL_OPTION</b> : a database url of the form jdbc:subprotocol:subname</p>
<p>- <b>USERNAME_OPTION</b> : the database user on whose behalf the connection is being made</p>
<p>- <b>PASSWORD_OPTION</b> : the user's password</p>
<p><b>2. Connector-option to specify your own JDBCConnectionHandler</b></p>
<p>- <b>CONNECTOR_OPTION</b> : a classname which is implementing the JDBCConnectionHandler-interface</p>
<p>This interface is used to get a customized connection.</p>
<p>If in addition the database-options are given, these options will be used as arguments for the JDBCConnectionHandler-interface to get a connection.</p>
<p>Else if no database-options are given, the JDBCConnectionHandler-interface is called without them.</p>
<p>Else if this option is not defined, the database-options are required to open a connection by the JDBCAppender.</p>
<p><b>3. SQL-option to specify a static sql-statement which will be performed with every occuring message-event</b></p>
<p>- <b>SQL_OPTION</b> : a sql-statement which will be used to write to the database</p>
<p>Use the variable <b>@MSG@</b> on a location in the statement, which has to be dynamically replaced by the message-text.</p>
<p>If you give this option, the table-option and columns-option will be ignored !</p>
<p><b>4. Table-option to specify a table contained by the database</b></p>
<p>- <b>TABLE_OPTION</b> : the table in which the logging will be done</p>
<p><b>5. Columns-option to describe the important columns of the table (Not nullable columns are mandatory to describe!)</b></p>
<p>- <b>COLUMNS_OPTION</b> : a formatted list of column-descriptions</p>
<p>Each column description consists of</p>
<dir>
<p>- the <b><i>name</i></b> of the column (required)</p>
<p>- a <b><i>logtype</i></b> which is a static constant of class LogType (required)</p>
<p>- and a <b><i>value</i></b> which depends by the LogType (optional/required, depending by logtype)</p>
</dir>
<p>Here is a description of the available logtypes of class <b>{@link LogType}</b> and how to handle the <b><i>value</i></b>:</p>
<dir>
<p>o <b>MSG</b> = a value will be ignored, the column will get the message. (One columns need to be of this type!)</p>
<p>o <b>STATIC</b> = the value will be filled into the column with every logged message. (Ensure that the type of value can be casted into the sql-type of the column!)</p>
<p>o <b>ID</b> = value must be a classname, which implements the JDBCIDHandler-interface.</p>
<p>o <b>TIMESTAMP</b> = a value will be ignored, the column will be filled with a actually timestamp with every logged message.</p>
<p>o <b>EMPTY</b> = a value will be ignored, the column will be ignored when writing to the database (Ensure to fill not nullable columns by a database trigger!)</p>
</dir>
<p>If there are more than one column to describe, the columns must be separated by a Tabulator-delimiter (unicode0008) !</p>
<p>The arguments of a column-description must be separated by the delimiter '~' !</p>
<p><i>(Example : name1~logtype1~value1 name2~logtype2~value2...)</i></p>
<p><b>6. Layout-options to define the layout of the messages (optional)</b></p>
<p>- <b>_</b> : the layout wont be set by a xxx_OPTION</p>
<p>See the configuration-file and code examples below...</p>
<p>The default is a layout of the class {@link org.apache.log4j.PatternLayout} with the pattern=%m which representate only the message.</p>
<p><b>7. Buffer-option to define the size of the message-event-buffer (optional)</b></p>
<p>- <b>BUFFER_OPTION</b> : define how many messages will be buffered until they will be updated to the database.</p>
<p>The default is buffer=1, which will do a update with every happened message-event.</p>
<p><b>8. Commit-option to define a auto-commitment</b></p>
<p>- <b>COMMIT_OPTION</b> : define whether updated messages should be committed to the database (Y) or not (N).</p>
<p>The default is commit=Y.</p>
</dir>
<p><b>The sequence of some options is important :</b></p>
<dir>
<p><b>1. Connector-option OR/AND Database-options</b></p>
<p>Any database connection is required !</p>
<p><b>2. (Table-option AND Columns-option) OR SQL-option</b></p>
<p>Anything of that is required ! Whether where to write something OR what to write somewhere...;-)</p>
<p><b>3. All other options can be set at any time...</b></p>
<p>The other options are optional and have a default initialization, which can be customized.</p>
</dir>
<p><b>Here is a <b>configuration-file example</b>, which can be used as argument for the <b>PropertyConfigurator</b> : </b><A HREF="configfile_example.txt"> configfile_example.txt</A></p>
<p><b>Here is a <b>code-example</b> to configure the JDBCAppender <b>with a configuration-file</b> : </b><A HREF="code_example1.java"> code_example1.java</A></p>
<p><b>Here is a <b>another code-example</b> to configure the JDBCAppender <b>without a configuration-file</b> : </b><A HREF="code_example2.java"> code_example2.java</A></p>
<p><b>Author : </b><A HREF="mailto:t.fenner@klopotek.de">Thomas Fenner</A></p>
@since 1.0
*/
public class JDBCAppender extends AppenderSkeleton
{
/**
A database-option to to set a database url of the form jdbc:subprotocol:subname.
*/
public static final String URL_OPTION = "url";
/**
A database-option to set the database user on whose behalf the connection is being made.
*/
public static final String USERNAME_OPTION = "username";
/**
A database-option to set the user's password.
*/
public static final String PASSWORD_OPTION = "password";
/**
A table-option to specify a table contained by the database
*/
public static final String TABLE_OPTION = "table";
/**
A connector-option to specify your own JDBCConnectionHandler
*/
public static final String CONNECTOR_OPTION = "connector";
/**
A columns-option to describe the important columns of the table
*/
public static final String COLUMNS_OPTION = "columns";
/**
A sql-option to specify a static sql-statement which will be performed with every occuring message-event
*/
public static final String SQL_OPTION = "sql";
/**
A buffer-option to define the size of the message-event-buffer
*/
public static final String BUFFER_OPTION = "buffer";
/**
A commit-option to define a auto-commitment
*/
public static final String COMMIT_OPTION = "commit";
//Variables to store the options values setted by setOption() :
private String url = null;
private String username = null;
private String password = null;
private String table = null;
private String connection_class = null;
private String sql = null;
private boolean docommit = true;
private int buffer_size = 1;
private JDBCConnectionHandler connectionHandler = null;
//This buffer stores message-events.
//When the buffer_size is reached, the buffer will be flushed and the messages will updated to the database.
private ArrayList buffer = new ArrayList();
//Database-connection
private Connection con = null;
//This class encapsulate the logic which is necessary to log into a table
private JDBCLogger jlogger = new JDBCLogger();
//Flags :
//A flag to indicate a established database connection
private boolean connected = false;
//A flag to indicate configuration status
private boolean configured = false;
//A flag to indicate that everything is ready to get append()-commands.
private boolean ready = false;
/**
If program terminates close the database-connection and flush the buffer
*/
public void finalize()
{
close();
super.finalize();
}
/**
Internal method. Returns a array of strings containing the available options which can be set with method setOption()
*/
public String[] getOptionStrings()
{
// The sequence of options in this string is important, because setOption() is called this way ...
return new String[]{CONNECTOR_OPTION, URL_OPTION, USERNAME_OPTION, PASSWORD_OPTION, SQL_OPTION, TABLE_OPTION, COLUMNS_OPTION, BUFFER_OPTION, COMMIT_OPTION};
}
/**
Sets all necessary options
*/
public void setOption(String _option, String _value)
{
_option = _option.trim();
_value = _value.trim();
if(_option == null || _value == null) return;
if(_option.length() == 0 || _value.length() == 0) return;
_value = _value.trim();
if(_option.equals(CONNECTOR_OPTION))
{
if(!connected) connection_class = _value;
}
else if(_option.equals(URL_OPTION))
{
if(!connected) url = _value;
}
else if(_option.equals(USERNAME_OPTION))
{
if(!connected) username = _value;
}
else if(_option.equals(PASSWORD_OPTION))
{
if(!connected) password = _value;
}
else if(_option.equals(SQL_OPTION))
{
sql = _value;
}
else if(_option.equals(TABLE_OPTION))
{
if(sql != null) return;
table = _value;
}
else if(_option.equals(COLUMNS_OPTION))
{
if(sql != null) return;
String name = null;
int logtype = -1;
String value = null;
String column = null;
String arg = null;
int num_args = 0;
int num_columns = 0;
StringTokenizer st_col;
StringTokenizer st_arg;
//Columns are TAB-separated
st_col = new StringTokenizer(_value, " ");
num_columns = st_col.countTokens();
if(num_columns < 1)
{
errorHandler.error("JDBCAppender::setOption(), Invalid COLUMN_OPTION value : " + _value + " !");
return;
}
for(int i=1; i<=num_columns; i++)
{
column = st_col.nextToken();
//Arguments are ~-separated
st_arg = new StringTokenizer(column, "~");
num_args = st_arg.countTokens();
if(num_args < 2)
{
errorHandler.error("JDBCAppender::setOption(), Invalid COLUMN_OPTION value : " + _value + " !");
return;
}
for(int j=1; j<=num_args; j++)
{
arg = st_arg.nextToken();
if(j == 1) name = arg;
else if(j == 2)
{
try
{
logtype = Integer.parseInt(arg);
}
catch(Exception e)
{
logtype = LogType.parseLogType(arg);
}
if(!LogType.isLogType(logtype))
{
errorHandler.error("JDBCAppender::setOption(), Invalid COLUMN_OPTION LogType : " + arg + " !");
return;
}
}
else if(j == 3) value = arg;
}
if(!setLogType(name, logtype, value)) return;
}
}
else if(_option.equals(BUFFER_OPTION))
{
try
{
buffer_size = Integer.parseInt(_value);
}
catch(Exception e)
{
errorHandler.error("JDBCAppender::setOption(), Invalid BUFFER_OPTION value : " + _value + " !");
return;
}
}
else if(_option.equals(COMMIT_OPTION))
{
docommit = _value.equals("Y");
}
if(_option.equals(SQL_OPTION) || _option.equals(TABLE_OPTION))
{
if(!configured) configure();
}
}
/**
Internal method. Returns true, you may define your own layout...
*/
public boolean requiresLayout()
{
return true;
}
/**
Internal method. Close the database connection & flush the buffer.
*/
public void close()
{
flush_buffer();
if(connection_class == null)
{
try{con.close();}catch(Exception e){errorHandler.error("JDBCAppender::close(), " + e);}
}
this.closed = true;
}
/**
You have to call this function for all provided columns of your log-table !
*/
public boolean setLogType(String _name, int _logtype, Object _value)
{
if(sql != null) return true;
if(!configured)
{
if(!configure()) return false;
}
try
{
jlogger.setLogType(_name, _logtype, _value);
}
catch(Exception e)
{
errorHandler.error("JDBCAppender::setLogType(), " + e);
return false;
}
return true;
}
/**
Internal method. Appends the message to the database table.
*/
public void append(LoggingEvent event)
{
if(!ready)
{
if(!ready())
{
errorHandler.error("JDBCAppender::append(), Not ready to append !");
return;
}
}
buffer.add(event);
if(buffer.size() >= buffer_size) flush_buffer();
}
/**
Internal method. Flushes the buffer.
*/
public void flush_buffer()
{
try
{
int size = buffer.size();
if(size < 1) return;
for(int i=0; i<size; i++)
{
LoggingEvent event = (LoggingEvent)buffer.get(i);
//Insert message into database
jlogger.append(layout.format(event));
}
buffer.clear();
if(docommit) con.commit();
}
catch(Exception e)
{
errorHandler.error("JDBCAppender::flush_buffer(), " + e + " : " + jlogger.getErrorMsg());
try{con.rollback();} catch(Exception ex){}
return;
}
}
/**
Internal method. Returns true, when the JDBCAppender is ready to append messages to the database, else false.
*/
public boolean ready()
{
if(ready) return true;
if(!configured) return false;
ready = jlogger.ready();
if(!ready){errorHandler.error(jlogger.getErrorMsg());}
return ready;
}
/**
Internal method. Connect to the database.
*/
protected void connect() throws Exception
{
if(connected) return;
try
{
if(connection_class == null)
{
if(url == null) throw new Exception("JDBCAppender::connect(), No URL defined.");
if(username == null) throw new Exception("JDBCAppender::connect(), No USERNAME defined.");
if(password == null) throw new Exception("JDBCAppender::connect(), No PASSWORD defined.");
connectionHandler = new DefaultConnectionHandler();
}
else
{
connectionHandler = (JDBCConnectionHandler)(Class.forName(connection_class).newInstance());
}
if(url != null && username != null && password != null)
{
con = connectionHandler.getConnection(url, username, password);
}
else
{
con = connectionHandler.getConnection();
}
if(con.isClosed())
{
throw new Exception("JDBCAppender::connect(), JDBCConnectionHandler returns no connected Connection !");
}
}
catch(Exception e)
{
throw new Exception("JDBCAppender::connect(), " + e);
}
connected = true;
}
/**
Internal method. Configures for appending...
*/
protected boolean configure()
{
if(configured) return true;
if(!connected)
{
if((connection_class == null) && (url == null || username == null || password == null))
{
errorHandler.error("JDBCAppender::configure(), Missing database-options or connector-option !");
return false;
}
try
{
connect();
}
catch(Exception e)
{
connection_class = null;
url = null;
errorHandler.error("JDBCAppender::configure(), " + e);
return false;
}
}
if(sql == null && table == null)
{
errorHandler.error("JDBCAppender::configure(), No SQL_OPTION or TABLE_OPTION given !");
return false;
}
if(!jlogger.isConfigured())
{
try
{
jlogger.setConnection(con);
if(sql == null)
{
jlogger.configureTable(table);
}
else jlogger.configureSQL(sql);
}
catch(Exception e)
{
errorHandler.error("JDBCAppender::configure(), " + e);
return false;
}
}
//Default Message-Layout
if(layout == null)
{
layout = new PatternLayout("%m");
}
configured = true;
return true;
}
}
/**
This is a default JDBCConnectionHandler used by JDBCAppender
*/
class DefaultConnectionHandler implements JDBCConnectionHandler
{
Connection con = null;
public Connection getConnection()
{
return con;
}
public Connection getConnection(String _url, String _username, String _password)
{
try
{
if(con != null && !con.isClosed()) con.close();
con = DriverManager.getConnection(_url, _username, _password);
con.setAutoCommit(false);
}
catch(Exception e){}
return con;
}
}

View File

@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.klopotek.utils.log;
import java.sql.*;
/**
This interface has to be implemented for your own database-connection-handling and its used in class JDBCLogger.
<p><b>Author : </b><A HREF="mailto:t.fenner@klopotek.de">Thomas Fenner</A></p>
@since 1.0
*/
public interface JDBCConnectionHandler
{
/**Get a connection*/
Connection getConnection();
/**Get a defined connection*/
Connection getConnection(String _url, String _username, String _password);
}

View File

@ -0,0 +1,35 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.klopotek.utils.log;
/**
This interface has to be implemented to provide ID-columns with unique IDs and its used in class JDBCLogger.
<p><b>Author : </b><A HREF="mailto:t.fenner@klopotek.de">Thomas Fenner</A></p>
@since 1.0
*/
public interface JDBCIDHandler
{
/**Get a unique ID*/
Object getID();
}

View File

@ -0,0 +1,468 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.klopotek.utils.log;
import java.sql.*;
import java.util.*;
import org.apache.log4j.*;
import org.apache.log4j.helpers.*;
import org.apache.log4j.spi.*;
/**
This class encapsulate the logic which is necessary to log into a table.
Used by JDBCAppender
<p><b>Author : </b><A HREF="mailto:t.fenner@klopotek.de">Thomas Fenner</A></p>
@since 1.0
*/
public class JDBCLogger
{
//All columns of the log-table
private ArrayList logcols = null;
//Only columns which will be provided by logging
private String column_list = null;
//Number of all columns
private int num = 0;
//Status for successful execution of method configure()
private boolean isconfigured = false;
//Status for ready to do logging with method append()
private boolean ready = false;
//This message will be filled with a error-string when method ready() failes, and can be got by calling getMsg()
private String errormsg = "";
private Connection con = null;
private Statement stmt = null;
private ResultSet rs = null;
private String table = null;
//Variables for static SQL-statement logging
private String sql = null;
private String new_sql = null;
private String new_sql_part1 = null;
private String new_sql_part2 = null;
private static final String msg_wildcard = "@MSG@";
private int msg_wildcard_pos = 0;
/**
Writes a message into the database table.
Throws an exception, if an database-error occurs !
*/
public void append(String _msg) throws Exception
{
if(!ready) if(!ready()) throw new Exception("JDBCLogger::append(), Not ready to append !");
if(sql != null)
{
appendSQL(_msg);
return;
}
LogColumn logcol;
rs.moveToInsertRow();
for(int i=0; i<num; i++)
{
logcol = (LogColumn)logcols.get(i);
if(logcol.logtype == LogType.MSG)
{
rs.updateObject(logcol.name, _msg);
}
else if(logcol.logtype == LogType.ID)
{
rs.updateObject(logcol.name, logcol.idhandler.getID());
}
else if(logcol.logtype == LogType.STATIC)
{
rs.updateObject(logcol.name, logcol.value);
}
else if(logcol.logtype == LogType.TIMESTAMP)
{
rs.updateObject(logcol.name, new Timestamp((new java.util.Date()).getTime()));
}
}
rs.insertRow();
}
/**
Writes a message into the database using a given sql-statement.
Throws an exception, if an database-error occurs !
*/
public void appendSQL(String _msg) throws Exception
{
if(!ready) if(!ready()) throw new Exception("JDBCLogger::appendSQL(), Not ready to append !");
if(sql == null) throw new Exception("JDBCLogger::appendSQL(), No SQL-Statement configured !");
if(msg_wildcard_pos > 0)
{
new_sql = new_sql_part1 + _msg + new_sql_part2;
}
else new_sql = sql;
try
{
stmt.executeUpdate(new_sql);
}
catch(Exception e)
{
errormsg = new_sql;
throw e;
}
}
/**
Configures this class, by reading in the structure of the log-table
Throws an exception, if an database-error occurs !
*/
public void configureTable(String _table) throws Exception
{
if(isconfigured) return;
//Fill logcols with META-informations of the table-columns
stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
rs = stmt.executeQuery("SELECT * FROM " + _table + " WHERE 1 = 2");
LogColumn logcol;
ResultSetMetaData rsmd = rs.getMetaData();
num = rsmd.getColumnCount();
logcols = new ArrayList(num);
for(int i=1; i<=num; i++)
{
logcol = new LogColumn();
logcol.name = rsmd.getColumnName(i).toUpperCase();
logcol.type = rsmd.getColumnTypeName(i);
logcol.nullable = (rsmd.isNullable(i) == rsmd.columnNullable);
logcol.isWritable = rsmd.isWritable(i);
if(!logcol.isWritable) logcol.ignore = true;
logcols.add(logcol);
}
table = _table;
isconfigured = true;
}
/**
Configures this class, by storing and parsing the given sql-statement.
Throws an exception, if somethings wrong !
*/
public void configureSQL(String _sql) throws Exception
{
if(isconfigured) return;
if(!isConnected()) throw new Exception("JDBCLogger::configureSQL(), Not connected to database !");
if(_sql == null || _sql.trim().equals("")) throw new Exception("JDBCLogger::configureSQL(), Invalid SQL-Statement !");
sql = _sql.trim();
stmt = con.createStatement();
msg_wildcard_pos = sql.indexOf(msg_wildcard);
if(msg_wildcard_pos > 0)
{
new_sql_part1 = sql.substring(0, msg_wildcard_pos-1) + "'";
//between the message...
new_sql_part2 = "'" + sql.substring(msg_wildcard_pos+msg_wildcard.length());
}
isconfigured = true;
}
/**
Sets a connection. Throws an exception, if the connection is not open !
*/
public void setConnection(Connection _con) throws Exception
{
con = _con;
if(!isConnected()) throw new Exception("JDBCLogger::setConnection(), Given connection isnt connected to database !");
}
/**
Sets a columns logtype (LogTypes) and value, which depends on that logtype.
Throws an exception, if the given arguments arent correct !
*/
public void setLogType(String _name, int _logtype, Object _value) throws Exception
{
if(!isconfigured) throw new Exception("JDBCLogger::setLogType(), Not configured !");
//setLogType() makes only sense for further configuration of configureTable()
if(sql != null) return;
_name = _name.toUpperCase();
if(_name == null || !(_name.trim().length() > 0)) throw new Exception("JDBCLogger::setLogType(), Missing argument name !");
if(!LogType.isLogType(_logtype)) throw new Exception("JDBCLogger::setLogType(), Invalid logtype '" + _logtype + "' !");
if((_logtype != LogType.MSG && _logtype != LogType.EMPTY) && _value == null) throw new Exception("JDBCLogger::setLogType(), Missing argument value !");
LogColumn logcol;
for(int i=0; i<num; i++)
{
logcol = (LogColumn)logcols.get(i);
if(logcol.name.equals(_name))
{
if(!logcol.isWritable) throw new Exception("JDBCLogger::setLogType(), Column " + _name + " is not writeable !");
//Column gets the message
if(_logtype == LogType.MSG)
{
logcol.logtype = _logtype;
return;
}
//Column will be provided by JDBCIDHandler::getID()
else if(_logtype == LogType.ID)
{
logcol.logtype = _logtype;
try
{
//Try to cast directly Object to JDBCIDHandler
logcol.idhandler = (JDBCIDHandler)_value;
}
catch(Exception e)
{
try
{
//Assuming _value is of class string which contains the classname of a JDBCIDHandler
logcol.idhandler = (JDBCIDHandler)(Class.forName((String)_value).newInstance());
}
catch(Exception e2)
{
throw new Exception("JDBCLogger::setLogType(), Cannot cast value of class " + _value.getClass() + " to class JDBCIDHandler !");
}
}
return;
}
//Column will be statically defined with Object _value
else if(_logtype == LogType.STATIC)
{
logcol.logtype = _logtype;
logcol.value = _value;
return;
}
//Column will be provided with a actually timestamp
else if(_logtype == LogType.TIMESTAMP)
{
logcol.logtype = _logtype;
return;
}
//Column will be fully ignored during process.
//If this column is not nullable, the column has to be filled by a database trigger,
//else a database error occurs !
//Columns which are not nullable, but should be not filled, must be explicit assigned with LogType.EMPTY,
//else a value is required !
else if(_logtype == LogType.EMPTY)
{
logcol.logtype = _logtype;
logcol.ignore = true;
return;
}
}
}
}
/**
Return true, if this class is ready to append(), else false.
When not ready, a reason-String is stored in the instance-variable msg.
*/
public boolean ready()
{
if(ready) return true;
if(!isconfigured){ errormsg = "Not ready to append ! Call configure() first !"; return false;}
//No need to doing the whole rest...
if(sql != null)
{
ready = true;
return true;
}
boolean msgcol_defined = false;
LogColumn logcol;
for(int i=0; i<num; i++)
{
logcol = (LogColumn)logcols.get(i);
if(logcol.ignore || !logcol.isWritable) continue;
if(!logcol.nullable && logcol.logtype == LogType.EMPTY)
{
errormsg = "Not ready to append ! Column " + logcol.name + " is not nullable, and must be specified by setLogType() !";
return false;
}
if(logcol.logtype == LogType.ID && logcol.idhandler == null)
{
errormsg = "Not ready to append ! Column " + logcol.name + " is specified as an ID-column, and a JDBCIDHandler has to be set !";
return false;
}
else if(logcol.logtype == LogType.STATIC && logcol.value == null)
{
errormsg = "Not ready to append ! Column " + logcol.name + " is specified as a static field, and a value has to be set !";
return false;
}
else if(logcol.logtype == LogType.MSG) msgcol_defined = true;
}
if(!msgcol_defined) return false;
//create the column_list
for(int i=0; i<num; i++)
{
logcol = (LogColumn)logcols.get(i);
if(logcol.ignore || !logcol.isWritable) continue;
if(logcol.logtype != LogType.EMPTY)
{
if(column_list == null)
{
column_list = logcol.name;
}
else column_list += ", " + logcol.name;
}
}
try
{
rs = stmt.executeQuery("SELECT " + column_list + " FROM " + table + " WHERE 1 = 2");
}
catch(Exception e)
{
errormsg = "Not ready to append ! Cannot select columns '" + column_list + "' of table " + table + " !";
return false;
}
ready = true;
return true;
}
/**
Return true, if this class is configured, else false.
*/
public boolean isConfigured(){ return isconfigured;}
/**
Return true, if this connection is open, else false.
*/
public boolean isConnected()
{
try
{
return (con != null && !con.isClosed());
}
catch(Exception e){return false;}
}
/**
Return the internal error message stored in instance variable msg.
*/
public String getErrorMsg(){String r = new String(errormsg); errormsg = null; return r;}
}
/**
This class encapsulate all by class JDBCLogger needed data around a column
*/
class LogColumn
{
//column name
String name = null;
//column type
String type = null;
//not nullability means that this column is mandatory
boolean nullable = false;
//isWritable means that the column can be updated, else column is only readable
boolean isWritable = false;
//if ignore is true, this column will be ignored by building sql-statements.
boolean ignore = false;
//Must be filled for not nullable columns ! In other case it is optional.
int logtype = LogType.EMPTY;
Object value = null; //Generic storage for typewrapper-classes Long, String, etc...
JDBCIDHandler idhandler = null;
}
/**
This class contains all constants which are necessary to define a columns log-type.
*/
class LogType
{
//A column of this type will receive the message.
public static final int MSG = 1;
//A column of this type will be a unique identifier of the logged row.
public static final int ID = 2;
//A column of this type will contain a static, one-time-defined value.
public static final int STATIC = 3;
//A column of this type will be filled with an actual timestamp depending by the time the logging will be done.
public static final int TIMESTAMP = 4;
//A column of this type will contain no value and will not be included in logging insert-statement.
//This could be a column which will be filled not by creation but otherwhere...
public static final int EMPTY = 5;
public static boolean isLogType(int _lt)
{
if(_lt == MSG || _lt == STATIC || _lt == ID || _lt == TIMESTAMP || _lt == EMPTY) return true;
return false;
}
public static int parseLogType(String _lt)
{
if(_lt.equals("MSG")) return MSG;
if(_lt.equals("ID")) return ID;
if(_lt.equals("STATIC")) return STATIC;
if(_lt.equals("TIMESTAMP")) return TIMESTAMP;
if(_lt.equals("EMPTY")) return EMPTY;
return -1;
}
}

View File

@ -0,0 +1,271 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
// Class JDBCAppender, writes messages into a database
// The JDBCAppender is configurable at runtime in two alternatives :
// 1. Configuration-file
// Define the options in a file and call a PropertyConfigurator.configure(file)-method.
// 2. method JDBCAppender::setOption(JDBCAppender.xxx_OPTION, String value)
// The sequence of some options is important :
// 1. Connector-option OR/AND Database-options
// Any database connection is required !
// 2. (Table-option AND Columns-option) OR SQL-option
// Any statement is required !
// 3. All other options can be set at any time...
// The other options are optional and have a default initialization, which can be custumized.
// All available options are defined as static String-constants in JDBCAppender named xxx_OPTION.
// Here is a description of all available options :
// 1. Database-options to connect to the database
// - URL_OPTION : a database url of the form jdbc:subprotocol:subname
// - USERNAME_OPTION : the database user on whose behalf the connection is being made
// - PASSWORD_OPTION : the user's password
//
// 2. Connector-option to specify your own JDBCConnectionHandler
// - CONNECTOR_OPTION : a classname which is implementing the JDBCConnectionHandler-interface
// This interface is used to get a customized connection.
// If in addition the database-options are given, these options will be used
// for invocation of the JDBCConnectionHandler-interface to get a connection.
// Else if no database-options are given, the JDBCConnectionHandler-interface is called without these options.
//
// 3. SQL-option to specify a static sql-statement which will be performed with every occuring message-event
// - SQL_OPTION : a sql-statement which will be used to write to the database
// If you give this option, the table-option and columns-option will be ignored !
// Use the variable @MSG@ on that location in the statement, which has to be dynamically replaced by the message.
//
// 4. Table-option to specify one table contained by the database
// - TABLE_OPTION : the table in which the logging will be done
//
// 5. Columns-option to describe the important columns of the table (Not nullable columns are mandatory to describe!)
// - COLUMNS_OPTION : a formatted list of column-descriptions
// Each column description consists of
// - the name of the column (required)
// - a logtype which is a static constant of class LogType (required)
// - and a value which depends by the LogType (optional/required, depending by logtype)
// Here is a description of the available logtypes of class LogType :
// o MSG = a value will be ignored, the column will get the message. (One columns need to be of this type!)
// o STATIC = the value will be filled into the column with every logged message. (Ensure that the type of value can be casted into the sql-type of the column!)
// o ID = value must be a classname, which implements the JDBCIDHandler-interface.
// o TIMESTAMP = a value will be ignored, the column will be filled with a actually timestamp with every logged message.
// o EMPTY = a value will be ignored, the column will be ignored when writing to the database (Ensure to fill not nullable columns by a database trigger!)
// If there are more than one column to describe, the columns must be separated by a TAB-delimiter (' ') !
// The arguments of a column-description must be separated by the delimiter '~' !
// (Example : name1~logtype1~value1 name2~logtype2~value2...)
//
// 6. Layout-options to define the layout of the messages (optional)
// - the layout wont be set by a xxx_OPTION
// Configuration-file : see at the following configuration-file example
// JDBCAppender::setOption() : see at the following code example
// The default is a layout of class org.apache.log4j.PatternLayout with ConversionPattern=%m
//
// 7. Buffer-option to define the size of the message-event-buffer (optional)
// - BUFFER_OPTION : define how many messages will be buffered until they will be updated to the database.
// The default is a update on every message (buffer=1=no buffer).
//
// 8. Commit-option to define a auto-commitment
// - COMMIT_OPTION : define whether updated messages should be committed to the database (Y) or not (N).
// The default is a commit on every buffer-flush.
// Here is a Configuration-file example, which can be used with the PropertyConfigurator :
//
// Declare a appender variable named JDBC
log4j.rootCategory=JDBC
// JDBC is a class of JDBCAppender, which writes messages into a database
log4j.appender.JDBC=JDBCAppender
// 1. Database-options to connect to the database
log4j.appender.JDBC.url=jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(COMMUNITY=tcp.world)(PROTOCOL=TCP)(Host=LENZI)(Port=1521))(ADDRESS=(COMMUNITY=tcp.world)(PROTOCOL=TCP)(Host=LENZI)(Port=1526)))(CONNECT_DATA=(SID=LENZI)))
log4j.appender.JDBC.username=mex_pr_dev60
log4j.appender.JDBC.password=mex_pr_dev60
// 2. Connector-option to specify your own JDBCConnectionHandler
log4j.appender.JDBC.connector=MyConnectionHandler
// 3. SQL-option to specify a static sql-statement which will be performed with every occuring message-event
log4j.appender.JDBC.sql=INSERT INTO LOGTEST (id, msg, created_on, created_by) VALUES (1, @MSG@, sysdate, 'me')
// 4. Table-option to specify one table contained by the database
log4j.appender.JDBC.table=logtest
// 5. Columns-option to describe the important columns of the table (Not nullable columns are mandatory to describe!)
log4j.appender.JDBC.columns=id_seq~EMPTY id~ID~MyIDHandler msg~MSG created_on~TIMESTAMP created_by~STATIC~Thomas Fenner (t.fenner@klopotek.de)
// 6. Layout-options to define the layout of the messages (optional)
log4j.appender.JDBC.layout=org.apache.log4j.PatternLayout
log4j.appender.JDBC.layout.ConversionPattern=%m
// 7. Buffer-option to define the size of the message-event-buffer (optional)
log4j.appender.JDBC.buffer=1
// 8. Commit-option to define a auto-commitment
log4j.appender.JDBC.commit=Y
*/
// Here is a code example to configure the JDBCAppender with a configuration-file :
import org.apache.log4j.*;
import java.sql.*;
import java.lang.*;
import java.util.*;
public class Log4JTest
{
// Create a category instance for this class
static Category cat = Category.getInstance(Log4JTest.class.getName());
public static void main(String[] args)
{
// Ensure to have all necessary drivers installed !
try
{
Driver d = (Driver)(Class.forName("oracle.jdbc.driver.OracleDriver").newInstance());
DriverManager.registerDriver(d);
}
catch(Exception e){}
// Set the priority which messages have to be logged
cat.setPriority(Priority.INFO);
// Configuration with configuration-file
PropertyConfigurator.configure("log4jtestprops.txt");
// These messages with Priority >= setted priority will be logged to the database.
cat.debug("debug"); //this not, because Priority DEBUG is less than INFO
cat.info("info");
cat.error("error");
cat.fatal("fatal");
}
}
// Here is a code example to configure the JDBCAppender without a configuration-file :
/*
import org.apache.log4j.*;
import java.sql.*;
import java.lang.*;
import java.util.*;
public class Log4JTest
{
// Create a category instance for this class
static Category cat = Category.getInstance(Log4JTest.class.getName());
public static void main(String[] args)
{
// A JDBCIDHandler
MyIDHandler idhandler = new MyIDHandler();
// Ensure to have all necessary drivers installed !
try
{
Driver d = (Driver)(Class.forName("oracle.jdbc.driver.OracleDriver").newInstance());
DriverManager.registerDriver(d);
}
catch(Exception e){}
// Set the priority which messages have to be logged
cat.setPriority(Priority.DEBUG);
// Create a new instance of JDBCAppender
JDBCAppender ja = new JDBCAppender();
// Set options with method setOption()
ja.setOption(JDBCAppender.CONNECTOR_OPTION, "MyConnectionHandler");
ja.setOption(JDBCAppender.URL_OPTION, "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(COMMUNITY=tcp.world)(PROTOCOL=TCP)(Host=LENZI)(Port=1521))(ADDRESS=(COMMUNITY=tcp.world)(PROTOCOL=TCP)(Host=LENZI)(Port=1526)))(CONNECT_DATA=(SID=LENZI)))");
ja.setOption(JDBCAppender.USERNAME_OPTION, "mex_pr_dev60");
ja.setOption(JDBCAppender.PASSWORD_OPTION, "mex_pr_dev60");
ja.setOption(JDBCAppender.TABLE_OPTION, "logtest");
// There are two ways to setup the column-descriptions :
// 1. Use the the method setOption(JDBCAppender.COLUMNS_OPTION, column-description)
//ja.setOption(JDBCAppender.COLUMNS_OPTION, "id_seq~EMPTY id~ID~MyIDHandler msg~MSG created_on~TIMESTAMP created_by~STATIC~:-) Thomas Fenner (t.fenner@klopotek.de)");
// 2. Use the better way of coding with method setLogType(String columnname, int LogType.xxx, Object xxx)
ja.setLogType("id_seq", LogType.EMPTY, "");
ja.setLogType("id", LogType.ID, idhandler);
ja.setLogType("msg", LogType.MSG, "");
ja.setLogType("created_on", LogType.TIMESTAMP, "");
ja.setLogType("created_by", LogType.STATIC, "FEN");
// If you just want to perform a static sql-statement, forget about the table- and columns-options,
// and use this one :
//ja.setOption(JDBCAppender.SQL_OPTION, "INSERT INTO LOGTEST (id, msg, created_on, created_by) VALUES (1, @MSG@, sysdate, 'me')");
// other options
//ja.setOption(JDBCAppender.BUFFER_OPTION, "1");
//ja.setOption(JDBCAppender.COMMIT_OPTION, "Y");
// Define a layout
//ja.setLayout(new PatternLayout("%m"));
// Add the appender to a category
cat.addAppender(ja);
// These messages with Priority >= setted priority will be logged to the database.
cat.debug("debug");
cat.info("info");
cat.error("error");
cat.fatal("fatal");
}
}
*/
// Implement a sample JDBCConnectionHandler
class MyConnectionHandler implements JDBCConnectionHandler
{
Connection con = null;
//Default connection
String url = "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(COMMUNITY=tcp.world)(PROTOCOL=TCP)(Host=LENZI)(Port=1521))(ADDRESS=(COMMUNITY=tcp.world)(PROTOCOL=TCP)(Host=LENZI)(Port=1526)))(CONNECT_DATA=(SID=LENZI)))";
String username = "mex_pr_dev60";
String password = "mex_pr_dev60";
public Connection getConnection()
{
return getConnection(url, username, password);
}
public Connection getConnection(String _url, String _username, String _password)
{
try
{
if(con != null && !con.isClosed()) con.close();
con = DriverManager.getConnection(_url, _username, _password);
con.setAutoCommit(false);
}
catch(Exception e){}
return con;
}
}
// Implement a sample JDBCIDHandler
class MyIDHandler implements JDBCIDHandler
{
private static long id = 0;
public synchronized Object getID()
{
return new Long(++id);
}
}

View File

@ -0,0 +1,53 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Here is a code example to configure the JDBCAppender with a configuration-file
import org.apache.log4j.*;
import java.sql.*;
import java.lang.*;
import java.util.*;
public class Log4JTest
{
// Create a category instance for this class
static Category cat = Category.getInstance(Log4JTest.class.getName());
public static void main(String[] args)
{
// Ensure to have all necessary drivers installed !
try
{
Driver d = (Driver)(Class.forName("oracle.jdbc.driver.OracleDriver").newInstance());
DriverManager.registerDriver(d);
}
catch(Exception e){}
// Set the priority which messages have to be logged
cat.setPriority(Priority.INFO);
// Configuration with configuration-file
PropertyConfigurator.configure("log4jtestprops.txt");
// These messages with Priority >= setted priority will be logged to the database.
cat.debug("debug"); //this not, because Priority DEBUG is less than INFO
cat.info("info");
cat.error("error");
cat.fatal("fatal");
}
}

View File

@ -0,0 +1,129 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Here is a code example to configure the JDBCAppender without a configuration-file
import org.apache.log4j.*;
import java.sql.*;
import java.lang.*;
import java.util.*;
public class Log4JTest
{
// Create a category instance for this class
static Category cat = Category.getInstance(Log4JTest.class.getName());
public static void main(String[] args)
{
// A JDBCIDHandler
MyIDHandler idhandler = new MyIDHandler();
// Ensure to have all necessary drivers installed !
try
{
Driver d = (Driver)(Class.forName("oracle.jdbc.driver.OracleDriver").newInstance());
DriverManager.registerDriver(d);
}
catch(Exception e){}
// Set the priority which messages have to be logged
cat.setPriority(Priority.DEBUG);
// Create a new instance of JDBCAppender
JDBCAppender ja = new JDBCAppender();
// Set options with method setOption()
ja.setOption(JDBCAppender.CONNECTOR_OPTION, "MyConnectionHandler");
ja.setOption(JDBCAppender.URL_OPTION, "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(COMMUNITY=tcp.world)(PROTOCOL=TCP)(Host=LENZI)(Port=1521))(ADDRESS=(COMMUNITY=tcp.world)(PROTOCOL=TCP)(Host=LENZI)(Port=1526)))(CONNECT_DATA=(SID=LENZI)))");
ja.setOption(JDBCAppender.USERNAME_OPTION, "mex_pr_dev60");
ja.setOption(JDBCAppender.PASSWORD_OPTION, "mex_pr_dev60");
ja.setOption(JDBCAppender.TABLE_OPTION, "logtest");
// There are two ways to setup the column-descriptions :
// 1. Use the the method setOption(JDBCAppender.COLUMNS_OPTION, column-description)
//ja.setOption(JDBCAppender.COLUMNS_OPTION, "id_seq~EMPTY id~ID~MyIDHandler msg~MSG created_on~TIMESTAMP created_by~STATIC~:-) Thomas Fenner (t.fenner@klopotek.de)");
// 2. Use the better way of coding with method setLogType(String columnname, int LogType.xxx, Object xxx)
ja.setLogType("id_seq", LogType.EMPTY, "");
ja.setLogType("id", LogType.ID, idhandler);
ja.setLogType("msg", LogType.MSG, "");
ja.setLogType("created_on", LogType.TIMESTAMP, "");
ja.setLogType("created_by", LogType.STATIC, "FEN");
// If you just want to perform a static sql-statement, forget about the table- and columns-options,
// and use this one :
//ja.setOption(JDBCAppender.SQL_OPTION, "INSERT INTO LOGTEST (id, msg, created_on, created_by) VALUES (1, @MSG@, sysdate, 'me')");
// other options
//ja.setOption(JDBCAppender.BUFFER_OPTION, "1");
//ja.setOption(JDBCAppender.COMMIT_OPTION, "Y");
// Define a layout
//ja.setLayout(new PatternLayout("%m"));
// Add the appender to a category
cat.addAppender(ja);
// These messages with Priority >= setted priority will be logged to the database.
cat.debug("debug");
cat.info("info");
cat.error("error");
cat.fatal("fatal");
}
}
// Implement a sample JDBCConnectionHandler
class MyConnectionHandler implements JDBCConnectionHandler
{
Connection con = null;
//Default connection
String url = "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(COMMUNITY=tcp.world)(PROTOCOL=TCP)(Host=LENZI)(Port=1521))(ADDRESS=(COMMUNITY=tcp.world)(PROTOCOL=TCP)(Host=LENZI)(Port=1526)))(CONNECT_DATA=(SID=LENZI)))";
String username = "mex_pr_dev60";
String password = "mex_pr_dev60";
public Connection getConnection()
{
return getConnection(url, username, password);
}
public Connection getConnection(String _url, String _username, String _password)
{
try
{
if(con != null && !con.isClosed()) con.close();
con = DriverManager.getConnection(_url, _username, _password);
con.setAutoCommit(false);
}
catch(Exception e){}
return con;
}
}
// Implement a sample JDBCIDHandler
class MyIDHandler implements JDBCIDHandler
{
private static long id = 0;
public synchronized Object getID()
{
return new Long(++id);
}
}

View File

@ -0,0 +1,52 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Here is a Configuration-file example, which can be used with the PropertyConfigurator :
# Declare a appender variable named JDBC
log4j.rootCategory=JDBC
# JDBC is a class of JDBCAppender, which writes messages into a database
log4j.appender.JDBC=JDBCAppender
# 1. Database-options to connect to the database
log4j.appender.JDBC.url=jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(COMMUNITY=tcp.world)(PROTOCOL=TCP)(Host=LENZI)(Port=1521))(ADDRESS=(COMMUNITY=tcp.world)(PROTOCOL=TCP)(Host=LENZI)(Port=1526)))(CONNECT_DATA=(SID=LENZI)))
log4j.appender.JDBC.username=mex_pr_dev60
log4j.appender.JDBC.password=mex_pr_dev60
# 2. Connector-option to specify your own JDBCConnectionHandler
#log4j.appender.JDBC.connector=MyConnectionHandler
# 3. SQL-option to specify a static sql-statement which will be performed with every occuring message-event
#log4j.appender.JDBC.sql=INSERT INTO LOGTEST (id, msg, created_on, created_by) VALUES (1, @MSG@, sysdate, 'me')
# 4. Table-option to specify one table contained by the database
log4j.appender.JDBC.table=logtest
# 5. Columns-option to describe the important columns of the table (Not nullable columns are mandatory to describe!)
log4j.appender.JDBC.columns=id_seq~EMPTY id~ID~MyIDHandler msg~MSG created_on~TIMESTAMP created_by~STATIC~Thomas Fenner (t.fenner@klopotek.de)
# 6. Layout-options to define the layout of the messages (optional)
#log4j.appender.JDBC.layout=org.apache.log4j.PatternLayout
#log4j.appender.JDBC.layout.ConversionPattern=%m
# 7. Buffer-option to define the size of the message-event-buffer (optional)
#log4j.appender.JDBC.buffer=1
# 8. Commit-option to define a auto-commitment (optional)
#log4j.appender.JDBC.commit=Y

View File

@ -0,0 +1,75 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.psibt.framework.net;
import java.io.*;
import java.net.*;
/**
* This interface defines all methods that have to be implemented for a HTTPRequestHandler for the
* PluggableHTTPServer.
*
* @author <a HREF="mailto:V.Mentzner@psi-bt.de">Volker Mentzner</a>
*/
public interface HTTPRequestHandler {
/**
* Gets the title for html page
*/
public String getTitle();
/**
* Sets the title for html page
*/
public void setTitle(String title);
/**
* Gets the description for html page
*/
public String getDescription();
/**
* Sets the description for html page
*/
public void setDescription(String description);
/**
* Gets the virtual path in the HTTP server that ist handled in this HTTPRequestHandler.
* So the root path handler will return "/" (without brackets) because it handles the path
* "http://servername/" or a handler for "http://servername/somepath/" will return "/somepath/"
* It is important to include the trailing "/" because all HTTPRequestHandler have to serve a path!
*/
public String getHandledPath();
/**
* Sets the virtual path in the HTTP server that ist handled in this HTTPRequestHandler.
* So set the path to "/" for the root path handler because it handles the path
* "http://servername/" or set it to "/somepath/" for a handler for "http://servername/somepath/".
* It is important to include the trailing "/" because all HTTPRequestHandler have to serve a path!
*/
public void setHandledPath(String path);
/**
* Handles the given request and writes the reply to the given out-stream. Every handler has to check
* the request for the right path info.
*
* @param request - client browser request
* @param out - Out stream for sending data to client browser
* @return if the request was handled by this handler : true, else : false
*/
public boolean handleRequest(String request, Writer out);
}

View File

@ -0,0 +1,177 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.psibt.framework.net;
import java.io.*;
import java.net.*;
import java.util.*;
import org.apache.log4j.*;
/**
* This class implements a RequestHandler for log4j configuration. It serves the "/log4j/" path
* in the PluggableHTTPServer. If this path is requested a list of all current log4j categories
* with their current priorities is created. All priority settings can be changed by the user
* and can be submitted and taken over.
*
* @author <a HREF="mailto:V.Mentzner@psi-bt.de">Volker Mentzner</a>
*/
public class Log4jRequestHandler extends RootRequestHandler {
private Priority[] prios = Priority.getAllPossiblePriorities();
/**
* Creates a new Log4jRequestHandler object
*/
public Log4jRequestHandler() {
this.setTitle("log4j");
this.setDescription("log4j configuration");
this.setHandledPath("/log4j/");
}
/**
* Handles the given request and writes the reply to the given out-stream.
*
* @param request - client browser request
* @param out - Out stream for sending data to client browser
* @return if the request was handled by this handler : true, else : false
*/
public boolean handleRequest(String request, Writer out) {
String path = "";
String query = null;
String name;
try {
// check request url
URL url = new URL("http://localhost"+request);
path = url.getPath();
query = url.getQuery();
if (path.startsWith(this.getHandledPath()) == false) {
return false;
}
out.write("HTTP/1.0 200 OK\r\n");
out.write("Content-type: text/html\r\n\r\n");
out.write("<HTML><HEAD><TITLE>" + this.getTitle() + "</TITLE></HEAD>\r\n");
out.write("<BODY><H1>log4j</H1>\r\n");
out.write(this.getDescription() + "<br><br>\r\n");
// handle a request with query
if ((query != null) && (query.length() >= 0)) {
StringTokenizer st = new StringTokenizer(query, "&");
String cmd;
String catname;
String catval;
int idx;
while (st.hasMoreTokens()) {
cmd = st.nextToken();
idx = cmd.indexOf("=");
catname = cmd.substring(0, idx);
catval = cmd.substring(idx+1, cmd.length());
if (catname.equalsIgnoreCase("root"))
Category.getRoot().setPriority(Priority.toPriority(catval));
else
Category.getInstance(catname).setPriority(Priority.toPriority(catval));
}
}
// output category information in a form with a simple table
out.write("<form name=\"Formular\" ACTION=\""+this.getHandledPath()+"\" METHOD=\"PUT\">");
out.write("<table cellpadding=4>\r\n");
out.write(" <tr>\r\n");
out.write(" <td><b>Category</b></td>\r\n");
out.write(" <td><b>Priority</b></td>\r\n");
out.write(" <td><b>Appender</b></td>\r\n");
out.write(" </tr>\r\n");
// output for root category
Category cat = Category.getRoot();
out.write(" <tr><td>root</td>\r\n");
out.write(" <td>\r\n");
out.write(" <select size=1 name=\""+ cat.getName() +"\">");
for (int i = 0; i < prios.length; i++) {
if (cat.getChainedPriority().toString().equals(prios[i].toString()))
out.write("<option selected>"+prios[i].toString());
else
out.write("<option>"+prios[i].toString());
}
out.write("</select>\r\n");
out.write(" </td>\r\n");
out.write(" <td>\r\n");
for (Enumeration apds = cat.getAllAppenders(); apds.hasMoreElements();) {
Appender apd = (Appender)apds.nextElement();
name = apd.getName();
if (name == null)
name = "<i>(no name)</i>";
out.write(name);
if (apd instanceof AppenderSkeleton) {
try {
AppenderSkeleton apskel = (AppenderSkeleton)apd;
out.write(" [" + apskel.getThreshold().toString() + "]");
} catch (Exception ex) {
}
}
if (apds.hasMoreElements())
out.write(", ");
}
out.write(" </td>\r\n");
out.write(" </tr>\r\n");
// output for all other categories
for (Enumeration en = Category.getCurrentCategories(); en.hasMoreElements();) {
cat = (Category)en.nextElement();
out.write(" <tr>\r\n");
out.write(" <td>" + cat.getName() + "</td>\r\n");
out.write(" <td>\r\n");
out.write(" <select size=1 name=\""+ cat.getName() +"\">");
for (int i = 0; i < prios.length; i++) {
if (cat.getChainedPriority().toString().equals(prios[i].toString()))
out.write("<option selected>"+prios[i].toString());
else
out.write("<option>"+prios[i].toString());
}
out.write("</select>\r\n");
out.write(" </td>\r\n");
out.write(" <td>\r\n");
for (Enumeration apds = cat.getAllAppenders(); apds.hasMoreElements();) {
Appender apd = (Appender)apds.nextElement();
name = apd.getName();
if (name == null)
name = "<i>(no name)</i>";
out.write(name);
if (apd instanceof AppenderSkeleton) {
try {
AppenderSkeleton apskel = (AppenderSkeleton)apd;
out.write(" [" + apskel.getThreshold().toString() + "]");
} catch (Exception ex) {
}
}
if (apds.hasMoreElements())
out.write(", ");
}
out.write(" </td>\r\n");
out.write(" </tr>\r\n");
}
out.write("</table>\r\n");
out.write("<input type=submit value=\"Submit\">");
out.write("</form>");
out.write("</BODY></HTML>\r\n");
out.flush();
return true;
} catch (Exception ex) {
return false;
}
}
}

View File

@ -0,0 +1,262 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.psibt.framework.net;
import java.net.*;
import java.io.*;
import java.util.*;
import org.apache.log4j.*;
/**
* This class implements a HTTP-server frame. All HTTP-requests are handled by HTTPRequestHandler
* classes which implement the <code>HTTPRequestHandler</code> interface. Every RequestHandler has
* to be registered in the PluggableHTTPServer with the <code>addRequestHandler</code> method.
* A new thread is created for each connection to handle the request. If all reply data are sent
* to the client the connection is closed and the thread ends.
* An example how to use the PluggableHTTPServer class can be found in the <code>main</code> method
* at the end of the source file.
*
* @author <a HREF="mailto:V.Mentzner@psi-bt.de">Volker Mentzner</a>
*/
public class PluggableHTTPServer implements Runnable {
public static final int DEFAULT_PORT = 80;
static Category cat = Category.getInstance("PluggableHTTPServer");
private int port;
private Vector handler;
private ServerSocket server;
/**
* Creates a new server object on the given TCP port.
* If the port is occupied by another process a IOException (java.net.BindException) is thrown.
*
* @param port - TCP port number to listen on for requests
*/
public PluggableHTTPServer(int port) throws IOException {
this.port = port;
this.handler = new Vector();
cat.setPriority(Priority.ERROR);
server = new ServerSocket(this.port);
}
/**
* Creates a new server object on the default TCP port 80
* If the port is occupied by another process a IOException (java.net.BindException) is thrown.
*/
public PluggableHTTPServer() throws IOException {
this(DEFAULT_PORT);
}
/**
* Registers the given HTTPRequestHandler
*
* @param h - the HTTPRequestHandler to register
*/
public void addRequestHandler(HTTPRequestHandler h) {
handler.add(h);
}
/**
* Unregisters the given HTTPRequestHandler
*
* @param h - the HTTPRequestHandler to unregister
*/
public void removeRequestHandler(HTTPRequestHandler h) {
handler.remove(h);
}
/**
* Sends the HTTP message 404 - File Not Found
* see RFC2616 for details
*
* @param out - Out stream for sending data to client browser
*/
public static void replyNotFound(Writer out) {
try {
out.write("HTTP/1.0 404 Not Found\r\n");
out.write("<HTML><HEAD><TITLE>Not Found</TITLE></HEAD>\r\n");
out.write("<BODY><H1>Not Found</H1>\r\n");
out.write("</BODY></HTML>\r\n");
out.flush();
} // end try
catch (IOException e) {
}
}
/**
* Sends the HTTP message 405 - Method Not Allowed
* see RFC2616 for details
*
* @param out - Out stream for sending data to client browser
*/
public static void replyMethodNotAllowed(Writer out) {
try {
out.write("HTTP/1.1 405 Method Not Allowed\r\n");
out.write("Allow: GET, PUT\r\n");
out.write("<HTML><HEAD><TITLE>Method Not Allowed</TITLE></HEAD>\r\n");
out.write("<BODY><H1>Method Not Allowed</H1>\r\n");
out.write("</BODY></HTML>\r\n");
out.flush();
} // end try
catch (IOException e) {
}
}
/**
* Creates the ReplyHTML data for the root page
*
* @param index - index of the RootRequestHandler
*/
public void autoCreateRootPage(int index) {
if (handler.get(index) instanceof RootRequestHandler) {
RootRequestHandler r = (RootRequestHandler)handler.get(index);
String html = "<HTML><HEAD><TITLE>"+r.getTitle()+"</TITLE></HEAD>\r\n";
html = html + "<BODY><H1>"+r.getDescription()+"</H1>\r\n";
for (int i = 0; i < handler.size(); i++) {
html = html + "<a href=\"" + ((HTTPRequestHandler)handler.get(i)).getHandledPath();
html = html + "\">" + ((HTTPRequestHandler)handler.get(i)).getDescription() + "</a><br>";
}
html = html + "</BODY></HTML>\r\n";
r.setReplyHTML(html);
}
}
/**
* Main loop of the PluggableHTTPServer
*/
public void run() {
while (true) {
try {
Socket s = server.accept();
Thread t = new ServerThread(s);
t.start();
}
catch (IOException e) {
}
}
}
/**
* This class handles the incomming connection for one request.
*/
class ServerThread extends Thread {
private Socket connection;
ServerThread(Socket s) {
this.connection = s;
}
/**
* Serves the HTTP request.
*/
public void run() {
try {
Writer out = new BufferedWriter(
new OutputStreamWriter(
connection.getOutputStream(), "ASCII"
)
);
Reader in = new InputStreamReader(
new BufferedInputStream(
connection.getInputStream()
)
);
// read the first line only; that's all we need
StringBuffer req = new StringBuffer(80);
while (true) {
int c = in.read();
if (c == '\r' || c == '\n' || c == -1) break;
req.append((char) c);
}
String get = req.toString();
cat.debug(get);
StringTokenizer st = new StringTokenizer(get);
String method = st.nextToken();
String request = st.nextToken();
String version = st.nextToken();
if (method.equalsIgnoreCase("GET")) {
boolean served = false;
for (int i = 0; i < handler.size(); i++) {
if (handler.get(i) instanceof HTTPRequestHandler) {
if (((HTTPRequestHandler)handler.get(i)).handleRequest(request, out)) {
served = true;
break;
}
}
}
if (!served)
PluggableHTTPServer.replyNotFound(out);
}
else {
PluggableHTTPServer.replyMethodNotAllowed(out);
}
} // end try
catch (IOException e) {
}
finally {
try {
if (connection != null) connection.close();
}
catch (IOException e) {}
}
} // end run
} // end class ServerThread
/**
* Demo how to use the PluggableHTTPServer.
*/
public static void main(String[] args) {
int thePort;
// create some logging stuff
BasicConfigurator.configure();
Category cat1 = Category.getInstance("cat1");
cat1.addAppender(new org.apache.log4j.ConsoleAppender(new PatternLayout("%m%n")));
Category cat2 = Category.getInstance("cat2");
cat2.setPriority(Priority.INFO);
cat2.addAppender(new org.apache.log4j.ConsoleAppender(new PatternLayout("%c - %m%n")));
// set TCP port number
try {
thePort = Integer.parseInt(args[1]);
}
catch (Exception e) {
thePort = PluggableHTTPServer.DEFAULT_PORT;
}
PluggableHTTPServer server = null;
while (server == null) {
try {
server = new PluggableHTTPServer(thePort);
server.addRequestHandler(new RootRequestHandler());
server.addRequestHandler(new Log4jRequestHandler());
server.addRequestHandler(new UserDialogRequestHandler());
server.autoCreateRootPage(0);
Thread t = new Thread(server);
t.start();
} catch (IOException e) {
server = null;
thePort++;
}
}
} // end main
}

View File

@ -0,0 +1,159 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.psibt.framework.net;
import java.io.*;
import java.net.*;
import java.util.*;
/**
* This class implements a RequestHandler for the root path "/" in the PluggableHTTPServer.
* A simple HTML message will be replied to the client.
*
* @author <a HREF="mailto:V.Mentzner@psi-bt.de">Volker Mentzner</a>
*/
public class RootRequestHandler implements HTTPRequestHandler {
private String title;
private String description;
private String handledPath;
private String ReplyType = "Content-type: text/html\r\n\r\n";
private String ReplyHTML = "<HTML><HEAD><TITLE>Root</TITLE></HEAD>\r\n"
+ "<BODY><H1>Root</H1>\r\n"
+ "</BODY></HTML>\r\n";
/**
* Creates a new RootRequestHandler object
*/
public RootRequestHandler() {
this.setTitle("root page");
this.setDescription("root page");
this.setHandledPath("/");
}
/**
* Gets the content type of the reply HTTP message
*
* @return content type as String
*/
public String getReplyType() {
return this.ReplyType;
}
/**
* Sets the content type of the reply HTTP message
*
* @param ReplyType - content type as String
*/
public void setReplyType(String ReplyType) {
this.ReplyType = ReplyType;
}
/**
* Gets the HTML data of the reply HTTP message
*
* @return HTML message as String
*/
public String getReplyHTML() {
return this.ReplyHTML;
}
/**
* Sets the HTML data of the reply HTTP message
*
* @param ReplyHTML - HTML message as String
*/
public void setReplyHTML(String ReplyHTML) {
this.ReplyHTML = ReplyHTML;
}
/**
* Gets the title for html page
*/
public String getTitle() {
return this.title;
}
/**
* Sets the title for html page
*/
public void setTitle(String title) {
this.title = title;
}
/**
* Gets the description for html page
*/
public String getDescription() {
return this.description;
}
/**
* Sets the description for html page
*/
public void setDescription(String description) {
this.description = description;
}
/**
* Gets the server path
*
* @return the server path
*/
public String getHandledPath() {
return this.handledPath;
}
/**
* Sets the server path
*
* @param path - the server path
*/
public void setHandledPath(String path) {
this.handledPath = path;
}
/**
* Handles the given request and writes the reply to the given out-stream.
*
* @param request - client browser request
* @param out - Out stream for sending data to client browser
* @return if the request was handled by this handler : true, else : false
*/
public boolean handleRequest(String request, Writer out) {
String path = "";
String query = null;
try {
URL url = new URL("http://localhost"+request);
path = url.getPath();
query = url.getPath();
if (path.equals(handledPath) == false) {
return false;
}
out.write("HTTP/1.0 200 OK\r\n");
if (ReplyType != null)
out.write(ReplyType);
if (ReplyHTML != null)
out.write(ReplyHTML);
out.flush();
return true;
} catch (Exception ex) {
return false;
}
}
}

View File

@ -0,0 +1,135 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Title: PSI Java Framework: UserDialogRequestHandler<p>
* Copyright: PSI-BT AG<p>
* History:
* Date Author What's new
* 16.04.2001 VMentzner Created
*/
package com.psibt.framework.net;
/**
* This class implements a RequestHandler for the path "/userdialog/" in the PluggableHTTPServer.
* A simple input form is presented in the browser where you can enter a message. This message will be sent
* to the PluggableHTTPServer and shown in a JOptionPane MessageDialog.
*
* @author <a HREF="mailto:V.Mentzner@psi-bt.de">Volker Mentzner</a>
*/
public class UserDialogRequestHandler extends RootRequestHandler {
private Component parentComponent;
/**
* Creates a new UserDialogRequestHandler object
*/
public UserDialogRequestHandler() {
this(null);
}
/**
* Creates a new UserDialogRequestHandler object with a parentComponent reference
*/
public UserDialogRequestHandler(Component parentComponent) {
this.setTitle("user dialog");
this.setDescription("show user dialog");
this.setHandledPath("/userdialog/");
this.parentComponent = parentComponent;
}
/**
* Handles the given request and writes the reply to the given out-stream.
*
* @param request - client browser request
* @param out - Out stream for sending data to client browser
* @return if the request was handled by this handler : true, else : false
*/
public boolean handleRequest(String request, Writer out) {
String path = "";
String query = null;
try {
URL url = new URL("http://localhost"+request);
path = url.getPath();
query = url.getQuery();
if (path.startsWith(this.getHandledPath()) == false) {
return false;
}
out.write("HTTP/1.0 200 OK\r\n");
out.write("Content-type: text/html\r\n\r\n");
out.write("<HTML><HEAD><TITLE>" + this.getTitle() + "</TITLE></HEAD>\r\n");
out.write("<BODY><H1>" + this.getDescription() + "</H1>\r\n");
if ((query != null) && (query.length() >= 0)) {
int idx = query.indexOf("=");
String message = query.substring(idx+1, query.length());
// replace '+' by space
message = message.replace('+', ' ');
// replace hex strings starting with '%' by their values
idx = message.indexOf("%");
while (idx >= 0) {
String sl = message.substring(0, idx);
String sm = message.substring(idx+1, idx+3);
String sr = message.substring(idx+3, message.length());
try {
int i = Integer.parseInt(sm, 16);
sm = String.valueOf((char)i);
}
catch (Exception ex) {
sm = "";
}
message = sl + sm + sr;
idx = message.indexOf("%");
}
// show message in a new thread
if ((message != null) && (message.length() > 0)) {
Thread t = new Thread(new DialogThread(parentComponent, message));
t.start();
}
}
out.write("<form name=\"Formular\" ACTION=\""+this.getHandledPath()+"+\" METHOD=\"PUT\">");
out.write("<table>\r\n");
out.write(" <tr><td>Send message to user</td></tr>\r\n");
out.write(" <tr><td><textarea name=\"message\" rows=10 cols=50></textarea></td></tr>\r\n");
out.write("</table>\r\n");
out.write("<input type=submit value=\"Submit\">");
out.write("</form>");
out.write("</BODY></HTML>\r\n");
out.flush();
return true;
} catch (Exception ex) {
return false;
}
}
/**
* Internal class to start the user dialog in a new thread. This makes the RequestHandler return
* immediatly
*/
class DialogThread implements Runnable {
private Component parentComponent;
private String message;
public DialogThread(Component parentComponent, String message) {
this.parentComponent = parentComponent;
this.message = message;
}
public void run() {
JOptionPane.showMessageDialog(parentComponent, message);
}
}
}

View File

@ -0,0 +1,42 @@
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Delivered-To: cgu@qos.ch
From: "Mentzner, Volker" <V.Mentzner@PSI-BT.de>
To: "'cgu@qos.ch'" <cgu@qos.ch>
Subject: Remote configuring log4j
Date: Thu, 3 May 2001 08:10:25 +0200
X-Mailer: Internet Mail Service (5.5.2653.19)
Hi Ceki,
I am using log4j in a GUI project. Working at the application I found
it useful to remotely configure log4j with my favourite browser. This
is reached by using a very small web server (PluggableHTTPServer) with
extentions for tasks like configuring log4j. You can easily put this
web server in an application, an example can be found in
PluggableHTTPServer.main(). Maybe someone else can use this too, so I
sent it to you to give it to the contrib dir if you like it.
Regards
Volker Mentzner
<<pluggableServer.zip>>

View File

@ -0,0 +1,64 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package examples;
import org.apache.log4j.*;
import org.apache.log4j.helpers.PatternParser;
/**
Example showing how to extend PatternLayout to recognize additional
conversion characters.
<p>In this case MyPatternLayout recognizes %# conversion pattern. It
outputs the value of an internal counter which is also incremented
at each call.
<p>See <a href=doc-files/MyPatternLayout.java><b>source</b></a> code
for more details.
@see MyPatternParser
@see org.apache.log4j.PatternLayout
@author Anders Kristensen
*/
public class MyPatternLayout extends PatternLayout {
public
MyPatternLayout() {
this(DEFAULT_CONVERSION_PATTERN);
}
public
MyPatternLayout(String pattern) {
super(pattern);
}
public
PatternParser createPatternParser(String pattern) {
return new MyPatternParser(
pattern == null ? DEFAULT_CONVERSION_PATTERN : pattern);
}
public
static void main(String[] args) {
Layout layout = new MyPatternLayout("[counter=%.10#] - %m%n");
Logger logger = Logger.getLogger("some.cat");
logger.addAppender(new ConsoleAppender(layout, ConsoleAppender.SYSTEM_OUT));
logger.debug("Hello, log");
logger.info("Hello again...");
}
}

View File

@ -0,0 +1,72 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package examples;
import org.apache.log4j.helpers.FormattingInfo;
import org.apache.log4j.helpers.PatternConverter;
import org.apache.log4j.helpers.PatternParser;
import org.apache.log4j.spi.LoggingEvent;
/**
Example showing how to extend PatternParser to recognize additional
conversion characters. The examples shows that minimum and maximum
width and alignment settings apply for "extension" conversion
characters just as they do for PatternLayout recognized characters.
<p>In this case MyPatternParser recognizes %# and outputs the value
of an internal counter which is also incremented at each call.
See <a href=doc-files/MyPatternParser.java><b>source</b></a> code
for more details.
@see org.apache.log4j.examples.MyPatternLayout
@see org.apache.log4j.helpers.PatternParser
@see org.apache.log4j.PatternLayout
@author Anders Kristensen
*/
public class MyPatternParser extends PatternParser {
int counter = 0;
public
MyPatternParser(String pattern) {
super(pattern);
}
public
void finalizeConverter(char c) {
if (c == '#') {
addConverter(new UserDirPatternConverter(formattingInfo));
currentLiteral.setLength(0);
} else {
super.finalizeConverter(c);
}
}
private class UserDirPatternConverter extends PatternConverter {
UserDirPatternConverter(FormattingInfo formattingInfo) {
super(formattingInfo);
}
public
String convert(LoggingEvent event) {
return String.valueOf(++counter);
}
}
}

View File

@ -0,0 +1,37 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package examples;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
NumberCruncher's factor positive integers. See <a
href=doc-files/NumberCruncher.java>source</a> code for more details.
@author Ceki G&uuml;lc&uuml;
*/
public interface NumberCruncher extends Remote {
/**
Factor a positive integer <code>number</code> and return its
<em>distinct</em> factor's as an integer array.
*/
int[] factor(int number) throws RemoteException;
}

View File

@ -0,0 +1,107 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package examples;
import java.rmi.RemoteException;
import java.rmi.Naming;
import java.io.*;
/**
NumberCruncherClient is a simple client for factoring integers. A
remote NumberCruncher is contacted and asked to factor an
integer. The factors returned by the {@link NumberCruncherServer}
are displayed on the screen.
<p>See <a href=doc-files/NumberCruncherClient.java>source</a> code of
<code>NumberCruncherClient</code> for more details.
<pre>
<b>Usage:</b> java org.apache.log4j.examples.NumberCruncherClient HOST
&nbsp;&nbsp;&nbsp;&nbsp;where HOST is the machine where the NumberCruncherServer is running
</pre>
<p>Note that class files for the example code is not included in
any of the distributed log4j jar files. You will have to add the
directory <code>/dir-where-you-unpacked-log4j/classes</code> to
your classpath before trying out the examples.
@author Ceki G&uuml;lc&uuml;
*/
public class NumberCruncherClient {
public static void main(String[] args) {
if(args.length == 1) {
try {
String url = "rmi://"+args[0]+ "/Factor";
NumberCruncher nc = (NumberCruncher) Naming.lookup(url);
loop(nc);
}
catch(Exception e) {
e.printStackTrace();
}
}
else
usage("Wrong number of arguments.");
}
static
void usage(String msg) {
System.err.println(msg);
System.err.println(
"Usage: java org.apache.log4j.examples.NumberCruncherClient HOST\n" +
" where HOST is the machine where the NumberCruncherServer is running.");
System.exit(1);
}
static
void loop(NumberCruncher nc) {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
int i = 0;
while (true) {
System.out.print("Enter a number to factor, '-1' to quit: ");
try {
i = Integer.parseInt(in.readLine());
}
catch(Exception e) {
e.printStackTrace();
}
if(i == -1) {
System.out.print("Exiting loop.");
return;
}
else {
try {
System.out.println("Will attempt to factor "+i);
int[] factors = nc.factor(i);
System.out.print("The factors of "+i+" are");
for(int k=0; k < factors.length; k++) {
System.out.print(" " + factors[k]);
}
System.out.println(".");
}
catch(RemoteException e) {
System.err.println("Could not factor "+i);
e.printStackTrace();
}
}
}
}
}

View File

@ -0,0 +1,172 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package examples;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.RemoteException;
import java.rmi.Naming;
import java.util.Vector;
import org.apache.log4j.Logger;
import org.apache.log4j.NDC;
import org.apache.log4j.PropertyConfigurator;
/**
A simple {@link NumberCruncher} implementation that logs its
progress when factoring numbers. The purpose of the whole exercise
is to show the use of nested diagnostic contexts in order to
distinguish the log output from different client requests.
<pre>
<b>Usage:</b> java org.apache.log4j.examples.NumberCruncherServer <em>configFile</em>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where <em>configFile</em> is a log4j configuration file.
</pre>
We supply a simple config file <a href=doc-files/factor.lcf>factor.lcf</a>
for directing log output to the file <code>factor.log</code>.
<p>Try it yourself by starting a <code>NumberCruncherServer</code>
and make queries from multiple {@link NumberCruncherClient
NumberCruncherClients} to factor numbers.
<p><b><a href="doc-files/factor.html">Sample output</a></b> shows the log
output when two clients connect to the server near simultaneously.
<p>See <a href=doc-files/NumberCruncherServer.java>source</a> code
of <code>NumberCruncherServer</code> for more details.
<p>Note that class files for the example code is not included in
any of the distributed log4j jar files. You will have to add the
directory <code>/dir-where-you-unpacked-log4j/classes</code> to
your classpath before trying out the examples.
*/
public class NumberCruncherServer extends UnicastRemoteObject
implements NumberCruncher {
private static final long serialVersionUID = 2626753561969426769L;
static Logger logger = Logger.getLogger(NumberCruncherServer.class);
public
NumberCruncherServer() throws RemoteException {
}
public
int[] factor(int number) throws RemoteException {
// The client's host is an important source of information.
try {
NDC.push(getClientHost());
}
catch(java.rmi.server.ServerNotActiveException e) {
// we are being called from same VM
NDC.push("localhost");
}
// The information contained within the request is another source of
// distinctive information. It might reveal the users name, date of request,
// request ID etc. In servlet type environments, much information is
// contained in cookies.
NDC.push(String.valueOf(number));
logger.info("Beginning to factor.");
if(number <= 0) {
throw new IllegalArgumentException(number+" is not a positive integer.");
}
else if(number == 1)
return new int[] {1};
Vector factors = new Vector();
int n = number;
for(int i = 2; (i <= n) && (i*i <= number); i++) {
// It is bad practice to place log requests within tight loops.
// It is done here to show interleaved log output from
// different requests.
logger.debug("Trying to see if " + i + " is a factor.");
if((n % i) == 0) {
logger.info("Found factor "+i);
factors.addElement(new Integer(i));
do {
n /= i;
} while((n % i) == 0);
}
// Placing artificial delays in tight-loops will also lead to sub-optimal
// resuts. :-)
delay(100);
}
if(n != 1) {
logger.info("Found factor "+n);
factors.addElement(new Integer(n));
}
int len = factors.size();
int[] result = new int[len];
for(int i = 0; i < len; i++) {
result[i] = ((Integer) factors.elementAt(i)).intValue();
}
// Before leaving a thread we call NDC.remove. This deletes the reference
// to the thread in the internal hash table. Version 0.8.5 introduces a
// a lazy removal mechanism in case you forget to call remove when
// exiting a thread. See the java documentation in NDC.remove for further
// details.
NDC.remove();
return result;
}
static
void usage(String msg) {
System.err.println(msg);
System.err.println(
"Usage: java org.apache.log4j.examples.NumberCruncherServer configFile\n" +
" where configFile is a log4j configuration file.");
System.exit(1);
}
public static
void delay(int millis) {
try{Thread.sleep(millis);}
catch(InterruptedException e) {}
}
public static void main(String[] args) {
if(args.length != 1)
usage("Wrong number of arguments.");
NumberCruncherServer ncs;
PropertyConfigurator.configure(args[0]);
try {
ncs = new NumberCruncherServer();
Naming.rebind("Factor", ncs);
logger.info("NumberCruncherServer bound and ready to serve.");
}
catch(Exception e) {
logger.error("Could not bind NumberCruncherServer.", e);
return;
}
NumberCruncherClient.loop(ncs);
}
}

View File

@ -0,0 +1,95 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package examples;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.Logger;
/**
Example code for log4j to viewed in conjunction with the {@link
examples.SortAlgo SortAlgo} class.
<p>This program expects a configuration file name as its first
argument, and the size of the array to sort as the second and last
argument. See its <b><a href="doc-files/Sort.java">source
code</a></b> for more details.
<p>Play around with different values in the configuration file and
watch the changing behavior.
<p>Example configuration files can be found in <a
href="doc-files/sort1.properties">sort1.properties</a>, <a
href="doc-files/sort2.properties">sort2.properties</a>, <a
href="doc-files/sort3.properties">sort3.properties</a> and <a
href="doc-files/sort4.properties">sort4.properties</a> are supplied with the
package.
<p>If you are also interested in logging performance, then have
look at the {@link org.apache.log4j.performance.Logging} class.
@author Ceki G&uuml;lc&uuml; */
public class Sort {
static Logger logger = Logger.getLogger(Sort.class.getName());
public static void main(String[] args) {
if(args.length != 2) {
usage("Incorrect number of parameters.");
}
int arraySize = -1;
try {
arraySize = Integer.valueOf(args[1]).intValue();
if(arraySize <= 0)
usage("Negative array size.");
}
catch(java.lang.NumberFormatException e) {
usage("Could not number format ["+args[1]+"].");
}
PropertyConfigurator.configure(args[0]);
int[] intArray = new int[arraySize];
logger.info("Populating an array of " + arraySize + " elements in" +
" reverse order.");
for(int i = arraySize -1 ; i >= 0; i--) {
intArray[i] = arraySize - i - 1;
}
SortAlgo sa1 = new SortAlgo(intArray);
sa1.bubbleSort();
sa1.dump();
// We intentionally initilize sa2 with null.
SortAlgo sa2 = new SortAlgo(null);
logger.info("The next log statement should be an error message.");
sa2.dump();
logger.info("Exiting main method.");
}
static
void usage(String errMsg) {
System.err.println(errMsg);
System.err.println("\nUsage: java org.apache.examples.Sort " +
"configFile ARRAY_SIZE\n"+
"where configFile is a configuration file\n"+
" ARRAY_SIZE is a positive integer.\n");
System.exit(1);
}
}

View File

@ -0,0 +1,87 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package examples;
import org.apache.log4j.Logger;
import org.apache.log4j.NDC;
/**
Example code for log4j to viewed in conjunction with the {@link
examples.Sort Sort} class.
<p>SortAlgo uses the bubble sort algorithm to sort an integer
array. See also its <b><a href="doc-files/SortAlgo.java">source
code</a></b>.
@author Ceki G&uuml;lc&uuml; */
public class SortAlgo {
final static String className = SortAlgo.class.getName();
final static Logger LOG = Logger.getLogger(className);
final static Logger OUTER = Logger.getLogger(className + ".OUTER");
final static Logger INNER = Logger.getLogger(className + ".INNER");
final static Logger DUMP = Logger.getLogger(className + ".DUMP");
final static Logger SWAP = Logger.getLogger(className + ".SWAP");
int[] intArray;
SortAlgo(int[] intArray) {
this.intArray = intArray;
}
void bubbleSort() {
LOG.info( "Entered the sort method.");
for(int i = intArray.length -1; i >= 0 ; i--) {
NDC.push("i=" + i);
OUTER.debug("in outer loop.");
for(int j = 0; j < i; j++) {
NDC.push("j=" + j);
// It is poor practice to ship code with log staments in tight loops.
// We do it anyway in this example.
INNER.debug( "in inner loop.");
if(intArray[j] > intArray[j+1])
swap(j, j+1);
NDC.pop();
}
NDC.pop();
}
}
void dump() {
if(! (this.intArray instanceof int[])) {
DUMP.error("Tried to dump an uninitialized array.");
return;
}
DUMP.info("Dump of integer array:");
for(int i = 0; i < this.intArray.length; i++) {
DUMP.info("Element [" + i + "]=" + this.intArray[i]);
}
}
void swap(int l, int r) {
// It is poor practice to ship code with log staments in tight
// loops or code called potentially millions of times.
SWAP.debug( "Swapping intArray["+l+"]=" + intArray[l] +
" and intArray["+r+"]=" + intArray[r]);
int temp = this.intArray[l];
this.intArray[l] = this.intArray[r];
this.intArray[r] = temp;
}
}

View File

@ -0,0 +1,79 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package examples;
import org.apache.log4j.Logger;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.NDC;
/**
View the <a href="doc-files/Trivial.java">source code</a> of this a
trivial usage example. Running <code>java examples.Trivial</code>
should output something similar to:
<pre>
0 INFO [main] examples.Trivial (Client #45890) - Awake awake. Put on thy strength.
15 DEBUG [main] examples.Trivial (Client #45890 DB) - Now king David was old.
278 INFO [main] examples.Trivial$InnerTrivial (Client #45890) - Entered foo.
293 INFO [main] examples.Trivial (Client #45890) - Exiting Trivial.
</pre>
<p> The increasing numbers at the beginning of each line are the
times elapsed since the start of the program. The string between
the parentheses is the nested diagnostic context.
<p>See {@link Sort} and {@link SortAlgo} for sligtly more elaborate
examples.
<p>Note thent class files for the example code is not included in
any of the distributed log4j jar files. You will have to add the
directory <code>/dir-where-you-unpacked-log4j/classes</code> to
your classpath before trying out the examples.
*/
public class Trivial {
static Logger logger = Logger.getLogger(Trivial.class);
public static void main(String[] args) {
BasicConfigurator.configure();
NDC.push("Client #45890");
logger.info("Awake awake. Put on thy strength.");
Trivial.foo();
InnerTrivial.foo();
logger.info("Exiting Trivial.");
}
static
void foo() {
NDC.push("DB");
logger.debug("Now king David was old.");
NDC.pop();
}
static class InnerTrivial {
static Logger logger = Logger.getLogger(InnerTrivial.class);
static
void foo() {
logger.info("Entered foo.");
}
}
}

View File

@ -0,0 +1,90 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package examples.customLevel;
import org.apache.log4j.Level;
/**
This class introduces a new level level called TRACE. TRACE has
lower level than DEBUG.
*/
public class XLevel extends Level {
private static final long serialVersionUID = 2626753561969426769L;
static public final int TRACE_INT = Level.DEBUG_INT - 1;
static public final int LETHAL_INT = Level.FATAL_INT + 1;
private static String TRACE_STR = "TRACE";
private static String LETHAL_STR = "LETHAL";
public static final XLevel TRACE = new XLevel(TRACE_INT, TRACE_STR, 7);
public static final XLevel LETHAL = new XLevel(LETHAL_INT, LETHAL_STR,
0);
protected
XLevel(int level, String strLevel, int syslogEquiv) {
super(level, strLevel, syslogEquiv);
}
/**
Convert the string passed as argument to a level. If the
conversion fails, then this method returns {@link #TRACE}.
*/
public
static
Level toLevel(String sArg) {
return (Level) toLevel(sArg, XLevel.TRACE);
}
public
static
Level toLevel(String sArg, Level defaultValue) {
if(sArg == null) {
return defaultValue;
}
String stringVal = sArg.toUpperCase();
if(stringVal.equals(TRACE_STR)) {
return XLevel.TRACE;
} else if(stringVal.equals(LETHAL_STR)) {
return XLevel.LETHAL;
}
return Level.toLevel(sArg, (Level) defaultValue);
}
public
static
Level toLevel(int i) throws IllegalArgumentException {
switch(i) {
case TRACE_INT: return XLevel.TRACE;
case LETHAL_INT: return XLevel.LETHAL;
}
return Level.toLevel(i);
}
}

View File

@ -0,0 +1,83 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html> <head>
<title></title>
</head>
<body bgcolor=white>
<center><h2>Log4j output of two near-simultaneous requests</h2></center>
<p>Here is the logged output when two clients ask to factor two
integers near-simultanesouly. The client on the host 128.178.50.84
asks to factor the prime number 359. The client on the host 9.4.2.196
asks to factor the number 347 (also a prime).
<p>The NDC is placed between parantheses in bold. The NDC information
consists of the client's host and the number to factor. Since the two
requests have distinct NDCs, their output can be easily separated.
<pre>
0 INFO [main] <b>()</b> - NumberCruncherServer bound and ready to serve.
276493 INFO [RMI TCP Connection(7)-128.178.50.84] <b>(128.178.50.84 359)</b> - Beginning to factor.
276495 DEBUG [RMI TCP Connection(7)-128.178.50.84] <b>(128.178.50.84 359)</b> - Trying to see if 2 is a factor.
276699 DEBUG [RMI TCP Connection(7)-128.178.50.84] <b>(128.178.50.84 359)</b> - Trying to see if 3 is a factor.
276908 DEBUG [RMI TCP Connection(7)-128.178.50.84] <b>(128.178.50.84 359)</b> - Trying to see if 4 is a factor.
276983 INFO [RMI TCP Connection(8)-9.4.2.196] <b>(9.4.2.196 347)</b> - Beginning to factor.
276984 DEBUG [RMI TCP Connection(8)-9.4.2.196] <b>(9.4.2.196 347)</b> - Trying to see if 2 is a factor.
277115 DEBUG [RMI TCP Connection(7)-128.178.50.84] <b>(128.178.50.84 359)</b> - Trying to see if 5 is a factor.
277188 DEBUG [RMI TCP Connection(8)-9.4.2.196] <b>(9.4.2.196 347)</b> - Trying to see if 3 is a factor.
277318 DEBUG [RMI TCP Connection(7)-128.178.50.84] <b>(128.178.50.84 359)</b> - Trying to see if 6 is a factor.
277398 DEBUG [RMI TCP Connection(8)-9.4.2.196] <b>(9.4.2.196 347)</b> - Trying to see if 4 is a factor.
277520 DEBUG [RMI TCP Connection(7)-128.178.50.84] <b>(128.178.50.84 359)</b> - Trying to see if 7 is a factor.
277605 DEBUG [RMI TCP Connection(8)-9.4.2.196] <b>(9.4.2.196 347) </b>- Trying to see if 5 is a factor.
277728 DEBUG [RMI TCP Connection(7)-128.178.50.84] <b>(128.178.50.84 359)</b> - Trying to see if 8 is a factor.
277808 DEBUG [RMI TCP Connection(8)-9.4.2.196] <b>(9.4.2.196 347)</b> - Trying to see if 6 is a factor.
277931 DEBUG [RMI TCP Connection(7)-128.178.50.84] <b>(128.178.50.84 359)</b> - Trying to see if 9 is a factor.
278019 DEBUG [RMI TCP Connection(8)-9.4.2.196] <b>(9.4.2.196 347)</b> - Trying to see if 7 is a factor.
278138 DEBUG [RMI TCP Connection(7)-128.178.50.84] <b>(128.178.50.84 359)</b> - Trying to see if 10 is a factor.
278228 DEBUG [RMI TCP Connection(8)-9.4.2.196] <b>(9.4.2.196 347)</b> - Trying to see if 8 is a factor.
278348 DEBUG [RMI TCP Connection(7)-128.178.50.84] <b>(128.178.50.84 359)</b> - Trying to see if 11 is a factor.
278438 DEBUG [RMI TCP Connection(8)-9.4.2.196] <b>(9.4.2.196 347)</b> - Trying to see if 9 is a factor.
278559 DEBUG [RMI TCP Connection(7)-128.178.50.84] <b>(128.178.50.84 359)</b> - Trying to see if 12 is a factor.
278648 DEBUG [RMI TCP Connection(8)-9.4.2.196] <b>(9.4.2.196 347)</b> - Trying to see if 10 is a factor.
278768 DEBUG [RMI TCP Connection(7)-128.178.50.84] <b>(128.178.50.84 359)</b> - Trying to see if 13 is a factor.
278858 DEBUG [RMI TCP Connection(8)-9.4.2.196] <b>(9.4.2.196 347)</b> - Trying to see if 11 is a factor.
278970 DEBUG [RMI TCP Connection(7)-128.178.50.84] <b>(128.178.50.84 359)</b> - Trying to see if 14 is a factor.
279068 DEBUG [RMI TCP Connection(8)-9.4.2.196] <b>(9.4.2.196 347)</b> - Trying to see if 12 is a factor.
279178 DEBUG [RMI TCP Connection(7)-128.178.50.84] <b>(128.178.50.84 359)</b> - Trying to see if 15 is a factor.
279270 DEBUG [RMI TCP Connection(8)-9.4.2.196] <b>(9.4.2.196 347)</b> - Trying to see if 13 is a factor.
279387 DEBUG [RMI TCP Connection(7)-128.178.50.84] <b>(128.178.50.84 359)</b> - Trying to see if 16 is a factor.
279478 DEBUG [RMI TCP Connection(8)-9.4.2.196] <b>(9.4.2.196 347)</b> - Trying to see if 14 is a factor.
279598 DEBUG [RMI TCP Connection(7)-128.178.50.84] <b>(128.178.50.84 359)</b> - Trying to see if 17 is a factor.
279688 DEBUG [RMI TCP Connection(8)-9.4.2.196] <b>(9.4.2.196 347)</b> - Trying to see if 15 is a factor.
279808 DEBUG [RMI TCP Connection(7)-128.178.50.84] <b>(128.178.50.84 359)</b> - Trying to see if 18 is a factor.
279898 DEBUG [RMI TCP Connection(8)-9.4.2.196] <b>(9.4.2.196 347)</b> - Trying to see if 16 is a factor.
280018 INFO [RMI TCP Connection(7)-128.178.50.84] <b>(128.178.50.84 359)</b> - Found factor 359
280108 DEBUG [RMI TCP Connection(8)-9.4.2.196] <b>(9.4.2.196 347)</b> - Trying to see if 17 is a factor.
280318 DEBUG [RMI TCP Connection(8)-9.4.2.196] <b>(9.4.2.196 347)</b> - Trying to see if 18 is a factor.
280520 INFO [RMI TCP Connection(8)-9.4.2.196] <b>(9.4.2.196 347)</b> - Found factor 347
</pre>
<hr>
<address></address>
<!-- hhmts start -->
Last modified: Fri May 5 10:36:05 MDT 2000
<!-- hhmts end -->
</body> </html>

View File

@ -0,0 +1,45 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
#
#
# For the general syntax of property based configuration files see the
# documenation of org.apache.log4j.PropertyConfigurator.
# The root category uses the appender called A1. Since no priority is
# specified, the root category assumes the default priority for root
# which is DEBUG in log4j. The root category is the only category that
# has a default priority. All other categories need not be assigned a
# priority in which case they inherit their priority from the
# hierarchy.
log4j.rootCategory=, A1
# A1 is set to be a FileAppender which outputs to the file
# "factor.log". Start the server NumberCruncherServer and two
# NumberCruncherClients, and ask to factor two numbers
# near-simultaneously. Notice that the log output from these two
# requests are logged in the file factor.log. Nevertheless, the logs
# of these requests can still be distinguished given their distinct
# nested diagnostic contexts.
log4j.appender.A1=org.apache.log4j.FileAppender
log4j.appender.A1.File=factor.log
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
# Note the %x conversion specifier for NDC printing.
log4j.appender.A1.layout.ConversionPattern=%-4r %-5p [%t] (%x) - %m\n

View File

@ -0,0 +1,135 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package examples.lf5.InitUsingDefaultConfigurator;
import org.apache.log4j.Logger;
import org.apache.log4j.NDC;
import org.apache.log4j.lf5.DefaultLF5Configurator;
import java.io.IOException;
/**
* This class is a simple example of how to configure the LogFactor5
* logging window using the DefaultLF5Configurator.
*
* The DefaultLF5Configurator uses a default configuration file stored
* in the log4j.jar in order to provide a default configuration for
* the LF5Appender.
*
* @author Brent Sprecher
*/
// Contributed by ThoughtWorks Inc.
public class InitUsingDefaultConfigurator {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Protected Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Variables:
//--------------------------------------------------------------------------
private static Logger logger =
Logger.getLogger(InitUsingDefaultConfigurator.class);
//--------------------------------------------------------------------------
// Constructors:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
public static void main(String[] args) throws IOException {
// Configure the LF5Appender using the DefaultLF5Configurator. This
// will add the LF5Appender to the root of the Category tree.
DefaultLF5Configurator.configure();
// Add an NDC to demonstrate how NDC information is output.
NDC.push("#23856");
// Log some information.
for (int i = 0; i < 10; i++) {
logger.debug("Hello, my name is Homer Simpson.");
logger.info("Mmmmmm .... Chocolate.");
logger.warn("Mmm...forbidden donut.");
}
// Clean up NDC
NDC.pop();
NDC.remove();
NDC.push("Another NDC");
// Log some information.
logger.fatal("Hello, my name is Bart Simpson.");
logger.error("Hi diddly ho good neighbour.");
// Clean up NDC
NDC.pop();
NDC.remove();
// Call methods on both classes.
InitUsingDefaultConfigurator.foo();
InnerInitUsingDefaultConfigurator.foo();
logger.info("Exiting InitUsingDefaultConfigurator.");
}
public static void foo() {
logger.debug("Entered foo in InitUsingDefaultConfigurator class");
NDC.push("#123456");
logger.debug("Hello, my name is Marge Simpson.");
logger.info("D'oh!! A deer! A female deer.");
// Clean up NDC
NDC.pop();
NDC.remove();
}
//--------------------------------------------------------------------------
// Protected Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Nested Top-Level Classes or Interfaces:
//--------------------------------------------------------------------------
public static class InnerInitUsingDefaultConfigurator {
static Logger logger =
Logger.getLogger(InnerInitUsingDefaultConfigurator.class.getName());
static void foo() throws IOException {
// Configure the LF5Appender again. You can call
// DefaultLF5Configurator.configure() as often as you want
// without unexpected behavior.
DefaultLF5Configurator.configure();
logger.info("Entered foo in InnerInitUsingDefaultConfigurator class.");
}
}
}

View File

@ -0,0 +1,121 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package examples.lf5.InitUsingLog4JProperties;
import org.apache.log4j.Logger;
import java.io.IOException;
/**
* This class is a simple example of how to use the LogFactor5 logging
* window.
*
* The LF5Appender is the primary class that enables logging to the
* LogFactor5 logging window. The simplest method of using this Appender
* is to add the following line to your log4j.properties file:
*
* log4j.appender.A1=org.apache.log4j.lf5.LF5Appender
*
* The log4j.properties file MUST be in you system classpath. If this file
* is in your system classpath, a static initializer in the Category class
* will load the file during class initialization. The LF5Appender will be
* added to the root category of the Category tree.
*
* Create a log4j.properties file and add this line to it, or add this line
* to your existing log4j.properties file. Run the example at the command line
* and explore the results!
*
* @author Brent Sprecher
*/
// Contributed by ThoughtWorks Inc.
public class InitUsingLog4JProperties {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Protected Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Variables:
//--------------------------------------------------------------------------
private static Logger logger =
Logger.getLogger(InitUsingLog4JProperties.class);
//--------------------------------------------------------------------------
// Constructors:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
public static void main(String argv[]) {
// Add a bunch of logging statements ...
logger.debug("Hello, my name is Homer Simpson.");
logger.debug("Hello, my name is Lisa Simpson.");
logger.debug("Hello, my name is Marge Simpson.");
logger.debug("Hello, my name is Bart Simpson.");
logger.debug("Hello, my name is Maggie Simpson.");
logger.info("We are the Simpsons!");
logger.info("Mmmmmm .... Chocolate.");
logger.info("Homer likes chocolate");
logger.info("Doh!");
logger.info("We are the Simpsons!");
logger.warn("Bart: I am through with working! Working is for chumps!" +
"Homer: Son, I'm proud of you. I was twice your age before " +
"I figured that out.");
logger.warn("Mmm...forbidden donut.");
logger.warn("D'oh! A deer! A female deer!");
logger.warn("Truly, yours is a butt that won't quit." +
"- Bart, writing as Woodrow to Ms. Krabappel.");
logger.error("Dear Baby, Welcome to Dumpsville. Population: you.");
logger.error("Dear Baby, Welcome to Dumpsville. Population: you.",
new IOException("Dumpsville, USA"));
logger.error("Mr. Hutz, are you aware you're not wearing pants?");
logger.error("Mr. Hutz, are you aware you're not wearing pants?",
new IllegalStateException("Error !!"));
logger.fatal("Eep.");
logger.fatal("Mmm...forbidden donut.",
new SecurityException("Fatal Exception"));
logger.fatal("D'oh! A deer! A female deer!");
logger.fatal("Mmmmmm .... Chocolate.",
new SecurityException("Fatal Exception"));
}
//--------------------------------------------------------------------------
// Protected Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Nested Top-Level Classes or Interfaces:
//--------------------------------------------------------------------------
}

View File

@ -0,0 +1,33 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# For the general syntax of property based configuration files see the
# documenation of org.apache.log4j.PropertyConfigurator.
# The root category uses the appender called A1. Since no priority is
# specified, the root category assumes the default priority for root
# which is DEBUG in log4j. The root category is the only category that
# has a default priority. All other categories need not be assigned a
# priority in which case they inherit their priority from the
# hierarchy.
log4j.rootCategory=, A1
# A1 is set to be a LF5Appender which outputs to a swing
# logging console.
log4j.appender.A1=org.apache.log4j.lf5.LF5Appender
log4j.appender.A1.MaxNumberOfRecords=1000

View File

@ -0,0 +1,146 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package examples.lf5.InitUsingMultipleAppenders;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import java.io.IOException;
import java.net.URL;
/**
* This example shows how to use LogFactor5 with other Log4J appenders
* (In this case the RollingFileAppender).
*
* The following lines can be added to the log4j.properties file or a
* standard Java properties file.
*
* # Two appenders are registered with the root of the Category tree.
*
* log4j.rootCategory=, A1, R
*
* # A1 is set to be a LF5Appender which outputs to a swing
* # logging console.
*
* log4j.appender.A1=org.apache.log4j.lf5.LF5Appender
*
* # R is the RollingFileAppender that outputs to a rolling log
* # file called rolling_log_file.log.
*
* log4j.appender.R=org.apache.log4j.RollingFileAppender
* log4j.appender.R.File=rolling_log_file.log
*
* log4j.appender.R.layout=org.apache.log4j.PatternLayout
* log4j.appender.R.layout.ConversionPattern=Date - %d{DATE}%nPriority
* - %p%nThread - %t%nCategory - %c%nLocation - %l%nMessage - %m%n%n
* log4j.appender.R.MaxFileSize=100KB
* log4j.appender.R.MaxBackupIndex=1
*
* To make this example work, either run the InitUsingMultipleAppenders.bat
* file located in the examples folder or run it at the command line. If you
* are running the example at the command line, you must ensure that the
* example.properties file is in your classpath.
*
* @author Brent Sprecher
* @author Brad Marlborough
*/
// Contributed by ThoughtWorks Inc.
public class InitUsingMultipleAppenders {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Protected Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Variables:
//--------------------------------------------------------------------------
private static Logger logger =
Logger.getLogger(InitUsingMultipleAppenders.class);
//--------------------------------------------------------------------------
// Constructors:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
public static void main(String argv[]) {
// Use a PropertyConfigurator to initialize from a property file.
String resource =
"/examples/lf5/InitUsingMultipleAppenders/example.properties";
URL configFileResource =
InitUsingMultipleAppenders.class.getResource(resource);
PropertyConfigurator.configure(configFileResource);
// Add a bunch of logging statements ...
logger.debug("Hello, my name is Homer Simpson.");
logger.debug("Hello, my name is Lisa Simpson.");
logger.debug("Hello, my name is Marge Simpson.");
logger.debug("Hello, my name is Bart Simpson.");
logger.debug("Hello, my name is Maggie Simpson.");
logger.info("We are the Simpsons!");
logger.info("Mmmmmm .... Chocolate.");
logger.info("Homer likes chocolate");
logger.info("Doh!");
logger.info("We are the Simpsons!");
logger.warn("Bart: I am through with working! Working is for chumps!" +
"Homer: Son, I'm proud of you. I was twice your age before " +
"I figured that out.");
logger.warn("Mmm...forbidden donut.");
logger.warn("D'oh! A deer! A female deer!");
logger.warn("Truly, yours is a butt that won't quit." +
"- Bart, writing as Woodrow to Ms. Krabappel.");
logger.error("Dear Baby, Welcome to Dumpsville. Population: you.");
logger.error("Dear Baby, Welcome to Dumpsville. Population: you.",
new IOException("Dumpsville, USA"));
logger.error("Mr. Hutz, are you aware you're not wearing pants?");
logger.error("Mr. Hutz, are you aware you're not wearing pants?",
new IllegalStateException("Error !!"));
logger.fatal("Eep.");
logger.fatal("Mmm...forbidden donut.",
new SecurityException("Fatal Exception"));
logger.fatal("D'oh! A deer! A female deer!");
logger.fatal("Mmmmmm .... Chocolate.",
new SecurityException("Fatal Exception"));
}
//--------------------------------------------------------------------------
// Protected Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Nested Top-Level Classes or Interfaces:
//--------------------------------------------------------------------------
}

View File

@ -0,0 +1,49 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# For the general syntax of property based configuration files see the
# documenation of org.apache.log4j.PropertyConfigurator.
# The root category uses two appenders called A1 and R. Since no priority is
# specified, the root category assumes the default priority for root
# which is DEBUG in log4j. The root category is the only category that
# has a default priority. All other categories need not be assigned a
# priority in which case they inherit their priority from the
# hierarchy.
log4j.rootCategory=, A1, R
# A1 is set to be a LF5Appender which outputs to a swing
# logging console.
log4j.appender.A1=org.apache.log4j.lf5.LF5Appender
# R is the RollingFileAppender that outputs to a rolling log
# file called rolling_log_file.log.
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=rolling_log_file.log
# Define a pattern layout for the file.
# For more information on conversion characters (i.e. d,p,t,c,l,m,n)
# please see the PatternLayout class of the Log4j API.
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=[slf5s.start]%d{DATE}[slf5s.DATE]%n%p[slf5s.PRIORITY]%n%x[slf5s.NDC]%n%t[slf5s.THREAD]%n%c[slf5s.CATEGORY]%n%l[slf5s.LOCATION]%n%m[slf5s.MESSAGE]%n%n
# Set the max size of the file and the number of backup files
log4j.appender.R.MaxFileSize=100KB
log4j.appender.R.MaxBackupIndex=1

View File

@ -0,0 +1,125 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package examples.lf5.InitUsingPropertiesFile;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import java.io.IOException;
import java.net.URL;
/**
* This is another simple example of how to use the LogFactor5
* logging console.
*
* The LF5Appender is the primary class that enables logging to the
* LogFactor5 logging window. If the following line is added to a properties
* file, the LF5Appender will be appended to the root category when
* the properties file is loaded:
*
* log4j.appender.A1=org.apache.log4j.lf5.LF5Appender
*
* To make this example work, you must ensure that the example.properties file
* is in your classpath.You can then run the example at the command line.
*
* @author Brent Sprecher
*/
// Contributed by ThoughtWorks Inc.
public class InitUsingPropertiesFile {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Protected Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Variables:
//--------------------------------------------------------------------------
private static Logger logger =
Logger.getLogger(InitUsingPropertiesFile.class);
//--------------------------------------------------------------------------
// Constructors:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
public static void main(String argv[]) {
// Use a PropertyConfigurator to initialize from a property file.
String resource =
"/examples/lf5/InitUsingPropertiesFile/example.properties";
URL configFileResource =
InitUsingPropertiesFile.class.getResource(resource);
PropertyConfigurator.configure(configFileResource);
// Add a bunch of logging statements ...
logger.debug("Hello, my name is Homer Simpson.");
logger.debug("Hello, my name is Lisa Simpson.");
logger.debug("Hello, my name is Marge Simpson.");
logger.debug("Hello, my name is Bart Simpson.");
logger.debug("Hello, my name is Maggie Simpson.");
logger.info("We are the Simpsons!");
logger.info("Mmmmmm .... Chocolate.");
logger.info("Homer likes chocolate");
logger.info("Doh!");
logger.info("We are the Simpsons!");
logger.warn("Bart: I am through with working! Working is for chumps!" +
"Homer: Son, I'm proud of you. I was twice your age before " +
"I figured that out.");
logger.warn("Mmm...forbidden donut.");
logger.warn("D'oh! A deer! A female deer!");
logger.warn("Truly, yours is a butt that won't quit." +
"- Bart, writing as Woodrow to Ms. Krabappel.");
logger.error("Dear Baby, Welcome to Dumpsville. Population: you.");
logger.error("Dear Baby, Welcome to Dumpsville. Population: you.",
new IOException("Dumpsville, USA"));
logger.error("Mr. Hutz, are you aware you're not wearing pants?");
logger.error("Mr. Hutz, are you aware you're not wearing pants?",
new IllegalStateException("Error !!"));
logger.fatal("Eep.");
logger.fatal("Mmm...forbidden donut.",
new SecurityException("Fatal Exception"));
logger.fatal("D'oh! A deer! A female deer!");
logger.fatal("Mmmmmm .... Chocolate.",
new SecurityException("Fatal Exception"));
}
//--------------------------------------------------------------------------
// Protected Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Nested Top-Level Classes or Interfaces:
//--------------------------------------------------------------------------
}

View File

@ -0,0 +1,33 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# For the general syntax of property based configuration files see the
# documenation of org.apache.log4j.PropertyConfigurator.
# The root category uses the appender called A1. Since no priority is
# specified, the root category assumes the default priority for root
# which is DEBUG in log4j. The root category is the only category that
# has a default priority. All other categories need not be assigned a
# priority in which case they inherit their priority from the
# hierarchy.
log4j.rootCategory=, A1
# A1 is set to be a LF5Appender which outputs to a swing
# logging console.
log4j.appender.A1=org.apache.log4j.lf5.LF5Appender
log4j.appender.A1.MaxNumberOfRecords=700

View File

@ -0,0 +1,119 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package examples.lf5.InitUsingXMLPropertiesFile;
import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;
import java.io.IOException;
import java.net.URL;
/**
* This is another simple example of how to use the LogFactor5
* logging console.
*
* To make this example work, ensure that the lf5.jar, lf5-license.jar
* and example.xml files are in your classpath. Once your classpath has
* been set up, you can run the example from the command line.
*
* @author Brent Sprecher
*/
// Contributed by ThoughtWorks Inc.
public class InitUsingXMLPropertiesFile {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Protected Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Variables:
//--------------------------------------------------------------------------
private static Logger logger =
Logger.getLogger(InitUsingXMLPropertiesFile.class);
//--------------------------------------------------------------------------
// Constructors:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
public static void main(String argv[]) {
// Use a PropertyConfigurator to initialize from a property file.
String resource =
"/examples/lf5/InitUsingXMLPropertiesFile/example.xml";
URL configFileResource =
InitUsingXMLPropertiesFile.class.getResource(resource);
DOMConfigurator.configure(configFileResource.getFile());
// Add a bunch of logging statements ...
logger.debug("Hello, my name is Homer Simpson.");
logger.debug("Hello, my name is Lisa Simpson.");
logger.debug("Hello, my name is Marge Simpson.");
logger.debug("Hello, my name is Bart Simpson.");
logger.debug("Hello, my name is Maggie Simpson.");
logger.info("We are the Simpsons!");
logger.info("Mmmmmm .... Chocolate.");
logger.info("Homer likes chocolate");
logger.info("Doh!");
logger.info("We are the Simpsons!");
logger.warn("Bart: I am through with working! Working is for chumps!" +
"Homer: Son, I'm proud of you. I was twice your age before " +
"I figured that out.");
logger.warn("Mmm...forbidden donut.");
logger.warn("D'oh! A deer! A female deer!");
logger.warn("Truly, yours is a butt that won't quit." +
"- Bart, writing as Woodrow to Ms. Krabappel.");
logger.error("Dear Baby, Welcome to Dumpsville. Population: you.");
logger.error("Dear Baby, Welcome to Dumpsville. Population: you.",
new IOException("Dumpsville, USA"));
logger.error("Mr. Hutz, are you aware you're not wearing pants?");
logger.error("Mr. Hutz, are you aware you're not wearing pants?",
new IllegalStateException("Error !!"));
logger.fatal("Eep.");
logger.fatal("Mmm...forbidden donut.",
new SecurityException("Fatal Exception"));
logger.fatal("D'oh! A deer! A female deer!");
logger.fatal("Mmmmmm .... Chocolate.",
new SecurityException("Fatal Exception"));
}
//--------------------------------------------------------------------------
// Protected Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Nested Top-Level Classes or Interfaces:
//--------------------------------------------------------------------------
}

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<log4j:configuration>
<appender name="LF5Appender" class="org.apache.log4j.lf5.LF5Appender">
<param name="MaxNumberOfRecords" value="1000"/>
</appender>
<root>
<priority value ="debug" />
<appender-ref ref="LF5Appender"/>
</root>
</log4j:configuration>

View File

@ -0,0 +1,110 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package examples.lf5.UsingLogMonitorAdapter;
import org.apache.log4j.lf5.LogLevel;
import org.apache.log4j.lf5.util.LogMonitorAdapter;
/**
* This class is a simple example of how use the LogMonitorAdapter to
* bypass the Log4JAppender and post LogRecords directly to the LogMonitor
* using customized LogLevels
*
* To make this example work, ensure that the lf5.jar and lf5-license.jar
* files are in your classpath, and then run the example at the command line.
*
* @author Richard Hurst
*/
// Contributed by ThoughtWorks Inc.
public class CustomizedLogLevels {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
public final static LogLevel LEVEL_ONE = new LogLevel("LEVEL 1", 1);
public final static LogLevel LEVEL_TWO = new LogLevel("LEVEL 2", 2);
public final static LogLevel LEVEL_THREE = new LogLevel("LEVEL 3", 3);
public final static LogLevel LEVEL_FOUR = new LogLevel("LEVEL 4", 4);
public final static LogLevel DEFAULT = new LogLevel("DEFAULT", 0);
//--------------------------------------------------------------------------
// Protected Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Variables:
//--------------------------------------------------------------------------
private static LogMonitorAdapter _adapter;
static {
// The first LogLevel in the Array will be used as the default LogLevel.
_adapter = LogMonitorAdapter.newInstance(new LogLevel[]{DEFAULT, LEVEL_ONE,
LEVEL_TWO, LEVEL_THREE, LEVEL_FOUR, LogLevel.FATAL});
// if a different log level is to be used it can be specified as such
// _adapter.setDefaultLevel(LEVEL_THREE);
}
//--------------------------------------------------------------------------
// Constructors:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
public static void main(String[] args) {
CustomizedLogLevels test = new CustomizedLogLevels();
test.doMyBidding();
}
public void doMyBidding() {
// tell the LogMonitorAdapter which LogLevel is the severe Level if necessary
_adapter.setSevereLevel(LEVEL_ONE);
String levels = this.getClass().getName();
// will used the default Level
_adapter.log(levels, "Using the customized LogLevels");
_adapter.log(levels, LEVEL_FOUR, "This is a test");
_adapter.log(levels, LEVEL_THREE, "Hmmm fobidden doughnut");
_adapter.log(levels, LEVEL_ONE, "Danger Danger Will Robinson",
new RuntimeException("DANGER"), "32");
_adapter.log(levels, LEVEL_TWO, "Exit stage right->");
_adapter.log(levels, LEVEL_FOUR, "What's up Doc?",
new NullPointerException("Unfortunate exception"));
}
//--------------------------------------------------------------------------
// Protected Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Nested Top-Level Classes or Interfaces:
//--------------------------------------------------------------------------
}

View File

@ -0,0 +1,94 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package examples.lf5.UsingLogMonitorAdapter;
import org.apache.log4j.lf5.LogLevel;
import org.apache.log4j.lf5.util.LogMonitorAdapter;
/**
* This class is a simple example of how use the LogMonitorAdapter to
* bypass the Log4JAppender and post LogRecords directly to the LogMonitor
*
* To make this example work, ensure that the lf5.jar and lf5-license.jar
* files are in your classpath, and then run the example at the command line.
*
* @author Richard Hurst
*/
// Contributed by ThoughtWorks Inc.
public class UsingLogMonitorAdapter {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Protected Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Variables:
//--------------------------------------------------------------------------
private static LogMonitorAdapter _adapter;
static {
_adapter = LogMonitorAdapter.newInstance(LogMonitorAdapter.LOG4J_LOG_LEVELS);
}
//--------------------------------------------------------------------------
// Constructors:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
public static void main(String[] args) {
UsingLogMonitorAdapter test = new UsingLogMonitorAdapter();
test.doMyBidding();
}
public void doMyBidding() {
String logger = this.getClass().getName();
// will default to debug log level
_adapter.log(logger, "Doh this is a debugging");
_adapter.log(logger, LogLevel.INFO, "Hmmm fobidden doughnut");
_adapter.log(logger, LogLevel.WARN, "Danger Danger Will Robinson",
new RuntimeException("DANGER"), "32");
_adapter.log(logger, LogLevel.ERROR, "Exit stage right->");
_adapter.log(logger, LogLevel.FATAL, "What's up Doc?",
new NullPointerException("Unfortunate exception"));
}
//--------------------------------------------------------------------------
// Protected Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Nested Top-Level Classes or Interfaces:
//--------------------------------------------------------------------------
}

View File

@ -0,0 +1,141 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package examples.lf5.UsingSocketAppenders;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import java.io.IOException;
import java.net.URL;
/**
* This is another simple example of how to use the LogFactor5
* logging console.
*
* The LF5Appender is the primary class that enables logging to the
* LogFactor5 logging window. If the following line is added to a properties
* file, the LF5Appender will be appended to the root category when
* the properties file is loaded:
*
* log4j.appender.A1=org.apache.log4j.lf5.LF5Appender
*
* To make this example work, you must ensure that the example.properties file
* is in your classpath.You can then run the example at the command line.
*
* @author Brent Sprecher
*/
// Contributed by ThoughtWorks Inc.
public class UsingSocketAppenders {
//--------------------------------------------------------------------------
// Constants:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Protected Variables:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Variables:
//--------------------------------------------------------------------------
private static Logger logger1 =
Logger.getLogger(UsingSocketAppenders.class);
private static Logger logger2 =
Logger.getLogger("TestClass.Subclass");
private static Logger logger3 =
Logger.getLogger("TestClass.Subclass.Subclass");
//--------------------------------------------------------------------------
// Constructors:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Public Methods:
//--------------------------------------------------------------------------
public static void main(String argv[]) {
// Use a PropertyConfigurator to initialize from a property file.
String resource =
"/examples/lf5/UsingSocketAppenders/socketclient.properties";
URL configFileResource =
UsingSocketAppenders.class.getResource(resource);
PropertyConfigurator.configure(configFileResource);
// Add a bunch of logging statements ...
logger1.debug("Hello, my name is Homer Simpson.");
logger1.debug("Hello, my name is Lisa Simpson.");
logger2.debug("Hello, my name is Marge Simpson.");
logger2.debug("Hello, my name is Bart Simpson.");
logger3.debug("Hello, my name is Maggie Simpson.");
logger2.info("We are the Simpsons!");
logger2.info("Mmmmmm .... Chocolate.");
logger3.info("Homer likes chocolate");
logger3.info("Doh!");
logger3.info("We are the Simpsons!");
logger1.warn("Bart: I am through with working! Working is for chumps!" +
"Homer: Son, I'm proud of you. I was twice your age before " +
"I figured that out.");
logger1.warn("Mmm...forbidden donut.");
logger1.warn("D'oh! A deer! A female deer!");
logger1.warn("Truly, yours is a butt that won't quit." +
"- Bart, writing as Woodrow to Ms. Krabappel.");
logger2.error("Dear Baby, Welcome to Dumpsville. Population: you.");
logger2.error("Dear Baby, Welcome to Dumpsville. Population: you.",
new IOException("Dumpsville, USA"));
logger3.error("Mr. Hutz, are you aware you're not wearing pants?");
logger3.error("Mr. Hutz, are you aware you're not wearing pants?",
new IllegalStateException("Error !!"));
logger3.fatal("Eep.");
logger3.fatal("Mmm...forbidden donut.",
new SecurityException("Fatal Exception ... "));
logger3.fatal("D'oh! A deer! A female deer!");
logger2.fatal("Mmmmmm .... Chocolate.",
new SecurityException("Fatal Exception"));
// Put the main thread is put to sleep for 5 seconds to allow the
// SocketServer to process all incoming messages before the Socket is
// closed. This is done to overcome some basic limitations with the
// way the SocketServer and SocketAppender classes manage sockets.
try {
Thread.sleep(5000);
} catch (InterruptedException ie) {
}
}
//--------------------------------------------------------------------------
// Protected Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Private Methods:
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Nested Top-Level Classes or Interfaces:
//--------------------------------------------------------------------------
}

View File

@ -0,0 +1,33 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# For the general syntax of property based configuration files see the
# documenation of org.apache.log4j.PropertyConfigurator.
# The root category uses the appender called A1. Since no priority is
# specified, the root category assumes the default priority for root
# which is DEBUG in log4j. The root category is the only category that
# has a default priority. All other categories need not be assigned a
# priority in which case they inherit their priority from the
# hierarchy.
log4j.rootCategory=, A1
# A1 is set to be a LF5Appender which outputs to a swing
# logging console.
log4j.appender.A1=org.apache.log4j.net.SocketAppender
log4j.appender.A1.RemoteHost=localhost
log4j.appender.A1.Port=8887

View File

@ -0,0 +1,35 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# For the general syntax of property based configuration files see the
# documenation of org.apache.log4j.PropertyConfigurator.
# The root category uses the appender called A1. Since no priority is
# specified, the root category assumes the default priority for root
# which is DEBUG in log4j. The root category is the only category that
# has a default priority. All other categories need not be assigned a
# priority in which case they inherit their priority from the
# hierarchy.
#log4j.rootCategory=DEBUG, A1
log4j.rootCategory=, A1
# A1 is set to be a LF5Appender which outputs to a swing
# logging console.
#log4j.category.org.apache.log4j.net.SocketNode=DEBUG
log4j.appender.A1=org.apache.log4j.lf5.LF5Appender
log4j.appender.A1.MaxNumberOfRecords=700

View File

@ -0,0 +1,28 @@
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html>
<head>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<p>See <a href="../../docs/lf5/examples.html">Examples</a>
section in the LogFactor5 user guide.
</p>
</body>
</html>

View File

@ -0,0 +1,32 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# The usual stuff. Note that A1 is configured in root not in "some.cat"
log4j.rootLogger=DEBUG, A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%5p [%t] %c - %m%n
# Set the priority of "some.cat" to TRACE (defined in
# examples.customLevel.XLevel). This will actually have the side
# effect of instanciating a logger object having the name "some.cat"
# this will cause a ClassCastException if the logger object is cast
# as a MyLogger object.
log4j.logger.some.cat=TRACE#examples.customLevel.XLevel

View File

@ -0,0 +1,40 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Setting the logger factory to MyLoggerFactory solves the
# ClassCastException problem encountered with the "mycat.bad"
# configuration file.
log4j.loggerFactory=examples.subclass.MyLoggerFactory
# The usual stuff. Note that A1 is configured in root not in "some.cat"
log4j.rootLogger=DEBUG, A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%5p [%t] %c - %m%n
# Set the priority of "some.cat" to TRACE (defined in
# examples.customLevel.XLevel). Since we specified MyLoggerFactory as
# the logger factory, the following line willl also have the side
# effect of instanciating a MyLogger object having the name
# "some.cat".
log4j.logger.some.cat=TRACE#examples.customLevel.XLevel

View File

@ -0,0 +1,54 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html> <head>
<title></title>
</head>
<body>
<p>Example usage of log4j including source code.
<p>Note that class files for the example code is not included in any
of the distributed log4j jar files. You will have to add the directory
<code>/dir-where-you-unpacked-log4j/classes</code> to your classpath
before trying out the examples.
<p>This package's shows how log4j can be used to output log
statements.
<ul>
<p><li>See source code of <a
href="doc-files/Trivial.java">Trivial.java</a> for a trivial usage
example.
<p><li>See source code of <a href="doc-files/Sort.java">Sort.java</a> and
<a href="doc-files/SortAlgo.java">SortAlgo.java</a> to for a slightly
more advanced example.
<p><li>See {@link org.apache.log4j.examples.NumberCruncherServer} for a {@link
org.apache.log4j.NDC} based technique to distinguish the log output from
requests from multiple clients.
</ul>
<hr>
<address></address>
<!-- hhmts start -->
Last modified: Fri May 5 10:20:04 MDT 2000
<!-- hhmts end -->
</body> </html>

View File

@ -0,0 +1,42 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# An example log4j configuration file that outputs to System.out. The
# output information consists of relative time, log level, thread
# name, logger name, nested diagnostic context and the message in that
# order.
# For the general syntax of property based configuration files see the
# documenation of org.apache.log4j.PropertyConfigurator.
log4j.rootLogger=DEBUG, A1
# A1 is set to be a ConsoleAppender which outputs to System.out.
log4j.appender.A1=org.apache.log4j.ConsoleAppender
# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
# The conversion pattern uses format specifiers. You might want to
# change the pattern an watch the output format change.
log4j.appender.A1.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
# In this example, we are not really interested in INNER loop or SWAP
# messages. See the effects of uncommenting and changing the levels of
# the following loggers.
# log4j.logger.org.apache.log4j.examples.SortAlgo.INNER=WARN
# log4j.logger.org.apache.log4j.examples.SortAlgo.SWAP=WARN

View File

@ -0,0 +1,70 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# An example log4j configuration file that outputs both to System.out
# and a file named 'test'.
# For the general syntax of property based configuration files see the
# documenation of org.apache.log4j.PropertyConfigurator.
# WARNING: Location information can be useful but is very costly in
# terms of computation.
# The root logger uses the appender called A1.
# The root logger uses the appenders called A1 and A2. Since no level
# is specified, note the empty string between the comma (",") and the
# equals sign ("="), the level of the root logger remains
# untouched. Log4j always initializes the level for the root logger to
# DEBUG. The root logger is the only logger that has a default
# level. Bu default, all other loggers do not have an assigned level,
# such that they inherit their level instead.
log4j.rootLogger=, A1, A2
# A1 is set to be ConsoleAppender sending its output to System.out
log4j.appender.A1=org.apache.log4j.ConsoleAppender
# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
# The conversion pattern consists of date in ISO8601 format, level,
# thread name, logger name truncated to its rightmost two components
# and left justified to 17 characters, location information consisting
# of file name (padded to 13 characters) and line number, nested
# diagnostic context, the and the application supplied message
log4j.appender.A1.layout.ConversionPattern=%d %-5p [%t] %-17c{2} (%13F:%L) %3x - %m%n
# Appender A2 writes to the file "test".
log4j.appender.A2=org.apache.log4j.FileAppender
log4j.appender.A2.File=test
# Truncate 'test' if it aleady exists.
log4j.appender.A2.Append=false
# Appender A2 uses the PatternLayout.
log4j.appender.A2.layout=org.apache.log4j.PatternLayout
log4j.appender.A2.layout.ConversionPattern=%-5r %-5p [%t] %c{2} - %m%n
# In this example, we are not interested in INNER loop or SWAP
# messages. You might try to set INNER and SWAP to DEBUG for more
# verbose output.
log4j.logger.org.apache.log4j.examples.SortAlgo.INNER=INFO
log4j.logger.org.apache.log4j.examples.SortAlgo.SWAP=INFO

View File

@ -0,0 +1,47 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# An example log4j configuration file that directs its logging output
# to a SocketAppender. The SocketAppender is configuted to send its
# output to a server running on the localhost port number 12345.
# To test this example, you must start a log4j server with the command
#
#
# java org.apache.log4j.net.SocketServer 12345 configurationFile directory/
#
#
# For the general syntax of property based configuration files see
# the documenation of org.apache.log4j.PropertyConfigurator.
# The root logger uses the appender called A1.
log4j.rootLogger=DEBUG, A1
# A1 is set to be a SocketAppender sending its output to the server
running on the local host, port 12345.
log4j.appender.A1=org.apache.log4j.net.SocketAppender
log4j.appender.A1.Port=12345
log4j.appender.A1.RemoteHost=localhost
# In this example, we are not interested in INNER loop or SWAP
# messages. You might try to set INNER and SWAP to DEBUG for more
# verbose output.
log4j.logger.org.apache.log4j.examples.SortAlgo.INNER=INFO
log4j.logger.org.apache.log4j.examples.SortAlgo.SWAP=INFO

View File

@ -0,0 +1,47 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Attach appender A1 to root. Set root level to Level.DEBUG.
log4j.rootLogger=DEBUG, A1
# A1 is set to be a FileAppender sending its output to
# System.out. However, only error messages and above will be printed
# in A1 because A1's threshold is set to Level.ERROR.
# The fact that the root level is set to Prority.DEBUG only influences
# log requests made to the root logger. It has no influence on the
# *appenders* attached to root.
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.Threshold=ERROR
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%p [%t] %c{2} (%M:%L) - %m%n
# Set the level of the logger named "org.apache.log4j.examples" to
# Level.INFO, attach appender A2.
log4j.logger.org.apache.log4j.examples=INFO, A2
# Appender A2 writes to the file "test" in user's home.
log4j.appender.A2=org.apache.log4j.FileAppender
log4j.appender.A2.File=${user.home}/test
# Truncate 'test' if it aleady exists.
log4j.appender.A2.Append=false
# Appender A2 uses the PatternLayout.
log4j.appender.A2.layout=org.apache.log4j.PatternLayout
log4j.appender.A2.layout.ConversionPattern=%5r %-5p [%t] %c{2} - %m%n

View File

@ -0,0 +1,74 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package examples.subclass;
import org.apache.log4j.*;
import examples.customLevel.XLevel;
/**
A simple example showing logger subclassing.
<p>See <b><a href="doc-files/MyLogger.java">source code</a></b>
for more details.
<p>See {@link MyLoggerTest} for a usage example.
*/
public class MyLogger extends Logger {
// It's usually a good idea to add a dot suffix to the fully
// qualified class name. This makes caller localization to work
// properly even from classes that have almost the same fully
// qualified class name as MyLogger, e.g. MyLoggerTest.
static String FQCN = MyLogger.class.getName() + ".";
// It's enough to instantiate a factory once and for all.
private static MyLoggerFactory myFactory = new MyLoggerFactory();
/**
Just calls the parent constuctor.
*/
public MyLogger(String name) {
super(name);
}
/**
Overrides the standard debug method by appending " world" at the
end of each message. */
public
void debug(Object message) {
super.log(FQCN, Level.DEBUG, message + " world.", null);
}
/**
This method overrides {@link Logger#getLogger} by supplying
its own factory type as a parameter.
*/
public
static
Logger getLogger(String name) {
return Logger.getLogger(name, myFactory);
}
public
void trace(Object message) {
super.log(FQCN, XLevel.TRACE, message, null);
}
}

View File

@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package examples.subclass;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggerFactory;
/**
A factory that makes new {@link MyLogger} objects.
See <b><a href="doc-files/MyLoggerFactory.java">source
code</a></b> for more details.
@author Ceki G&uuml;lc&uuml; */
public class MyLoggerFactory implements LoggerFactory {
/**
The constructor should be public as it will be called by
configurators in different packages. */
public
MyLoggerFactory() {
}
public
Logger makeNewLoggerInstance(String name) {
return new MyLogger(name);
}
}

View File

@ -0,0 +1,85 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package examples.subclass;
import org.apache.log4j.*;
import org.apache.log4j.xml.DOMConfigurator;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.helpers.LogLog;
/**
A simple example showing logger subclassing.
<p>The example should make it clear that subclasses follow the
hierarchy. You should also try running this example with a <a
href="doc-files/mycat.bad">bad</a> and <a
href="doc-files/mycat.good">good</a> configuration file samples.
<p>See <b><a
href="doc-files/MyLogger.java">source code</a></b> for more details.
*/
public class MyLoggerTest {
/**
When called wihtout arguments, this program will just print
<pre>
DEBUG [main] some.cat - Hello world.
</pre>
and exit.
<b>However, it can be called with a configuration file in XML or
properties format.
*/
static public void main(String[] args) {
if(args.length == 0) {
// Note that the appender is added to root but that the log
// request is made to an instance of MyLogger. The output still
// goes to System.out.
Logger root = Logger.getRootLogger();
Layout layout = new PatternLayout("%p [%t] %c (%F:%L) - %m%n");
root.addAppender(new ConsoleAppender(layout, ConsoleAppender.SYSTEM_OUT));
}
else if(args.length == 1) {
if(args[0].endsWith("xml")) {
DOMConfigurator.configure(args[0]);
} else {
PropertyConfigurator.configure(args[0]);
}
} else {
usage("Incorrect number of parameters.");
}
try {
MyLogger c = (MyLogger) MyLogger.getLogger("some.cat");
c.trace("Hello");
c.debug("Hello");
} catch(ClassCastException e) {
LogLog.error("Did you forget to set the factory in the config file?", e);
}
}
static
void usage(String errMsg) {
System.err.println(errMsg);
System.err.println("\nUsage: "+MyLogger.class.getName() + "[configFile]\n"
+ " where *configFile* is an optional configuration file, "+
"either in properties or XML format.");
System.exit(1);
}
}

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More