blob: 7d4ab50b692180c02f85095b5d6587b394bb8386 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.karaf.log.command;
import java.io.PrintStream;
import org.apache.karaf.log.core.LogService;
import org.apache.karaf.shell.api.action.Command;
import org.apache.karaf.shell.api.action.lifecycle.Reference;
import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.apache.karaf.shell.api.console.Session;
import org.ops4j.pax.logging.spi.PaxAppender;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
@Command(scope = "log", name = "tail", description = "Continuously display log entries. Use ctrl-c to quit this command")
@Service
public class LogTail extends DisplayLog {
@Reference
Session session;
@Reference
BundleContext context;
@Override
public Object execute() throws Exception {
if (entries == 0) {
entries = 50;
}
int minLevel = getMinLevel(level);
// Do not use System.out as it may write to the wrong console depending on the thread that calls our log handler
PrintStream out = session.getConsole();
display(out, minLevel);
out.flush();
PaxAppender appender = event -> printEvent(out, event, minLevel);
ServiceTracker<LogService, LogService> tracker = new LogServiceTracker(context, LogService.class, null, appender);
tracker.open();
try {
synchronized (this) {
wait();
}
out.println("Stopping tail as log.core bundle was stopped.");
} catch (InterruptedException e) {
// Ignore as it will happen if the user breaks the tail using Ctrl-C
} finally {
tracker.close();
}
out.println();
return null;
}
private synchronized void stopTail() {
notifyAll();
}
/**
* Track LogService dynamically so we can react when the log core bundle stops even while we block for the tail
*/
private final class LogServiceTracker extends ServiceTracker<LogService, LogService> {
private final static String SSHD_LOGGER = "org.apache.sshd";
private final PaxAppender appender;
private String sshdLoggerLevel;
private LogServiceTracker(BundleContext context, Class<LogService> clazz,
ServiceTrackerCustomizer<LogService, LogService> customizer,
PaxAppender appender) {
super(context, clazz, customizer);
this.appender = appender;
}
@Override
public LogService addingService(ServiceReference<LogService> reference) {
LogService service = super.addingService(reference);
sshdLoggerLevel = service.getLevel(SSHD_LOGGER).get(SSHD_LOGGER);
service.setLevel(SSHD_LOGGER, "ERROR");
service.addAppender(appender);
return service;
}
@Override
public void removedService(ServiceReference<LogService> reference, LogService service) {
if (sshdLoggerLevel != null) {
service.setLevel(SSHD_LOGGER, sshdLoggerLevel);
}
service.removeAppender(appender);
stopTail();
}
}
}