【问题标题】:Java logging to File: Alternative persistence schemeJava 日志记录到文件:替代持久性方案
【发布时间】:2015-03-08 05:15:50
【问题描述】:

Java 新手。我想使用记录器,但使用不同的文件持久性方案。我希望在基于时间的文件系统层次结构中创建日志,而不是旋转文件和覆盖,其中日志文件包含过去一分钟的日志:示例:如果在 2015-03-08 13:05 生成日志,它将被放置在 /home/myUser/logs/2015/03/08/13 下的 log_05.txt 中 换句话说,文件完整路径是 /home/myUser/logs/2015/03/08/13/log_05.txt。

有什么建议吗?

【问题讨论】:

  • 谢谢!。使用提示创建库。似乎工作正常。

标签: java logging filehandler


【解决方案1】:

我最终实现了一个库。在 Linux 和 Windows 上测试。它提供了所需的文件持久性方案,并允许异步日志记录。非常感谢 cmets。

package com.signin.ems;

/**
 * The EMSLogger JAR wraps the Java Logger for two purposes:
 * 1. Implement a custom file persistence scheme (other than a single file, or a rotating scheme).
 * In particular, the scheme implemented is one minute files, placed in hourly directories.
 * The file name format is <mm>.log (mm=00..59), and the directory name format is YYYYMMDD24HH.
 * 
 * 2. Logging should be done asynchronously. For this, a dedicated thread is created. When a message is logged,
 * the LogRecord is placed in a BlockingQueue instead of writing the LogRecord to file. The dedicated thread 
 * performs a blocking wait on the queue. Upon retrieving a LogRecord object, it writes the LogRecord to the 
 * proper file 
 *   
 * 
 */

public class EMSLogger 
{
    private static final int m_iQueSize = 100000;
    private static BlockingQueue<LogRecord> m_LogRecordQueue;
    private static EMSLoggerThread m_EMSLoggerThread;
    private static Thread m_thread;
    private static final Logger m_instance = createInstance();

    protected EMSLogger() 
    {
    }

    public static Logger getInstance() {
        return m_instance;
    }

    private static Logger createInstance() 
    {
        MyFileHandler fileHandler  = null;
        Logger LOGGER = null;
        try 
        {
            // initialize the Log queue
            m_LogRecordQueue = new ArrayBlockingQueue<LogRecord>(m_iQueSize);

            // get top level logger
            LOGGER = Logger.getLogger("");
            LOGGER.setLevel(Level.ALL);

            // create our file handler
            fileHandler  = new MyFileHandler(m_LogRecordQueue);
            fileHandler.setLevel(Level.ALL);            
            LOGGER.addHandler(fileHandler);

            // create the logging thread
            m_EMSLoggerThread = new EMSLoggerThread(m_LogRecordQueue, fileHandler);
            m_thread = new Thread(m_EMSLoggerThread);
            m_thread.start();

        } 
        catch (IOException e) 
        {
            e.printStackTrace();
        }       
        return LOGGER;
    }
    public static void Terminate () 
    {
        m_thread.interrupt();
    }
}


public class MyFileHandler extends FileHandler 
{
    private final BlockingQueue<LogRecord> m_queue;
    private BufferedOutputStream m_BufferedOutputStream;
    private String m_RootFolderName;
    private String m_CurrentDirectoryName;
    private String m_CurrentFileName;
    private SimpleDateFormat m_SDfh;
    private SimpleDateFormat m_SDfm;

    public MyFileHandler (BlockingQueue<LogRecord> q) throws IOException, SecurityException 
    {
        super ();
        // use simple formatter. Do not use the default XML
        super.setFormatter (new SimpleFormatter ());

        // get root folder from which to create the log directory hierarchy
        m_RootFolderName = System.getProperty ("user.home") + "/logs";

        // Service can optionally set its name. All hourly directories will
        // be created below the provided name. If no name is given, "Default" 
        // is used
        String sName = System.getProperty ("EMS.ServiceName");
        if (sName != null)
        {
            System.out.println ("EMS.ServiceName = " + sName);
        }
        else
        {
            sName = "Default";
            System.out.println ("Using \"" + sName + "\" as service name");
        }
        m_RootFolderName += "/" + sName;

        // make sure the root folder is created
        new File (m_RootFolderName).mkdirs ();

        // initialize format objects
        m_SDfh = new SimpleDateFormat ("yyyyMMddHH");
        m_SDfm = new SimpleDateFormat ("mm");
        m_CurrentDirectoryName = "";
        m_CurrentFileName = "";
        m_BufferedOutputStream = null;
        m_queue = q;
    }

    // post the record the the queue. Actual writing to the log is done in a dedicated thread
    // note that placing in the queue is done without blocking while waiting for available space 
    @Override
    public void publish (LogRecord record)
    {
        m_queue.offer (record);
    }

    // check if a new file needs to be created
    private void SetCurrentFile ()
    {
        boolean bChangeFile = false;
        Date d = new Date (System.currentTimeMillis());
        String newDirectory = m_RootFolderName + "/" +  m_SDfh.format(d);
        String newFile = m_SDfm.format(d);

        if (!newDirectory.equals(m_CurrentDirectoryName))
        {
            // need to create a new directory and a new file
            m_CurrentDirectoryName = newDirectory;
            new File(m_CurrentDirectoryName).mkdirs();
            bChangeFile = true;
        }
        if (!newFile.equals(m_CurrentFileName))
        {
            // need to create a new file
            m_CurrentFileName = newFile;
            bChangeFile = true;         
        }
        if (bChangeFile)
        {
                try 
                {
                    if (m_BufferedOutputStream != null)
                    {
                        m_BufferedOutputStream.close ();
                    }
                    System.out.println("Creating File: " + m_CurrentDirectoryName + "/" + m_CurrentFileName + ".log");
                    m_BufferedOutputStream = new BufferedOutputStream 
                                                    (new FileOutputStream (m_CurrentDirectoryName + "/" + m_CurrentFileName + ".log", true),2048);

                    this.setOutputStream(m_BufferedOutputStream);
                } 
                catch (IOException e) 
                {
                    e.printStackTrace();
                }                                               
        }
    }

    // method _published is called from the dedicated thread
    public void _publish(LogRecord record)
    {
        // check if a new file needs to be created
        SetCurrentFile ();
        super.publish(record);
    }
}

class EMSLoggerThread implements Runnable 
{
       private final BlockingQueue<LogRecord> m_queue;
       private final MyFileHandler m_MyFileHandler;

       // Constructor
       EMSLoggerThread(BlockingQueue<LogRecord> q, MyFileHandler fh) 
       { 
           m_queue = q;
           m_MyFileHandler = fh;
       }

       public void run() 
       {
           try 
           {
               while (true) 
               {
                   m_MyFileHandler._publish(m_queue.take());
               }
           } 
           catch (InterruptedException ex) 
           {
           }
       }
}

【讨论】:

    【解决方案2】:

    How to create the log file for each record in a specific format using java util logging framework 对此进行了介绍。由于FileHandler will not create directories,您必须将这些示例修改为create directories。如果你要创建一个异步处理程序,你应该遵循Using java.util.logger with a separate thread to write on file 中的建议。

    【讨论】:

    • 太棒了!如果您也对此感兴趣,我会编辑答案以包含有关异步处理程序的一些提示。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-21
    • 1970-01-01
    • 1970-01-01
    • 2020-05-16
    • 2010-12-05
    • 1970-01-01
    相关资源
    最近更新 更多