Add SSH to configure logging level at runtime

Can configure the logging level of loggers with SSH command. This allows
the admin to change the logging level without restarting the server.

Add additional command to print the logging level of loggers.

Change-Id: I3bd3076bf617607430b86d23ca53d48203afcd76
This commit is contained in:
Simon Lei
2014-08-08 11:12:38 -04:00
parent 20984b0500
commit c331a4e92d
6 changed files with 253 additions and 0 deletions

View File

@@ -138,6 +138,12 @@ link:cmd-show-connections.html[gerrit show-connections]::
link:cmd-show-queue.html[gerrit show-queue]::
Display the background work queues, including replication.
link:cmd-logging-ls-level.html[gerrit logging ls-level]::
List loggers and their logging level.
link:cmd-logging-set-level.html[gerrit logging set-level]::
Set the logging level of loggers.
link:cmd-plugin-install.html[gerrit plugin add]::
Alias for 'gerrit plugin install'.

View File

@@ -0,0 +1,43 @@
= gerrit logging ls-level
== NAME
gerrit logging ls-level - view the logging level
gerrit logging ls - view the logging level
== SYNOPSIS
--
'ssh' -p <port> <host> 'gerrit logging ls-level | ls'
<NAME>
--
== DESCRIPTION
View the logging level of specified loggers.
== Options
<NAME>::
Display the loggers which contain the input argument in their name. If this
argument is not provided, all loggers will be printed.
== ACCESS
Caller must have the ADMINISTRATE_SERVER capability.
== Examples
View the logging level of the loggers in the package com.google:
=====
$ssh -p 29418 review.example.com gerrit logging ls-level \
com.google.
=====
View the logging level of every logger
=====
$ssh -p 29418 review.example.com gerrit logging ls-level
=====
GERRIT
------
Part of link:index.html[Gerrit Code Review]
SEARCHBOX
---------

View File

@@ -0,0 +1,51 @@
= gerrit logging set-level
== NAME
gerrit logging set-level - set the logging level
gerrit logging set - set the logging level
== SYNOPSIS
--
'ssh' -p <port> <host> 'gerrit logging set-level | set'
<LEVEL>
<NAME>
--
== DESCRIPTION
Set the logging level of specified loggers.
== Options
<LEVEL>::
Required; logging level for which the loggers should be set.
'reset' can be used to revert all loggers back to their level
at deployment time.
<NAME>::
Set the level of the loggers which contain the input argument in their name.
If this argument is not provided, all loggers will have their level changed.
Note that this argument has no effect if 'reset' is passed in LEVEL.
== ACCESS
Caller must have the ADMINISTRATE_SERVER capability.
== Examples
Change the logging level of the loggers in the package com.google to DEBUG.
=====
$ssh -p 29418 review.example.com gerrit logging set-level \
debug com.google.
=====
Reset the logging level of every logger to what they were at deployment time.
=====
$ssh -p 29418 review.example.com gerrit logging set-level \
reset
=====
GERRIT
------
Part of link:index.html[Gerrit Code Review]
SEARCHBOX
---------

View File

@@ -31,6 +31,7 @@ public class DefaultCommandModule extends CommandModule {
protected void configure() {
final CommandName git = Commands.named("git");
final CommandName gerrit = Commands.named("gerrit");
final CommandName logging = Commands.named(gerrit, "logging");
final CommandName plugin = Commands.named(gerrit, "plugin");
final CommandName testSubmit = Commands.named(gerrit, "test-submit");
@@ -98,5 +99,11 @@ public class DefaultCommandModule extends CommandModule {
command(gerrit, CreateAccountCommand.class);
command(testSubmit, TestSubmitRuleCommand.class);
command(testSubmit, TestSubmitTypeCommand.class);
command(logging).toProvider(new DispatchCommandProvider(logging));
command(logging, SetLoggingLevelCommand.class);
command(logging, ListLoggingLevelCommand.class);
alias(logging, "ls", ListLoggingLevelCommand.class);
alias(logging, "set", SetLoggingLevelCommand.class);
}
}

View File

@@ -0,0 +1,55 @@
// Copyright (C) 2014 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.google.gerrit.sshd.commands;
import static com.google.gerrit.sshd.CommandMetaData.Mode.MASTER_OR_SLAVE;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.kohsuke.args4j.Argument;
import java.util.Enumeration;
import java.util.Map;
import java.util.TreeMap;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
@CommandMetaData(name = "ls-level", description = "list the level of loggers",
runsAt = MASTER_OR_SLAVE)
public class ListLoggingLevelCommand extends SshCommand {
@Argument(index = 0, required = false, metaVar = "NAME", usage = "used to match loggers")
private String name;
@SuppressWarnings("unchecked")
@Override
protected void run() {
Map<String, String> logs = new TreeMap<>();
for (Enumeration<Logger> logger = LogManager.getCurrentLoggers(); logger
.hasMoreElements();) {
Logger log = logger.nextElement();
if (name == null || log.getName().contains(name)) {
logs.put(log.getName(), log.getEffectiveLevel().toString());
}
}
for (Map.Entry<String, String> e : logs.entrySet()) {
stdout.println(e.getKey() + ": " + e.getValue());
}
}
}

View File

@@ -0,0 +1,91 @@
// Copyright (C) 2014 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.google.gerrit.sshd.commands;
import static com.google.gerrit.sshd.CommandMetaData.Mode.MASTER_OR_SLAVE;
import com.google.common.base.Strings;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.helpers.Loader;
import org.kohsuke.args4j.Argument;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
@CommandMetaData(name = "set-level", description = "Change the level of loggers",
runsAt = MASTER_OR_SLAVE)
public class SetLoggingLevelCommand extends SshCommand {
private static final String LOG_CONFIGURATION = "log4j.properties";
private static final String JAVA_OPTIONS_LOG_CONFIG = "log4j.configuration";
private static enum LevelOption {
ALL,
TRACE,
DEBUG,
INFO,
WARN,
ERROR,
FATAL,
OFF,
RESET,
}
@Argument(index = 0, required = true, metaVar = "LEVEL", usage = "logging level to set to")
private LevelOption level;
@Argument(index = 1, required = false, metaVar = "NAME", usage = "used to match loggers")
private String name;
@SuppressWarnings("unchecked")
@Override
protected void run() throws MalformedURLException {
if (level == LevelOption.RESET) {
reset();
} else {
for (Enumeration<Logger> logger = LogManager.getCurrentLoggers(); logger
.hasMoreElements();) {
Logger log = logger.nextElement();
if (name == null || log.getName().contains(name)) {
log.setLevel(Level.toLevel(level.name()));
}
}
}
}
@SuppressWarnings("unchecked")
private static void reset() throws MalformedURLException {
for (Enumeration<Logger> logger = LogManager.getCurrentLoggers();
logger.hasMoreElements();) {
logger.nextElement().setLevel(null);
}
String path = System.getProperty(JAVA_OPTIONS_LOG_CONFIG);
if (Strings.isNullOrEmpty(path)) {
PropertyConfigurator.configure(Loader.getResource(LOG_CONFIGURATION));
} else {
PropertyConfigurator.configure(new URL(path));
}
}
}