logback可以把N天的日志压缩成一个包(zip,gz),在压缩的时候logback采用后台异步线程的方式来实现,下面咱们就来看看Future接口在logback中的妙用。
先来看下Future接口的全貌吧。
1public interface Future<V> { 2 3 //取消任务 4 boolean cancel(boolean mayInterruptIfRunning); 5 6 // 任务如果被取消就返回true 7 boolean isCancelled(); 8 9 //如果任务完成就返回true 10 boolean isDone(); 11 // 获取线程的执行结果,如果任务没有执行完成就会一直等待 12 V get() throws InterruptedException, ExecutionException; 13 14 //获取任务的执行结果,可以指定一个单位时间,如果在规定的时间内没有完成任务,那么就会抛出TimeoutException异常 15 V get(long timeout, TimeUnit unit) 16 throws InterruptedException, ExecutionException, TimeoutException; 17 18 19 20 21 22 23/** 24 gz压缩方法,用于压缩成.gz文件 25*/ 26 private void gzCompress(String nameOfFile2gz, String nameOfgzedFile) { 27 File file2gz = new File(nameOfFile2gz); 28 29 if (!file2gz.exists()) { 30 addStatus(new WarnStatus("The file to compress named [" + nameOfFile2gz + "] does not exist.", this)); 31 32 return; 33 } 34 35 if (!nameOfgzedFile.endsWith(".gz")) { 36 nameOfgzedFile = nameOfgzedFile + ".gz"; 37 } 38 39 File gzedFile = new File(nameOfgzedFile); 40 41 if (gzedFile.exists()) { 42 addWarn("The target compressed file named [" + nameOfgzedFile + "] exist already. Aborting file compression."); 43 return; 44 } 45 46 addInfo("GZ compressing [" + file2gz + "] as [" + gzedFile + "]"); 47 createMissingTargetDirsIfNecessary(gzedFile); 48 49 BufferedInputStream bis = null; 50 GZIPOutputStream gzos = null; 51 try { 52 bis = new BufferedInputStream(new FileInputStream(nameOfFile2gz)); 53 gzos = new GZIPOutputStream(new FileOutputStream(nameOfgzedFile)); 54 byte[] inbuf = new byte[BUFFER_SIZE]; 55 int n; 56 57 while ((n = bis.read(inbuf)) != -1) { 58 gzos.write(inbuf, 0, n); 59 } 60 61 bis.close(); 62 bis = null; 63 gzos.close(); 64 gzos = null; 65 66 if (!file2gz.delete()) { 67 addStatus(new WarnStatus("Could not delete [" + nameOfFile2gz + "].", this)); 68 } 69 } catch (Exception e) { 70 addStatus(new ErrorStatus("Error occurred while compressing [" + nameOfFile2gz + "] into [" + nameOfgzedFile + "].", this, e)); 71 } finally { 72 if (bis != null) { 73 try { 74 bis.close(); 75 } catch (IOException e) { 76 // ignore 77 } 78 } 79 if (gzos != null) { 80 try { 81 gzos.close(); 82 } catch (IOException e) { 83 // ignore 84 } 85 } 86 } 87 } 88 89 90 //工厂方法,可以根据传入的类型来判断是使用gz,还是zip压缩 91 public void compress(String nameOfFile2Compress, String nameOfCompressedFile, String innerEntryName) { 92 switch (compressionMode) { 93 case GZ: 94 gzCompress(nameOfFile2Compress, nameOfCompressedFile); 95 break; 96 case ZIP: 97 zipCompress(nameOfFile2Compress, nameOfCompressedFile, innerEntryName); 98 break; 99 case NONE: 100 throw new UnsupportedOperationException("compress method called in NONE compression mode"); 101 } 102 } 103 104 105 106 107 108
logback 把压缩的任务交给了一个线程去执行
1 //开启一个线程用于压缩日志文件 2 public Future<?> asyncCompress(String nameOfFile2Compress, String nameOfCompressedFile, String innerEntryName) throws RolloverFailure { 3 CompressionRunnable runnable = new CompressionRunnable(nameOfFile2Compress, nameOfCompressedFile, innerEntryName); 4 ExecutorService executorService = context.getExecutorService(); 5 Future<?> future = executorService.submit(runnable); 6 return future; 7 } 8 9 //压缩线程 10 class CompressionRunnable implements Runnable { 11 final String nameOfFile2Compress; 12 final String nameOfCompressedFile; 13 final String innerEntryName; 14 15 public CompressionRunnable(String nameOfFile2Compress, String nameOfCompressedFile, String innerEntryName) { 16 this.nameOfFile2Compress = nameOfFile2Compress; 17 this.nameOfCompressedFile = nameOfCompressedFile; 18 this.innerEntryName = innerEntryName; 19 } 20 21 public void run() { 22 Compressor.this.compress(nameOfFile2Compress, nameOfCompressedFile, innerEntryName); 23 } 24 } 25 26 27
stop方法才是重头戏,当调用stop方法的时候,需要检查有没有线程在正在进行压缩工作,可以看出logback使用Future的特性就是检测某个后台任务是否在指定时间内完成任务。
1 @Override 2 public void stop() { 3 if (!isStarted()) 4 return; 5 //检查任务是否完成 6 //压缩任务 7 waitForAsynchronousJobToStop(compressionFuture, "compression"); 8 //clean任务 9 waitForAsynchronousJobToStop(cleanUpFuture, "clean-up"); 10 super.stop(); 11 } 12 13 private void waitForAsynchronousJobToStop(Future<?> aFuture, String jobDescription) { 14 if (aFuture != null) { 15 try { 16 //获取执行结果 17 aFuture.get(CoreConstants.SECONDS_TO_WAIT_FOR_COMPRESSION_JOBS, TimeUnit.SECONDS); 18 } catch (TimeoutException e) { 19 addError("Timeout while waiting for " + jobDescription + " job to finish", e); 20 } catch (Exception e) { 21 addError("Unexpected exception while waiting for " + jobDescription + " job to finish", e); 22 } 23 } 24 }