diff --git a/core/src/main/java/hudson/logging/LogRecorder.java b/core/src/main/java/hudson/logging/LogRecorder.java
index c6ec3e1b41..a2a233df07 100644
--- a/core/src/main/java/hudson/logging/LogRecorder.java
+++ b/core/src/main/java/hudson/logging/LogRecorder.java
@@ -68,7 +68,7 @@ import org.kohsuke.stapler.verb.POST;
* TODO: still a work in progress.
*
*
Access Control
- * {@link LogRecorder} is only visible for administrators, and this access control happens at
+ * {@link LogRecorder} is only visible for administrators and system readers, and this access control happens at
* {@link jenkins.model.Jenkins#getLog()}, the sole entry point for binding {@link LogRecorder} to URL.
*
* @author Kohsuke Kawaguchi
@@ -332,6 +332,8 @@ public class LogRecorder extends AbstractModelObject implements Saveable {
*/
@POST
public synchronized void doConfigSubmit( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
+ Jenkins.get().checkPermission(Jenkins.ADMINISTER);
+
JSONObject src = req.getSubmittedForm();
String newName = src.getString("name"), redirect = ".";
@@ -358,6 +360,8 @@ public class LogRecorder extends AbstractModelObject implements Saveable {
@RequirePOST
public HttpResponse doClear() throws IOException {
+ Jenkins.get().checkPermission(Jenkins.ADMINISTER);
+
handler.clear();
return HttpResponses.redirectToDot();
}
@@ -385,6 +389,8 @@ public class LogRecorder extends AbstractModelObject implements Saveable {
*/
@RequirePOST
public synchronized void doDoDelete(StaplerResponse rsp) throws IOException, ServletException {
+ Jenkins.get().checkPermission(Jenkins.ADMINISTER);
+
getConfigFile().delete();
getParent().logRecorders.remove(name);
// Disable logging for all our targets,
diff --git a/core/src/main/java/hudson/logging/LogRecorderManager.java b/core/src/main/java/hudson/logging/LogRecorderManager.java
index 4bf9730f3a..c74159049d 100644
--- a/core/src/main/java/hudson/logging/LogRecorderManager.java
+++ b/core/src/main/java/hudson/logging/LogRecorderManager.java
@@ -112,6 +112,8 @@ public class LogRecorderManager extends AbstractModelObject implements ModelObje
*/
@RequirePOST
public HttpResponse doNewLogRecorder(@QueryParameter String name) {
+ Jenkins.get().checkPermission(Jenkins.ADMINISTER);
+
Jenkins.checkGoodName(name);
logRecorders.put(name,new LogRecorder(name));
@@ -208,7 +210,7 @@ public class LogRecorderManager extends AbstractModelObject implements ModelObje
@Restricted(NoExternalUse.class)
public Object getTarget() {
if (!SKIP_PERMISSION_CHECK) {
- Jenkins.get().checkPermission(Jenkins.ADMINISTER);
+ Jenkins.get().checkPermission(Jenkins.SYSTEM_READ);
}
return this;
}
diff --git a/core/src/main/java/jenkins/management/SystemLogLink.java b/core/src/main/java/jenkins/management/SystemLogLink.java
index f8c8e9e791..35fadad9fd 100644
--- a/core/src/main/java/jenkins/management/SystemLogLink.java
+++ b/core/src/main/java/jenkins/management/SystemLogLink.java
@@ -26,6 +26,8 @@ package jenkins.management;
import hudson.Extension;
import hudson.model.ManagementLink;
+import hudson.security.Permission;
+import jenkins.model.Jenkins;
import org.jenkinsci.Symbol;
import edu.umd.cs.findbugs.annotations.NonNull;
@@ -55,6 +57,12 @@ public class SystemLogLink extends ManagementLink {
return "log";
}
+ @NonNull
+ @Override
+ public Permission getRequiredPermission() {
+ return Jenkins.SYSTEM_READ;
+ }
+
@NonNull
@Override
public Category getCategory() {
diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java
index dfca35b678..36ce41cbf6 100644
--- a/core/src/main/java/jenkins/model/Jenkins.java
+++ b/core/src/main/java/jenkins/model/Jenkins.java
@@ -2559,7 +2559,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve
* Everything below here is admin-only, so do the check here.
*/
public LogRecorderManager getLog() {
- checkPermission(ADMINISTER);
+ checkPermission(SYSTEM_READ);
return log;
}
diff --git a/core/src/main/resources/hudson/logging/LogRecorder/configure.jelly b/core/src/main/resources/hudson/logging/LogRecorder/configure.jelly
index 6b2dbb9b1e..e1da3dfeb5 100644
--- a/core/src/main/resources/hudson/logging/LogRecorder/configure.jelly
+++ b/core/src/main/resources/hudson/logging/LogRecorder/configure.jelly
@@ -27,9 +27,16 @@ THE SOFTWARE.
-->
-
+
+
${%Configure log recorder}
+
+ ${%Enter the name of the logger you want to enable}.
+
+
+ ${%fine_warning}
+
@@ -74,4 +81,4 @@ THE SOFTWARE.
-
\ No newline at end of file
+
diff --git a/core/src/main/resources/hudson/logging/LogRecorder/configure.properties b/core/src/main/resources/hudson/logging/LogRecorder/configure.properties
new file mode 100644
index 0000000000..4b41a5d3f2
--- /dev/null
+++ b/core/src/main/resources/hudson/logging/LogRecorder/configure.properties
@@ -0,0 +1 @@
+fine_warning=Loggers that record messages at FINE, FINER, or even FINEST can cause performance issues when many messages are being logged. Additionally, more verbose log levels increase the likelihood of credentials being logged. It is recommended that you delete such loggers, or update them to a less verbose level, when you no longer need them.
diff --git a/core/src/main/resources/hudson/logging/LogRecorder/delete.jelly b/core/src/main/resources/hudson/logging/LogRecorder/delete.jelly
index 646f21523b..1dabebcd88 100644
--- a/core/src/main/resources/hudson/logging/LogRecorder/delete.jelly
+++ b/core/src/main/resources/hudson/logging/LogRecorder/delete.jelly
@@ -27,7 +27,7 @@ THE SOFTWARE.
-->
-
+
-
-
+
+
+
+
+
diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/levels.jelly b/core/src/main/resources/hudson/logging/LogRecorderManager/levels.jelly
index 4a4de33506..fb349850a7 100644
--- a/core/src/main/resources/hudson/logging/LogRecorderManager/levels.jelly
+++ b/core/src/main/resources/hudson/logging/LogRecorderManager/levels.jelly
@@ -51,25 +51,27 @@ THE SOFTWARE.
${%defaultLoggerMsg}
-
${%Adjust Levels}
-
- ${%Name}:
- ${%Level}:
-
-
-
-
+
+
${%Adjust Levels}
+
+ ${%Name}:
+ ${%Level}:
+
+
+
+
+
diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel.jelly b/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel.jelly
index f15d0032c5..1e08f2b659 100644
--- a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel.jelly
+++ b/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel.jelly
@@ -33,7 +33,9 @@ THE SOFTWARE.
-
+
+
+
diff --git a/core/src/test/java/hudson/logging/LogRecorderTest.java b/core/src/test/java/hudson/logging/LogRecorderTest.java
index 394a8f42e9..bbb146a637 100644
--- a/core/src/test/java/hudson/logging/LogRecorderTest.java
+++ b/core/src/test/java/hudson/logging/LogRecorderTest.java
@@ -30,10 +30,21 @@ import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.LogRecord;
+import jenkins.model.Jenkins;
import org.junit.Test;
import static org.junit.Assert.*;
-import org.jvnet.hudson.test.Issue;
+import static org.powermock.api.mockito.PowerMockito.mock;
+import static org.powermock.api.mockito.PowerMockito.mockStatic;
+import static org.powermock.api.mockito.PowerMockito.when;
+import org.junit.runner.RunWith;
+import org.jvnet.hudson.test.Issue;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+@PowerMockIgnore({"com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*"})
+@RunWith(PowerMockRunner.class)
public class LogRecorderTest {
@Issue("JENKINS-17983")
@@ -58,11 +69,13 @@ public class LogRecorderTest {
assertFalse(matches("", "hudson.model.Hudson", Level.FINE));
}
+ @PrepareForTest(Jenkins.class)
@Test public void testClearing() throws IOException {
LogRecorder lr = new LogRecorder("foo");
LogRecorder.Target t = new LogRecorder.Target("", Level.FINE);
lr.targets.add(t);
+ createMockJenkins();
LogRecord record = createLogRecord("jenkins", Level.INFO, "message");
lr.handler.publish(record);
assertEquals(lr.handler.getView().get(0), record);
@@ -73,6 +86,12 @@ public class LogRecorderTest {
assertEquals(0, lr.handler.getView().size());
}
+ private void createMockJenkins() {
+ mockStatic(Jenkins.class);
+ Jenkins j = mock(Jenkins.class);
+ when(Jenkins.get()).thenReturn(j);
+ }
+
@Test public void testSpecificExclusion() {
LogRecorder lr = new LogRecorder("foo");