Java记录到文件:替代持久性方案

时间:2015-03-08 05:15:50

标签: java logging filehandler

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。

有什么建议吗?

2 个答案:

答案 0 :(得分:0)

答案 1 :(得分:0)

我最终实现了一个库。在Linux和Linux上测试过视窗。它提供了所需的文件持久性方案,并允许异步日志记录。很感激评论。

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) 
           {
           }
       }
}