All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xipki.audit.services.EmbedAuditService Maven / Gradle / Ivy

/*
 *
 * Copyright (c) 2013 - 2022 Lijun Liao
 *
 * 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 org.xipki.audit.services;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xipki.audit.AuditEvent;
import org.xipki.audit.AuditLevel;
import org.xipki.audit.AuditService;
import org.xipki.audit.PciAuditEvent;
import org.xipki.password.PasswordResolver;
import org.xipki.password.PasswordResolverException;
import org.xipki.util.ConfPairs;
import org.xipki.util.DateUtil;
import org.xipki.util.LogUtil;
import org.xipki.util.StringUtil;
import org.xipki.util.exception.InvalidConfException;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Locale;
import java.util.TimeZone;

/**
 * The embedded audit service.
 *
 * @author Lijun Liao
 * @since 2.0.0
 */

public class EmbedAuditService implements AuditService {

  public static final String KEY_FILE = "file";

  public static final String KEY_SIZE = "size";

  private static final String DELIM = " | ";

  private static Logger LOG = LoggerFactory.getLogger(EmbedAuditService.class);

  private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern("yyyy.MM.dd-HH:mm:ss.SSS");

  private final ZoneId timeZone = ZoneId.systemDefault();

  private File logDir;

  private String logFileNamePrefix;

  private String logFileNameSuffix;

  private long lastMsOfToday;

  private int maxFileSize;

  private OutputStreamWriter writer;

  private Path writerPath;

  private String writerFileCoreName;

  public EmbedAuditService() {
  }

  @Override
  public void init(String conf) {
    try {
      init(conf, null);
    } catch (PasswordResolverException | InvalidConfException ex) {
      throw new IllegalStateException(ex);
    }
  }

  @Override
  public void init(String conf, PasswordResolver passwordResolver)
      throws PasswordResolverException, InvalidConfException {
    ConfPairs confPairs = new ConfPairs(conf);
    String str = confPairs.value(KEY_SIZE);

    final int mb = 1024 * 1024;

    if (str == null) {
      this.maxFileSize = 10 * mb; // 10 MB
    } else {
      str = str.trim().toLowerCase(Locale.ROOT);
      if (str.endsWith("gb")) {
        this.maxFileSize = Integer.parseInt(str.substring(0, str.length() - 2).trim()) * 1024 * mb;
      } else if (str.endsWith("mb")) {
        this.maxFileSize = Integer.parseInt(str.substring(0, str.length() - 2).trim()) * mb;
      } else if (str.endsWith("kb")) {
        this.maxFileSize = Integer.parseInt(str.substring(0, str.length() - 2).trim()) * 1024;
      } else {
        this.maxFileSize = Integer.parseInt(str);
      }

      if (this.maxFileSize < mb) {
        throw new InvalidConfException("invalid size " + str);
      }
    }

    String logFilePath = confPairs.value(KEY_FILE);

    if (StringUtil.isBlank(logFilePath)) {
      logFilePath = "logs/audit.log";
    }

    File logFile = new File(logFilePath).getAbsoluteFile();
    this.logDir = logFile.getParentFile();
    this.logDir.mkdirs();

    String fileName = logFile.getName();
    int idx = fileName.lastIndexOf('.');
    logFileNameSuffix = idx == -1 ? "" : fileName.substring(idx);

    String prefix = idx == -1 ? fileName : fileName.substring(0, idx);
    this.logFileNamePrefix = prefix + "_";

    // analyze the existing log files
    Calendar now = Calendar.getInstance(TimeZone.getDefault());

    int yyyyMMddNow = DateUtil.getYyyyMMdd(now);
    this.lastMsOfToday = DateUtil.getLastMsOfDay(now);

    this.writer = buildWriter(yyyyMMddNow);
  }

  @Override
  public void logEvent(AuditEvent event) {
    storeLog(AuditService.AUDIT_EVENT, event.getLevel(), event.toTextMessage());
  } // method logEvent

  @Override
  public void logEvent(PciAuditEvent event) {
    storeLog(AuditService.PCI_AUDIT_EVENT, event.getLevel(), event.toTextMessage());
  }

  protected void storeLog(int eventType, AuditLevel level, String message) {
    Instant date = Instant.now();

    String payload = DTF.format(date.atZone(timeZone)) + DELIM + level.getText() + DELIM + eventType + DELIM + message;

    long ms = date.toEpochMilli();
    try {
      long size = Files.size(writerPath);
      if (ms > lastMsOfToday || size >= maxFileSize) {
        long oldLastOfToday = lastMsOfToday;

        Calendar now = Calendar.getInstance(TimeZone.getDefault());
        now.setTimeInMillis(ms);
        int yyyyMMddNow = DateUtil.getYyyyMMdd(now);
        lastMsOfToday = DateUtil.getLastMsOfDay(now);
        writer.close();

        if (oldLastOfToday == lastMsOfToday) {
          for (int i = 1; ;i++) {
            File renameTo = new File(logDir, writerFileCoreName + "-" + i + logFileNameSuffix);
            if (!renameTo.exists()) {
              writerPath.toFile().renameTo(renameTo);
              break;
            }
          }
        }

        writer = buildWriter(yyyyMMddNow);
      }

      writer.write(payload);
      writer.write('\n');
    } catch (Exception ex) {
      LogUtil.error(LOG, ex);
    }
  }

  private OutputStreamWriter buildWriter(int yyyyMMdd) {
    this.writerFileCoreName = buildFileCoreName(yyyyMMdd);
    File currentLogFile = new File(logDir, writerFileCoreName + logFileNameSuffix);
    OutputStream fw;
    try {
      fw = new FileOutputStream(currentLogFile, true);
    } catch (IOException ex) {
      throw new IllegalStateException("error opening file " + currentLogFile.getPath());
    }

    this.writerPath = currentLogFile.toPath();
    return new OutputStreamWriter(fw);
  }

  private String buildFileCoreName(int yyyyMMdd) {
    int year = yyyyMMdd / 10000;
    int month = yyyyMMdd % 10000 / 100;
    int day = yyyyMMdd % 100;
    String dateStr = year + "." + (month < 10 ? "0" + month : month) + "." + (day < 10 ? "0" + day : day);
    return logFileNamePrefix + dateStr;
  }

  @Override
  public void close() throws Exception {
    if (writer != null) {
      writer.flush();
      writer.close();
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy