001/** 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014package ch.qos.logback.core; 015 016import java.io.File; 017import java.io.IOException; 018import java.nio.channels.FileChannel; 019 020import org.junit.Before; 021import org.junit.Ignore; 022import org.junit.Test; 023 024import ch.qos.logback.core.contention.RunnableWithCounterAndDone; 025import ch.qos.logback.core.encoder.EchoEncoder; 026import ch.qos.logback.core.recovery.RecoveryCoordinator; 027import ch.qos.logback.core.recovery.ResilientFileOutputStream; 028import ch.qos.logback.core.status.OnConsoleStatusListener; 029import ch.qos.logback.core.testUtil.CoreTestConstants; 030import ch.qos.logback.core.testUtil.RandomUtil; 031import ch.qos.logback.core.util.ResilienceUtil; 032 033public class FileAppenderResilienceTest { 034 035 FileAppender<Object> fa = new FileAppender<Object>(); 036 Context context = new ContextBase(); 037 int diff = RandomUtil.getPositiveInt(); 038 String outputDirStr = CoreTestConstants.OUTPUT_DIR_PREFIX + "resilience-" + diff + "/"; 039 040 // String outputDirStr = "\\\\192.168.1.3\\lbtest\\" + "resilience-"+ diff + 041 // "/";; 042 String logfileStr = outputDirStr + "output.log"; 043 044 @Before 045 public void setUp() throws InterruptedException { 046 047 context.getStatusManager().add(new OnConsoleStatusListener()); 048 049 File outputDir = new File(outputDirStr); 050 outputDir.mkdirs(); 051 052 fa.setContext(context); 053 fa.setName("FILE"); 054 fa.setEncoder(new EchoEncoder<Object>()); 055 fa.setFile(logfileStr); 056 fa.start(); 057 } 058 059 @Test 060 @Ignore 061 public void manual() throws InterruptedException, IOException { 062 Runner runner = new Runner(fa); 063 Thread t = new Thread(runner); 064 t.start(); 065 066 while (true) { 067 Thread.sleep(110); 068 } 069 } 070 071 @Test 072 public void smoke() throws InterruptedException, IOException { 073 Runner runner = new Runner(fa); 074 Thread t = new Thread(runner); 075 t.start(); 076 077 double delayCoefficient = 2.0; 078 for (int i = 0; i < 5; i++) { 079 Thread.sleep((int) (RecoveryCoordinator.BACKOFF_COEFFICIENT_MIN * delayCoefficient)); 080 closeLogFileOnPurpose(); 081 } 082 runner.setDone(true); 083 t.join(); 084 085 double bestCaseSuccessRatio = 1 / delayCoefficient; 086 // expect to loose at most 35% of the events 087 double lossinessFactor = 0.35; 088 double resilianceFactor = (1 - lossinessFactor); 089 090 ResilienceUtil.verify(logfileStr, "^hello (\\d{1,5})$", runner.getCounter(), bestCaseSuccessRatio * resilianceFactor); 091 } 092 093 private void closeLogFileOnPurpose() throws IOException { 094 ResilientFileOutputStream resilientFOS = (ResilientFileOutputStream) fa.getOutputStream(); 095 FileChannel fileChannel = resilientFOS.getChannel(); 096 fileChannel.close(); 097 } 098} 099 100class Runner extends RunnableWithCounterAndDone { 101 FileAppender<Object> fa; 102 103 Runner(FileAppender<Object> fa) { 104 this.fa = fa; 105 } 106 107 public void run() { 108 while (!isDone()) { 109 counter++; 110 fa.doAppend("hello " + counter); 111 if (counter % 128 == 0) { 112 try { 113 Thread.sleep(10); 114 } catch (InterruptedException e) { 115 } 116 } 117 } 118 } 119 120}