Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * JBoss, Home of Professional Open Source.
   * Copyright 2014 Red Hat, Inc., and individual contributors
   * as indicated by the @author tags.
   *
   * Licensed 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 io.undertow.server.handlers.accesslog;
 
 import java.io.File;
 import java.io.Writer;
 import java.util.Date;
 import java.util.List;
 
Log Receiver that stores logs in a directory under the specified file name, and rotates them after midnight.

Web threads do not touch the log file, but simply queue messages to be written later by a worker thread. A lightweight CAS based locking mechanism is used to ensure than only 1 thread is active writing messages at any given time

Author(s):
Stuart Douglas
 
 public class DefaultAccessLogReceiver implements AccessLogReceiverRunnableCloseable {
     private static final String DEFAULT_LOG_SUFFIX = ".log";
 
     private final Executor logWriteExecutor;
 
     private final Deque<StringpendingMessages;
 
     //0 = not running
     //1 = queued
     //2 = running
     @SuppressWarnings("unused")
     private volatile int state = 0;
 
     private static final AtomicIntegerFieldUpdater<DefaultAccessLogReceiverstateUpdater = AtomicIntegerFieldUpdater.newUpdater(DefaultAccessLogReceiver.class"state");
 
     private long changeOverPoint;
     private String currentDateString;
     private boolean forceLogRotation;
 
     private final File outputDirectory;
     private final File defaultLogFile;
 
     private final String logBaseName;
     private final String logNameSuffix;
 
     private Writer writer = null;
 
     private volatile boolean closed = false;
 
     public DefaultAccessLogReceiver(final Executor logWriteExecutorfinal File outputDirectoryfinal String logBaseName) {
         this(logWriteExecutoroutputDirectorylogBaseNamenull);
     }
 
     public DefaultAccessLogReceiver(final Executor logWriteExecutorfinal File outputDirectoryfinal String logBaseNamefinal String logNameSuffix) {
         this. = logWriteExecutor;
         this. = outputDirectory;
         this. = logBaseName;
         this. = (logNameSuffix != null) ? logNameSuffix : ;
         this. = new ConcurrentLinkedDeque<>();
         this. = new File(outputDirectorylogBaseName + this.);
         calculateChangeOverPoint();
     }
 
     private void calculateChangeOverPoint() {
         Calendar calendar = Calendar.getInstance();
         calendar.set(., 0);
         calendar.set(., 0);
         calendar.set(., 0);
         calendar.add(., 1);
          = calendar.getTimeInMillis();
         SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
         = df.format(new Date());
    }
    @Override
    public void logMessage(final String message) {
        this..add(message);
        int state = .get(this);
        if (state == 0) {
            if (.compareAndSet(this, 0, 1)) {
                .execute(this);
            }
        }
    }

    
processes all queued log messages
    @Override
    public void run() {
        if (!.compareAndSet(this, 1, 2)) {
            return;
        }
        if () {
            doRotate();
        }
        List<Stringmessages = new ArrayList<>();
        String msg = null;
        //only grab at most 1000 messages at a time
        for (int i = 0; i < 1000; ++i) {
            msg = .poll();
            if (msg == null) {
                break;
            }
            messages.add(msg);
        }
        try {
            if (!messages.isEmpty()) {
                writeMessage(messages);
            }
        } finally {
            .set(this, 0);
            //check to see if there is still more messages
            //if so then run this again
            if (!.isEmpty() || ) {
                if (.compareAndSet(this, 0, 1)) {
                    .execute(this);
                }
            } else if() {
                try {
                    .flush();
                    .close();
                     = null;
                } catch (IOException e) {
                    ..errorWritingAccessLog(e);
                }
            }
        }
    }

    
For tests only. Blocks the current thread until all messages are written Just does a busy wait.

DO NOT USE THIS OUTSIDE OF A TEST

    void awaitWrittenForTest() throws InterruptedException {
        while (!.isEmpty() || ) {
            Thread.sleep(10);
        }
        while ( != 0) {
            Thread.sleep(10);
        }
    }
    private void writeMessage(final List<Stringmessages) {
        if (System.currentTimeMillis() > ) {
            doRotate();
        }
        try {
            if ( == null) {
                 = new BufferedWriter(new FileWriter(true));
            }
            for (String message : messages) {
                .write(message);
                .write('\n');
            }
            .flush();
        } catch (IOException e) {
        }
    }
    private void doRotate() {
         = false;
        try {
            if ( != null) {
                .flush();
                .close();
                 = null;
            }
            File newFile = new File( + "_" +  + );
            int count = 0;
            while (newFile.exists()) {
                ++count;
                newFile = new File( + "_" +  + "-" + count + );
            }
            if (!.renameTo(newFile)) {
                ..errorRotatingAccessLog(new IOException());
            }
        } catch (IOException e) {
        } finally {
            calculateChangeOverPoint();
        }
    }

    
forces a log rotation. This rotation is performed in an async manner, you cannot rely on the rotation being performed immediately after this method returns.
    public void rotate() {
         = true;
        if (.compareAndSet(this, 0, 1)) {
            .execute(this);
        }
    }
    @Override
    public void close() throws IOException {
         = true;
        if (.compareAndSet(this, 0, 1)) {
            .execute(this);
        }
    }
New to GrepCode? Check out our FAQ X