/* This file is part of VoltDB. * Copyright (C) 2008-2017 VoltDB Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with VoltDB. If not, see <http://www.gnu.org/licenses/>. */ package org.voltdb; import org.json_voltpatches.JSONObject; import org.voltcore.network.Connection; import org.voltdb.client.ClientResponse; import org.voltdb.utils.VoltTrace; import java.io.File; import java.util.Collection; public class TraceAgent extends OpsAgent { public TraceAgent() { super("TraceAgent"); } @Override protected void collectStatsImpl(Connection c, long clientHandle, OpsSelector selector, ParameterSet params) throws Exception { JSONObject obj = new JSONObject(); obj.put("selector", OpsSelector.TRACE); String err; if (selector == OpsSelector.TRACE) { err = parseParamsForSystemInformation(params, obj); } else { err = "TraceAgent received non-TRACE selector: " + selector.name(); } if (err != null) { sendErrorResponse(c, ClientResponse.GRACEFUL_FAILURE, err, clientHandle); return; } PendingOpsRequest psr = new PendingOpsRequest(selector, obj.getString("subselector"), c, clientHandle, System.currentTimeMillis(), obj); distributeOpsWork(psr, obj); } // Parse the provided parameter set object and fill in subselector and interval into // the provided JSONObject. If there's an error, return that in the String, otherwise // return null. Yes, ugly. Bang it out, then refactor later. private String parseParamsForSystemInformation(ParameterSet params, JSONObject obj) throws Exception { // Default with no args is OVERVIEW String subselector = "status"; if (params.toArray().length < 1) { return "Incorrect number of arguments to @Trace (expects as least 1, received " + params.toArray().length + ")"; } if (params.toArray().length >= 1) { Object first = params.toArray()[0]; if (!(first instanceof String)) { return "First argument to @Trace must be a valid STRING selector, instead was " + first; } subselector = (String)first; if (!(subselector.equalsIgnoreCase("enable") || subselector.equalsIgnoreCase("disable") || subselector.equalsIgnoreCase("status") || subselector.equalsIgnoreCase("dump"))) { return "Invalid @Trace selector " + subselector; } } // Would be nice to have subselector validation here, maybe. Maybe later. obj.put("subselector", subselector); if (params.toArray().length >= 2) { obj.put("categories", params.toArray()[1]); } obj.put("interval", false); return null; } @Override protected void handleJSONMessage(JSONObject obj) throws Exception { VoltTable[] results = new VoltTable[] {new VoltTable(new VoltTable.ColumnInfo("STATUS", VoltType.STRING))}; OpsSelector selector = OpsSelector.valueOf(obj.getString("selector").toUpperCase()); if (selector != OpsSelector.TRACE) { hostLog.warn("TraceAgent received a non-TRACE OPS selector: " + selector); } final String subselector = obj.getString("subselector"); if (subselector.equalsIgnoreCase("dump")) { final String filePath = VoltTrace.dump(new File(VoltDB.instance().getVoltDBRootPath(), "trace_logs").getAbsolutePath()); if (filePath != null) { results[0].addRow(filePath); } else { results[0].addRow("A trace file write request is already in progress or there is no category enabled"); } } else if (subselector.equalsIgnoreCase("enable")) { VoltTrace.enableCategories(VoltTrace.Category.valueOf(obj.getString("categories").toUpperCase())); } else if (subselector.equalsIgnoreCase("disable")) { VoltTrace.disableCategories(VoltTrace.Category.valueOf(obj.getString("categories").toUpperCase())); } else if (subselector.equalsIgnoreCase("status")) { final Collection<VoltTrace.Category> enabledCategories = VoltTrace.enabledCategories(); if (enabledCategories.isEmpty()) { results[0].addRow("off"); } else { results[0].addRow(enabledCategories.toString()); } } sendOpsResponse(results, obj); } }