<commit_before>/*
 * Copyright (C) 2017 Google 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.google.gapid.util;

import com.google.common.collect.Sets;
import com.google.gapid.proto.log.Log;
import com.google.gapid.util.Flags.Flag;
import com.google.protobuf.MessageOrBuilder;
import com.google.protobuf.Timestamp;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Set;
import java.util.function.Consumer;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import java.util.logging.StreamHandler;

import io.grpc.Status;

/**
 * Logging setup and utilities.
 */
public class Logging {
  /**
   * Possible log level flag values.
   */
  public enum LogLevel {
    OFF(Level.OFF, Log.Severity.Fatal, "Fatal", "F"),
    ERROR(Level.SEVERE, Log.Severity.Error, "Error", "E"),
    WARNING(Level.WARNING, Log.Severity.Warning, "Warning", "W"),
    INFO(Level.INFO, Log.Severity.Info, "Info", "I"),
    DEBUG(Level.FINE, Log.Severity.Debug, "Debug", "D"),
    ALL(Level.ALL, Log.Severity.Debug, "Debug", "V");

    public final Level level;
    public final Log.Severity severity;
    public final String gapisLevel;
    public final String gapirLevel;

    LogLevel(Level level, Log.Severity severity, String gapisLevel, String gapirLevel) {
      this.level = level;
      this.severity = severity;
      this.gapisLevel = gapisLevel;
      this.gapirLevel = gapirLevel;
    }

    static LogLevel fromLevel(Level level) {
      int intLevel = level.intValue();
      switch (intLevel) {
        case 1000: return ERROR;
        case  900: return WARNING;
        case  800: case  700: return INFO;
        case  500: case  400: case  300: return DEBUG;
        default:
          if (intLevel > 1000) {
            return ERROR;
          } else if (intLevel > 900) {
            return WARNING;
          } else if (intLevel > 700) {
            return INFO;
          } else {
            return DEBUG;
          }
      }
    }
  }

  /**
   * Listener is the interface implemented by types that want to listen to log messages.
   */
  public interface Listener {
    void onNewMessage(Log.Message message);
  }

  public static final Flag<LogLevel> logLevel = Flags.value(
      "log-level", LogLevel.INFO, "Logging level [OFF, ERROR, WARNING, INFO, DEBUG, ALL].");
  public static final Flag<String> logDir = Flags.value(
      "log-dir", System.getProperty("java.io.tmpdir"), "Directory for log files.");
  // Actual default is to use logLevel's value.
  public static final Flag<LogLevel> gapisLogLevel = Flags.value(
      "gapis-log-level", LogLevel.INFO, "Gapis log level [OFF, ERROR, WARNING, INFO, DEBUG, ALL].");
  // Actual default is to use logLevel's value.
  public static final Flag<LogLevel> gapirLogLevel = Flags.value(
      "gapir-log-level", LogLevel.INFO, "Gapir log level [OFF, ERROR, WARNING, INFO, DEBUG, ALL].");

  private static final int BUFFER_SIZE = 1000;
  private static final long THROTTLE_TIME_MS = 5000;

  private static final RingBuffer buffer = new RingBuffer(BUFFER_SIZE);

  private static final Listener NULL_LISTENER = (m) -> { /* do nothing */ };

  private static Listener listener = NULL_LISTENER;
  private static long timeOfLastThrottledMessage = 0;

  /**
   * Initializes the Java logging system.
   */
  public static void init() {
    LogManager.getLogManager().reset();
    Logger rootLogger = Logger.getLogger("");

    rootLogger.addHandler(new LogToMessageHandler() {{
      setFormatter(new LogFormatter());
      setLevel(Level.ALL);
    }});

    ConsoleHandler handler = new ConsoleHandler();
    handler.setFormatter(new LogFormatter());
    handler.setLevel(Level.ALL);
    rootLogger.addHandler(handler);

    if (!logDir.get().isEmpty()) {
      try {
        FileHandler fileHandler = new FileHandler(logDir.get() + File.separator + "gapic.log");
        fileHandler.setFormatter(new LogFormatter());
        fileHandler.setLevel(Level.ALL);
        rootLogger.addHandler(fileHandler);
      } catch (IOException e) {
        // Ignore.
      }
    }

    Logger.getLogger("com.google.gapid").setLevel(logLevel.get().level);
  }

  public static File getLogDir() {
    return logDir.get().isEmpty() ? null : new File(logDir.get());
  }

  public static String getGapisLogLevel() {
    return (gapisLogLevel.isSpecified() ? gapisLogLevel.get() : logLevel.get()).gapisLevel;
  }

  public static String getGapirLogLevel() {
    return (gapirLogLevel.isSpecified() ? gapirLogLevel.get() : logLevel.get()).gapirLevel;
  }

  public static MessageIterator getMessageIterator() {
    return buffer.iterator();
  }

  public static void setListener(Listener newListener) {<commit_msg>Handle log file creation errors in the client.<commit_after>/*
 * Copyright (C) 2017 Google 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.google.gapid.util;

import com.google.common.collect.Sets;
import com.google.gapid.proto.log.Log;
import com.google.gapid.util.Flags.Flag;
import com.google.protobuf.MessageOrBuilder;
import com.google.protobuf.Timestamp;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Set;
import java.util.function.Consumer;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import java.util.logging.StreamHandler;

import io.grpc.Status;

/**
 * Logging setup and utilities.
 */
public class Logging {
  /**
   * Possible log level flag values.
   */
  public enum LogLevel {
    OFF(Level.OFF, Log.Severity.Fatal, "Fatal", "F"),
    ERROR(Level.SEVERE, Log.Severity.Error, "Error", "E"),
    WARNING(Level.WARNING, Log.Severity.Warning, "Warning", "W"),
    INFO(Level.INFO, Log.Severity.Info, "Info", "I"),
    DEBUG(Level.FINE, Log.Severity.Debug, "Debug", "D"),
    ALL(Level.ALL, Log.Severity.Debug, "Debug", "V");

    public final Level level;
    public final Log.Severity severity;
    public final String gapisLevel;
    public final String gapirLevel;

    LogLevel(Level level, Log.Severity severity, String gapisLevel, String gapirLevel) {
      this.level = level;
      this.severity = severity;
      this.gapisLevel = gapisLevel;
      this.gapirLevel = gapirLevel;
    }

    static LogLevel fromLevel(Level level) {
      int intLevel = level.intValue();
      switch (intLevel) {
        case 1000: return ERROR;
        case  900: return WARNING;
        case  800: case  700: return INFO;
        case  500: case  400: case  300: return DEBUG;
        default:
          if (intLevel > 1000) {
            return ERROR;
          } else if (intLevel > 900) {
            return WARNING;
          } else if (intLevel > 700) {
            return INFO;
          } else {
            return DEBUG;
          }
      }
    }
  }

  /**
   * Listener is the interface implemented by types that want to listen to log messages.
   */
  public interface Listener {
    void onNewMessage(Log.Message message);
  }

  public static final Flag<LogLevel> logLevel = Flags.value(
      "log-level", LogLevel.INFO, "Logging level [OFF, ERROR, WARNING, INFO, DEBUG, ALL].");
  public static final Flag<String> logDir = Flags.value(
      "log-dir", System.getProperty("java.io.tmpdir"), "Directory for log files.");
  // Actual default is to use logLevel's value.
  public static final Flag<LogLevel> gapisLogLevel = Flags.value(
      "gapis-log-level", LogLevel.INFO, "Gapis log level [OFF, ERROR, WARNING, INFO, DEBUG, ALL].");
  // Actual default is to use logLevel's value.
  public static final Flag<LogLevel> gapirLogLevel = Flags.value(
      "gapir-log-level", LogLevel.INFO, "Gapir log level [OFF, ERROR, WARNING, INFO, DEBUG, ALL].");

  private static final int BUFFER_SIZE = 1000;
  private static final long THROTTLE_TIME_MS = 5000;

  private static final RingBuffer buffer = new RingBuffer(BUFFER_SIZE);

  private static final Listener NULL_LISTENER = (m) -> { /* do nothing */ };

  private static Listener listener = NULL_LISTENER;
  private static long timeOfLastThrottledMessage = 0;

  /**
   * Initializes the Java logging system.
   */
  public static void init() {
    LogManager.getLogManager().reset();
    Logger rootLogger = Logger.getLogger("");

    rootLogger.addHandler(new LogToMessageHandler() {{
      setFormatter(new LogFormatter());
      setLevel(Level.ALL);
    }});

    ConsoleHandler handler = new ConsoleHandler();
    handler.setFormatter(new LogFormatter());
    handler.setLevel(Level.ALL);
    rootLogger.addHandler(handler);

    initFileHandler(rootLogger);

    Logger.getLogger("com.google.gapid").setLevel(logLevel.get().level);
  }

  private static void initFileHandler(Logger rootLogger) {
    if (!logDir.get().isEmpty()) {
      File dir = new File(logDir.get());
      dir.mkdirs();

      File file = new File(dir, "gapic.log");
      for (int i = 0; i < 10; i++) {
        if (!file.exists() || file.canWrite()) {
          try {
            FileHandler fileHandler = new FileHandler(file.getAbsolutePath());
            fileHandler.setFormatter(new LogFormatter());
            fileHandler.setLevel(Level.ALL);
            rootLogger.addHandler(fileHandler);
            return;
          } catch (IOException e) {
            System.err.println("Failed to create log file " + file + ":");
            e.printStackTrace(System.err);
          }
        }

        // Try a different name next.
        file = new File(dir, "gapic-" + i + ".log");
      }

      // Give up.
      System.err.println("Failed to create log file in " + logDir.get());
    }
  }

  public static File getLogDir() {
    return logDir.get().isEmpty() ? null : new File(logDir.get());
  }

  public static String getGapisLogLevel() {
    return (gapisLogLevel.isSpecified() ? gapisLogLevel.get() : logLevel.get()).gapisLevel;
  }

  public static String getGapirLogLevel() {
    return (gapirLogLevel.isSpecified() ? gapirLogLevel.get() : logLevel.get()).gapirLevel;
  }

  public static MessageIterator getMessageIterator() {
    return buffer.iterator();
  }

  public static void setListener(Listener newListener) {
{'fraction_non_alphanumeric': 0.11610869750404634, 'fraction_numerical': 0.00860379930147372, 'mean_word_length': 3.1988555078683834, 'pattern_counts': {'":': 1, '<': 12, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3864278', 'n_tokens_mistral': 3598, 'n_tokens_neox': 3436, 'n_words': 994}