[英]How do I make multiple threads and classes write into the same log file in Java?
Within a java application, I have several Classes and Threads here and there. 在java应用程序中,我有几个Classes和Threads。 I would like them all to write their logs to one single file. 我希望他们都将他们的日志写入一个文件。 How can I achieve that? 我怎样才能做到这一点?
Also here's some more questions: 还有一些问题:
Do I receive the same instance of a logger if I define the same name for them even in different classes. 如果我为它们定义相同的名称,即使在不同的类中,我也会收到相同的记录器实例。 To be clear, are the following two loggers the same: 需要说明的是,以下两个记录器是相同的:
class MyClass1 { Logger logger1 = Logger.getLogger("theSameName"); } class MyClass2{ Logger logger2 = Logger.getLogger("theSameName"); }
What happens if I define two of the FileHandler
in two separate Threads that have the same file name? 如果我在两个具有相同文件名的独立线程中定义两个FileHandler
会发生什么? Do both of them write to the same file? 他们两个都写到同一个文件? If yes, what happens if the file is already opened by the first one, when the second one tries to open and write to it? 如果是,如果第一个文件已经打开,第二个文件尝试打开并写入文件时会发生什么?
What happens if I try to add the same FielHandler to a logger more than once as in: 如果我尝试将多个FielHandler添加到记录器中,会发生什么情况,如:
logger.addHandler(myFileHandler); // in Thread one ... logger.addHandler(myFileHandler); // in Thread two
Will I receive a RuntimeException
because of the two FileHandler
may try to open the same file simultaneously? 我是否会收到RuntimeException
因为两个FileHandler
可能会尝试同时打开同一个文件?
I'm using java-util-logging
not log4j
. 我正在使用java-util-logging
而不是log4j
。
Make a singleton log class so any other class or thread tries creating a copy of it, will actually be using the same instance. 创建一个单例日志类,以便任何其他类或线程尝试创建它的副本,实际上将使用相同的实例。
Example implementation with java.util.logging
: 使用java.util.logging
示例实现:
public class LogMe {
private static LogMe logMe;
private static Logger logger;
private static FileHandler fh;
private static Formatter sf;
public LogMe() {
//Make this class a singleton
if (logMe != null) {
return;
}
//Create the log file
try {
fh = new FileHandler("../xyz/LogFile.log");
} catch (Exception e) {
e.printStackTrace();
}
sf = new SimpleFormatter();
fh.setFormatter(sf);
logger.addHandler(fh);
//Part of making this class a singleton
logger = Logger.getLogger("LogMe");
logMe = this;
}
public Logger getLogger() {
return LogMe.logger;
}
}
Then in your classes you will be using it like this: 然后在你的课程中你会像这样使用它:
class MyClass1 {
LogMe logMe1 = new LogMe();
Logger logger2 = logMe1.getLogger();
logger.info("X 01");
}
class MyClass2 {
LogMe logMe2 = new LogMe();
Logger logger2 = logMe2.getLogger();
logger.info("X 02");
}
Notice that whatever you name the LogMe
and its Logger
in your classes it won't have any effect because they are referencing the same instance of LogMe
and its Logger
请注意,无论您在类中命名LogMe
及其Logger
,它都不会产生任何影响,因为它们引用了LogMe
及其Logger
的相同实例
Example output in the log file will look something like this: 日志文件中的示例输出如下所示:
Oct 1, 2015 10:43:47 AM
INFO: X 01
Oct 1, 2015 10:43:47 AM
INFO: X 02
Notice that the order of these log lines will depends on the order of execution of your classes. 请注意,这些日志行的顺序取决于类的执行顺序。 Also you won't need any synchronization, quoting JavaDoc of Logger: 您也不需要任何同步,引用Logger的JavaDoc:
All methods on Logger are multi-thread safe. Logger上的所有方法都是多线程安全的。
Do I receive the same instance of a logger if I define the same name for them even in different classes. 如果我为它们定义相同的名称,即使在不同的类中,我也会收到相同的记录器实例。
I don't believe it is defined anywhere, but most like it is the same object and it shouldn't matter. 我不认为它是在任何地方定义的,但大多数人都喜欢它是同一个对象,它应该无关紧要。 The libraries don't determine which file to write to based on Logger instances. 库不会根据Logger实例确定要写入哪个文件。
What happens if I define two FileHandlers in two separate Threads that have the same file name? 如果我在两个具有相同文件名的独立线程中定义两个FileHandler会发生什么?
Most like you will get two logging handlers. 最像您将获得两个日志处理程序。 This means everything will be logged twice unless you attempt to write to the same file in which case it is likely to get corrupted. 这意味着除非您尝试写入同一文件,否则所有内容都将被记录两次,在这种情况下它可能会被破坏。
There is no good reason to do this. 没有充分的理由这样做。 Just define your configuration on start up, once. 只需在启动时定义一次配置即可。
What happens if I try to add the same FielHandler to a logger more than once as in: 如果我尝试将多个FielHandler添加到记录器中,会发生什么情况,如:
It is unlikely the underlying library will notice and it will corrupt the file. 底层库不太可能会注意到它会破坏文件。 If you really need to know, I suggest you try it but don't do this in production. 如果你真的需要知道,我建议你尝试一下,但不要在生产中这样做。
Will I receive a RuntimeException or something because two FileHandler may try to open the same file simultaneously? 我是否会收到RuntimeException,因为两个FileHandler可能会同时尝试打开同一个文件?
This is not what FileOutputStream does or the OS. 这不是FileOutputStream所做的或操作系统。 You just get a corrupted file. 你只是得到一个损坏的文件。
Create a singleton class that will be used by your application. 创建一个将由您的应用程序使用的单例类。
Here is everything you need to know when writing a singleton in Java: http://learnjava.today/2015/08/the-best-singleton-in-java/ 以下是在Java中编写单例时需要了解的所有内容: http : //learnjava.today/2015/08/the-best-singleton-in-java/
Keep coding ;) 继续编码;)
package javaloggers;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
//singleton class logger wrapper
public class LogWrap {
public static final Logger aLogger = Logger.getLogger("myLogger");
private static LogWrap instance = null;
public static LogWrap getInstance(){
if(instance==null){
getLoggerReady();
instance = new LogWrap();
}
return instance;
}
private static void getLoggerReady(){
try{
FileHandler fh = new FileHandler("test-log.txt");
fh.setFormatter(new SimpleFormatter());
aLogger.addHandler(fh);
aLogger.setUseParentHandlers(false);
aLogger.setLevel(Level.ALL);
} catch(Exception e){
System.out.print("Error: Logger creation issue: "+e);
}
}
}
class test {
public static void main(String args[]){
//usage
LogWrap logWrap = LogWrap.getInstance();
logWrap.aLogger.severe( "Hello world!" );
}
}
I have code that pushes data to multiple OutputStreams
. 我有代码将数据推送到多个OutputStreams
。 I use it to duplicate System.out
to both System.out
and a FileOutputStream
. 我用它将System.out
复制到System.out
和FileOutputStream
。
I would basically "reroll" that code so it use multiple input streams to pipe to one "master" file. 我基本上会“重新”重新编写代码,因此它使用多个输入流来管道传输到一个“主”文件。
Here is my code 这是我的代码
// This is an OutputStream that duplicate behavior across multiple OutStreams
public class MultiOutputStream extends OutputStream {
OutputStream[] outputStreams;
public MultiOutputStream(OutputStream... outputStreams) {
this.outputStreams = outputStreams;
}
@Override
public void write(int b) throws IOException {
for (OutputStream out : outputStreams)
out.write(b);
}
@Override
public void write(byte[] b) throws IOException {
for (OutputStream out : outputStreams)
out.write(b);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
for (OutputStream out : outputStreams)
out.write(b, off, len);
}
@Override
public void flush() throws IOException {
for (OutputStream out : outputStreams)
out.flush();
}
@Override
public void close() throws IOException {
for (OutputStream out : outputStreams)
out.close();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.