1/* 2 * Copyright (C) 2014 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.google.caliper.runner; 18 19import static com.google.common.base.Preconditions.checkState; 20 21import com.google.caliper.runner.TrialOutputFactory.FileAndWriter; 22 23import java.io.Closeable; 24import java.io.File; 25import java.io.IOException; 26import java.io.PrintWriter; 27import java.util.UUID; 28 29import javax.annotation.concurrent.GuardedBy; 30import javax.inject.Inject; 31 32/** 33 * A logger to write trial output to a file. 34 */ 35@TrialScoped final class TrialOutputLogger implements Closeable { 36 @GuardedBy("this") 37 private File file; 38 39 @GuardedBy("this") 40 private PrintWriter writer; 41 42 private final int trialNumber; 43 private final Experiment experiment; 44 private final UUID trialId; 45 private final TrialOutputFactory outputManager; 46 47 @Inject TrialOutputLogger(TrialOutputFactory outputManager, @TrialNumber int trialNumber, 48 @TrialId UUID trialId, Experiment experiment) { 49 this.outputManager = outputManager; 50 this.trialNumber = trialNumber; 51 this.trialId = trialId; 52 this.experiment = experiment; 53 } 54 55 /** Opens the trial output file. */ 56 synchronized void open() throws IOException { 57 if (writer == null) { 58 FileAndWriter fileAndWriter = outputManager.getTrialOutputFile(trialNumber); 59 file = fileAndWriter.file; 60 writer = fileAndWriter.writer; 61 } 62 } 63 64 /** 65 * Ensures that the writer has been opened. also creates a happens-before edge that ensures that 66 * writer is visible (and non-null) after a non-exceptional return from this method. 67 */ 68 private synchronized void checkOpened() { 69 checkState(writer != null, "The logger is not open"); 70 } 71 72 /** Prints header information to the file. */ 73 synchronized void printHeader() { 74 checkOpened(); 75 // make the file self describing 76 // TODO(lukes): we could print the command line here. The user wouldn't be able to run it again 77 // since there would be no runner sending continue messages, but it might be useful to debug 78 // classpath issues. 79 writer.println("Trial Number: " + trialNumber); 80 writer.println("Trial Id: " + trialId); 81 writer.println("Experiment: " + experiment); 82 writer.println(); 83 } 84 85 /** 86 * Logs a line of output to the logger. 87 * 88 * @param source The source of the line (e.g. 'stderr') 89 * @param line The output 90 */ 91 synchronized void log(String source, String line) { 92 checkOpened(); 93 writer.printf("[%s] %s%n", source, line); 94 } 95 96 @Override public synchronized void close() { 97 if (writer != null) { 98 writer.close(); 99 } 100 } 101 102 /** Marks the log file so that it will not be deleted at the end of the benchmark. */ 103 synchronized void ensureFileIsSaved() { 104 checkOpened(); 105 outputManager.persistFile(file); 106 } 107 108 /** Returns the log file path. */ 109 synchronized File trialOutputFile() { 110 checkOpened(); 111 return file; 112 } 113} 114