blob: 6c5b463a3f74afaf058ecf7300a1d7ad70e1e9ca [file] [log] [blame]
// Copyright (C) 2019 The Android Open Source Project
//
// 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.googlesource.gerrit.plugins.auditsl4j;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;
import com.googlesource.gerrit.plugins.auditsl4j.logsource.HTTPLog;
import com.googlesource.gerrit.plugins.auditsl4j.logsource.SSHLog;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Optional;
import java.util.function.Function;
import java.util.zip.GZIPInputStream;
import org.kohsuke.args4j.Option;
@CommandMetaData(name = "transform", description = "Transform ssh and http logs into audit logs")
public class TransformLogsCommand extends SshCommand {
private LoggerAudit loggerAudit;
private final SitePaths sitePaths;
@Inject
public TransformLogsCommand(SitePaths sitePaths, LoggerAudit loggerAudit) {
this.sitePaths = sitePaths;
this.loggerAudit = loggerAudit;
}
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
@Option(name = "--from", usage = "transform logs from <YYYY-MM-DD>")
private String from;
@Option(name = "--until", usage = "transform logs until <YYYY-MM-DD>")
private String until;
@Override
public void run() {
Date dateFrom;
try {
dateFrom = format.parse(from);
} catch (Exception e) {
stderr.print("Invalid 'from' format: " + from + ", expected format <YYYY-MM-DD>");
return;
}
Date dateUntil;
try {
dateUntil = format.parse(until);
} catch (Exception e) {
stderr.print("Invalid 'until' format: " + until + ", expected format <YYYY-MM-DD>");
return;
}
if (dateFrom.after(dateUntil)) {
stderr.print("'from' cannot be after 'until'");
return;
}
Date currentDate = dateFrom;
while (currentDate.compareTo(dateUntil) <= 0) {
transformHttpdLogs(format.format(currentDate));
transformSshdLogs(format.format(currentDate));
currentDate = getTomorrowDate(currentDate);
}
stdout.print("Transformed HTTP and SSH logs from " + from + " until " + until + "!\n");
}
private Date getTomorrowDate(Date currentDate) {
Calendar c = Calendar.getInstance();
c.setTime(currentDate);
c.add(Calendar.DAY_OF_MONTH, 1);
return c.getTime();
}
private void transformSshdLogs(String currentDateString) {
transformLogs(currentDateString, SSHLog.logFilenameBase(), SSHLog::createFromLog);
}
private void transformHttpdLogs(String currentDateString) {
transformLogs(currentDateString, HTTPLog.logFilenameBase(), HTTPLog::createFromLog);
}
private void transformLogs(
String currentDateString,
String fileType,
Function<String, Optional<? extends TransformableLog>> createTransformable) {
// Log format example: httpd_log.2019-01-19.gz
String logFileName = sitePaths.logs_dir + "/" + fileType + "." + currentDateString + ".gz";
String auditLogFileName = sitePaths.logs_dir + "/audit_log." + currentDateString + ".log";
stdout.print("Transforming: " + logFileName + " => " + auditLogFileName + " ...\n");
stdout.flush();
try {
GZIPInputStream gzis = new GZIPInputStream(new FileInputStream(logFileName));
BufferedReader input = new BufferedReader(new InputStreamReader(gzis));
PrintWriter pw =
new PrintWriter(
Files.newBufferedWriter(
Paths.get(auditLogFileName),
StandardOpenOption.CREATE,
StandardOpenOption.WRITE,
StandardOpenOption.APPEND));
input
.lines()
.map(createTransformable)
.map(
maybeTransformableLog ->
maybeTransformableLog.flatMap(
transformableLog -> transformableLog.toAuditLog(loggerAudit)))
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(pw::println);
pw.flush();
} catch (FileNotFoundException fnfe) {
stderr.print("Cannot find '" + logFileName + "'. Skipping!\n");
} catch (IOException e) {
stderr.print("Error: " + e.getMessage() + "!\n");
}
}
}