/* * Copyright 2012-2017 the original author or authors. * * 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.glowroot.agent; import java.io.File; import java.io.FileWriter; import java.io.PrintWriter; import java.net.URISyntaxException; import java.security.CodeSource; import javax.annotation.Nullable; import com.google.common.annotations.VisibleForTesting; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.RequiresNonNull; import org.h2.tools.Console; import org.h2.tools.Recover; import org.h2.tools.RunScript; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ToolMain { // need to wait to init logger until private static volatile @MonotonicNonNull Logger startupLogger; private ToolMain() {} public static void main(String... args) throws Exception { CodeSource codeSource = ToolMain.class.getProtectionDomain().getCodeSource(); File glowrootJarFile = getGlowrootJarFile(codeSource); File glowrootDir = GlowrootDir.getGlowrootDir(glowrootJarFile); File agentDir = GlowrootDir.getAgentDir(glowrootDir); File logDir = GlowrootDir.getLogDir(agentDir); MainEntryPoint.initLogging(agentDir, logDir); startupLogger = LoggerFactory.getLogger("org.glowroot"); if (args.length == 1 && args[0].equals("h2")) { h2(agentDir); return; } if (args.length == 1 && args[0].equals("recover")) { recover(agentDir); return; } if (args.length == 1 && args[0].equals("mask-central-data")) { maskCentralData(agentDir); return; } MainEntryPoint.runViewer(glowrootDir, agentDir); } @VisibleForTesting static @Nullable File getGlowrootJarFile(@Nullable CodeSource codeSource) throws URISyntaxException { if (codeSource == null) { return null; } File codeSourceFile = new File(codeSource.getLocation().toURI()); if (codeSourceFile.getName().endsWith(".jar")) { return codeSourceFile; } return null; } private static void h2(File agentDir) throws Exception { File dataDir = new File(agentDir, "data"); Console.main(new String[] {"-url", "jdbc:h2:" + dataDir.getPath() + File.separator + "data", "-user", "sa"}); } @RequiresNonNull("startupLogger") private static void recover(File agentDir) throws Exception { File dataDir = new File(agentDir, "data"); File recoverFile = new File(dataDir, "data.h2.sql"); if (recoverFile.exists() && !recoverFile.delete()) { startupLogger.warn("recover failed: cannot delete existing data.h2.sql"); } Recover.main(new String[] {"-dir", dataDir.getPath(), "-db", "data"}); File dbFile = new File(dataDir, "data.h2.db"); File dbBakFile = new File(dataDir, "data.h2.db.bak"); if (dbBakFile.exists() && !dbBakFile.delete()) { startupLogger.warn("recover failed, cannot delete existing file: {}", dbBakFile.getPath()); } if (!dbFile.renameTo(dbBakFile)) { startupLogger.warn("recover failed, cannot rename {} to {}", dbFile.getPath(), dbBakFile.getPath()); return; } RunScript.main( new String[] {"-url", "jdbc:h2:" + dataDir.getPath() + File.separator + "data", "-script", recoverFile.getPath()}); startupLogger.info("recover succeeded"); // clean up if (!dbBakFile.delete()) { startupLogger.info("failed to clean-up, cannot delete file: {}", dbBakFile.getPath()); } if (!recoverFile.delete()) { startupLogger.info("failed to clean-up, cannot delete file: {}", recoverFile.getPath()); } } @RequiresNonNull("startupLogger") private static void maskCentralData(File agentDir) throws Exception { File dataDir = new File(agentDir, "data"); File maskScriptFile = File.createTempFile("mask-central-data", ".sql"); PrintWriter out = new PrintWriter(new FileWriter(maskScriptFile)); try { // mask agent ids and agent rollup ids out.println("update trace set headline = left(headline, position(': ', headline) + 1)" + " || " + applyHash("substr(headline, position(': ', headline) + 2)") + " where transaction_type <> 'Web' and headline like '%: %';"); // mask query strings out.println("update trace set headline = left(headline, position('?', headline))" + " || " + applyHash("substr(headline, position('?', headline) + 1)") + " where transaction_type = 'Web' and headline like '%?%';"); // mask usernames out.println("update trace set user = " + applyHash("user") + " where transaction_type = 'Web'" + " and user is not null;"); } finally { out.close(); } RunScript.main( new String[] {"-url", "jdbc:h2:" + dataDir.getPath() + File.separator + "data", "-user", "sa", "-script", maskScriptFile.getPath()}); // just a temp file, no need to log if delete fails maskScriptFile.delete(); // re-create data file to eliminate any trace of previous values recover(agentDir); } private static String applyHash(String sql) { return "left(hash('sha256', stringtoutf8(" + sql + "), 100000), 40)"; } }