All Downloads are FREE. Search and download functionalities are using the official Maven repository.

hudson.logging.LogRecorder Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 *
 * Copyright (c) 2004-2009 Oracle Corporation.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * 
*    Kohsuke Kawaguchi
 *
 *
 *******************************************************************************/ 

package hudson.logging;

import com.thoughtworks.xstream.XStream;
import hudson.BulkChange;
import hudson.Util;
import hudson.XmlFile;
import hudson.model.AbstractModelObject;
import hudson.model.Hudson;
import hudson.model.Saveable;
import hudson.model.listeners.SaveableListener;
import hudson.util.CopyOnWriteList;
import hudson.util.RingBufferLogHandler;
import hudson.util.XStream2;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;

import javax.servlet.ServletException;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Arrays;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

/**
 * Records a selected set of logs so that the system administrator can diagnose
 * a specific aspect of the system.
 *
 * TODO: still a work in progress.
 *
 * 

Access Control

{@link LogRecorder} is only visible for * administrators, and this access control happens at {@link Hudson#getLog()}, * the sole entry point for binding {@link LogRecorder} to URL. * * @author Kohsuke Kawaguchi * @see LogRecorderManager */ public class LogRecorder extends AbstractModelObject implements Saveable { private volatile String name; //TODO: review and check whether we can do it private public final CopyOnWriteList targets = new CopyOnWriteList(); private transient /*almost final*/ RingBufferLogHandler handler = new RingBufferLogHandler() { @Override public void publish(LogRecord record) { for (Target t : targets) { if (t.includes(record)) { super.publish(record); return; } } } }; public CopyOnWriteList getTargets() { return targets; } /** * Logger that this recorder monitors, and its log level. Just a pair of * (logger name,level) with convenience methods. */ public static final class Target { public final String name; private final int level; public Target(String name, Level level) { this(name, level.intValue()); } public Target(String name, int level) { this.name = name; this.level = level; } @DataBoundConstructor public Target(String name, String level) { this(name, Level.parse(level.toUpperCase(Locale.ENGLISH))); } public Level getLevel() { return Level.parse(String.valueOf(level)); } public boolean includes(LogRecord r) { if (r.getLevel().intValue() < level) { return false; // below the threshold } String logName = r.getLoggerName(); if (logName == null || !logName.startsWith(name)) { return false; // not within this logger } String rest = r.getLoggerName().substring(name.length()); return rest.startsWith(".") || rest.length() == 0; } public Logger getLogger() { return Logger.getLogger(name); } /** * Makes sure that the logger passes through messages at the correct * level to us. */ public void enable() { Logger l = getLogger(); if (!l.isLoggable(getLevel())) { l.setLevel(getLevel()); } } } public LogRecorder(String name) { this.name = name; // register it only once when constructed, and when this object dies // WeakLogHandler will remove it new WeakLogHandler(handler, Logger.getLogger("")); } public String getDisplayName() { return name; } public String getSearchUrl() { return name; } public String getName() { return name; } public LogRecorderManager getParent() { return Hudson.getInstance().getLog(); } /** * Accepts submission from the configuration page. */ public synchronized void doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { JSONObject src = req.getSubmittedForm(); String newName = src.getString("name"), redirect = "."; XmlFile oldFile = null; if (!name.equals(newName)) { Hudson.checkGoodName(newName); oldFile = getConfigFile(); // rename getParent().logRecorders.remove(name); this.name = newName; getParent().logRecorders.put(name, this); redirect = "../" + Util.rawEncode(newName) + '/'; } List newTargets = req.bindJSONToList(Target.class, src.get("targets")); for (Target t : newTargets) { t.enable(); } targets.replaceBy(newTargets); save(); if (oldFile != null) { oldFile.delete(); } rsp.sendRedirect2(redirect); } /** * Loads the settings from a file. */ public synchronized void load() throws IOException { getConfigFile().unmarshal(this); for (Target t : targets) { t.enable(); } } /** * Save the settings to a file. */ public synchronized void save() throws IOException { if (BulkChange.contains(this)) { return; } getConfigFile().write(this); SaveableListener.fireOnChange(this, getConfigFile()); } /** * Deletes this recorder, then go back to the parent. */ public synchronized void doDoDelete(StaplerResponse rsp) throws IOException, ServletException { requirePOST(); getConfigFile().delete(); getParent().logRecorders.remove(name); // Disable logging for all our targets, // then reenable all other loggers in case any also log the same targets for (Target t : targets) { t.getLogger().setLevel(null); } for (LogRecorder log : getParent().logRecorders.values()) { for (Target t : log.targets) { t.enable(); } } rsp.sendRedirect2(".."); } /** * RSS feed for log entries. */ public void doRss(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { LogRecorderManager.doRss(req, rsp, getDisplayName(), getLogRecords()); } /** * The file we save our configuration. */ private XmlFile getConfigFile() { return new XmlFile(XSTREAM, new File(Hudson.getInstance().getRootDir(), "log/" + name + ".xml")); } /** * Gets a view of the log records. */ public List getLogRecords() { return handler.getView(); } /** * Thread-safe reusable {@link XStream}. */ public static final XStream XSTREAM = new XStream2(); static { XSTREAM.alias("log", LogRecorder.class); XSTREAM.alias("target", Target.class); } /** * Log levels that can be configured for {@link Target}. */ public static List LEVELS = Arrays.asList(Level.SEVERE, Level.WARNING, Level.INFO, Level.CONFIG, Level.FINE, Level.FINER, Level.FINEST, Level.ALL); }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy