| // 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"); |
| } |
| } |
| } |