/**
 * Copyright 2013 Netflix, Inc.
 *
 * 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 com.netflix.servo.publish;

import com.google.common.base.Preconditions;
import com.google.common.io.Closer;
import com.netflix.servo.Metric;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import java.util.zip.GZIPOutputStream;

/**
 * Writes observations to a file. The format is a basic text file with tabs
 * separating the fields.
 */
public final class FileMetricObserver extends BaseMetricObserver {

    private static final Logger LOGGER =
        LoggerFactory.getLogger(FileMetricObserver.class);

    private static final String FILE_DATE_FORMAT = "yyyy_dd_MM_HH_mm_ss_SSS";
    private final File dir;
    private final boolean compress;
    private final SimpleDateFormat fileFormat;

    /**
     * Creates a new instance that stores files in {@code dir} with a prefix of
     * {@code name} and a suffix of a timestamp in the format
     * {@code yyyy_dd_MM_HH_mm_ss_SSS}.
     *
     * @param name      name to use as a prefix on files
     * @param dir       directory where observations will be stored
     */
    public FileMetricObserver(String name, File dir) {
        this(name, dir, false);
    }

    /**
     * Creates a new instance that stores files in {@code dir} with a prefix of
     * {@code name} and a suffix of a timestamp in the format
     * {@code yyyy_dd_MM_HH_mm_ss_SSS}.
     *
     * @param name      name to use as a prefix on files
     * @param dir       directory where observations will be stored
     * @param compress  whether to compress our output
     */
    public FileMetricObserver(String name, File dir, boolean compress) {
        this(name,
            String.format("'%s'_%s", name, FILE_DATE_FORMAT) + (compress ? "'.log.gz'" : "'.log'"),
            dir,
            compress);
    }

    /**
     * Creates a new instance that stores files in {@code dir} with a name that
     * is created using {@code namePattern}.
     *
     * @param name         name of the observer
     * @param namePattern  date format pattern used to create the file names
     * @param dir          directory where observations will be stored
     * @param compress     whether to compress our output
     */
    public FileMetricObserver(String name, String namePattern, File dir, boolean compress) {
        super(name);
        this.dir = dir;
        this.compress = compress;
        fileFormat = new SimpleDateFormat(namePattern);
        fileFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
    }

    /** {@inheritDoc} */
    public void updateImpl(List<Metric> metrics) {
        Preconditions.checkNotNull(metrics);
        File file = new File(dir, fileFormat.format(new Date()));
        Closer closer = Closer.create();
        Writer out = null;
        try {
            try {
                LOGGER.debug("writing {} metrics to file {}", metrics.size(), file);
                OutputStream fileOut = new FileOutputStream(file, true);
                if (compress) {
                    fileOut = new GZIPOutputStream(fileOut);
                }
                out = closer.register(new OutputStreamWriter(fileOut, "UTF-8"));
                for (Metric m : metrics) {
                    out.append(m.getConfig().getName()).append('\t')
                       .append(m.getConfig().getTags().toString()).append('\t')
                       .append(m.getValue().toString()).append('\n');
                }
            } catch (Throwable t) {
                throw closer.rethrow(t);
            } finally {
                closer.close();
            }
        } catch (IOException e) {
            incrementFailedCount();
            LOGGER.error("failed to write update to file " + file, e);
        }
    }
}

@@ -741,16 +741,100 @@
 Metric;%0A
+import com.netflix.servo.util.Clock;%0Aimport com.netflix.servo.util.ClockWithOffset;%0A
 import o
@@ -846,24 +846,24 @@
 f4j.Logger;%0A
-
 import org.s
@@ -1617,24 +1617,55 @@
 n compress;%0A
+    private final Clock clock;%0A
     private 
@@ -3235,32 +3235,713 @@
 ean compress) %7B%0A
+        this(name, namePattern, dir, compress, ClockWithOffset.INSTANCE);%0A    %7D%0A%0A    /**%0A     * Creates a new instance that stores files in %7B@code dir%7D with a name that%0A     * is created using %7B@code namePattern%7D.%0A     *%0A     * @param name         name of the observer%0A     * @param namePattern  date format pattern used to create the file names%0A     * @param dir          directory where observations will be stored%0A     * @param compress     whether to compress our output%0A     * @param clock        clock instance to use for getting the time used in the filename%0A     */%0A%0A    public FileMetricObserver(String name, String namePattern, File dir, boolean compress, Clock clock) %7B%0A
         super(na
@@ -3999,24 +3999,52 @@
 = compress;%0A
+        this.clock = clock;%0A
         file
@@ -4272,24 +4272,24 @@
 l(metrics);%0A
-
         File
@@ -4337,16 +4337,27 @@
 ew Date(
+clock.now()
 )));%0A   

Use a clock instance for fileMetrics as well