added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.logreader-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
|
||||
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
|
||||
|
||||
<feature name="openhab-binding-logreader" description="Log Reader Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.logreader/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.logreader.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link LogReaderBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Miika Jukka - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class LogReaderBindingConstants {
|
||||
|
||||
private static final String BINDING_ID = "logreader";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_READER = new ThingTypeUID(BINDING_ID, "reader");
|
||||
|
||||
// List of all Channel ids
|
||||
public static final String CHANNEL_LASTWARNING = "lastWarningEvent";
|
||||
public static final String CHANNEL_LASTERROR = "lastErrorEvent";
|
||||
public static final String CHANNEL_LASTCUSTOMEVENT = "lastCustomEvent";
|
||||
public static final String CHANNEL_WARNINGS = "warningEvents";
|
||||
public static final String CHANNEL_ERRORS = "errorEvents";
|
||||
public static final String CHANNEL_CUSTOMEVENTS = "customEvents";
|
||||
public static final String CHANNEL_LOGROTATED = "logRotated";
|
||||
|
||||
public static final String CHANNEL_NEWWARNING = "newWarningEvent";
|
||||
public static final String CHANNEL_NEWERROR = "newErrorEvent";
|
||||
public static final String CHANNEL_NEWCUSTOM = "newCustomEvent";
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.logreader.internal;
|
||||
|
||||
import static org.openhab.binding.logreader.internal.LogReaderBindingConstants.THING_READER;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.logreader.internal.filereader.FileTailer;
|
||||
import org.openhab.binding.logreader.internal.handler.LogHandler;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
|
||||
/**
|
||||
* The {@link LogReaderHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Miika Jukka - Initial contribution
|
||||
*/
|
||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.logreader")
|
||||
@NonNullByDefault
|
||||
public class LogReaderHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections
|
||||
.unmodifiableSet(Stream.of(THING_READER).collect(Collectors.toSet()));
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
if (thingTypeUID.equals(THING_READER)) {
|
||||
return new LogHandler(thing, new FileTailer());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.logreader.internal.config;
|
||||
|
||||
/**
|
||||
* Configuration class for {@link LogReaderBinding} binding.
|
||||
*
|
||||
* @author Pauli Anttila - Initial contribution
|
||||
*/
|
||||
public class LogReaderConfiguration {
|
||||
public String filePath;
|
||||
public int refreshRate;
|
||||
public String warningPatterns;
|
||||
public String warningBlacklistingPatterns;
|
||||
public String errorPatterns;
|
||||
public String errorBlacklistingPatterns;
|
||||
public String customPatterns;
|
||||
public String customBlacklistingPatterns;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + "filePath=" + filePath + ", refreshRate=" + refreshRate + ", warningPatterns=" + warningPatterns
|
||||
+ ", warningBlacklistingPatterns=" + warningBlacklistingPatterns + ", errorPatterns=" + errorPatterns
|
||||
+ ", errorBlacklistingPatterns=" + errorBlacklistingPatterns + ", customPatterns=" + customPatterns
|
||||
+ ", customBlacklistingPatterns=" + customBlacklistingPatterns + "]";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.logreader.internal.filereader;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import org.openhab.binding.logreader.internal.filereader.api.FileReaderListener;
|
||||
import org.openhab.binding.logreader.internal.filereader.api.LogFileReader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Base class for LogFileReader implementations. Implements base functions which are same for all LogFileReaders.
|
||||
*
|
||||
* @author Pauli Anttila - Initial contribution
|
||||
*/
|
||||
public abstract class AbstractLogFileReader implements LogFileReader {
|
||||
private final Logger logger = LoggerFactory.getLogger(AbstractLogFileReader.class);
|
||||
|
||||
private List<FileReaderListener> fileReaderListeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
@Override
|
||||
public boolean registerListener(FileReaderListener fileReaderListener) {
|
||||
Objects.requireNonNull(fileReaderListener, "It's not allowed to pass a null FileReaderListener.");
|
||||
return fileReaderListeners.contains(fileReaderListener) ? false : fileReaderListeners.add(fileReaderListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unregisterListener(FileReaderListener fileReaderListener) {
|
||||
Objects.requireNonNull(fileReaderListener, "It's not allowed to pass a null FileReaderListener.");
|
||||
return fileReaderListeners.remove(fileReaderListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send file not found event to all registered listeners.
|
||||
*
|
||||
*/
|
||||
public void sendFileNotFoundToListeners() {
|
||||
for (FileReaderListener fileReaderListener : fileReaderListeners) {
|
||||
try {
|
||||
fileReaderListener.fileNotFound();
|
||||
} catch (Exception e) {
|
||||
// catch all exceptions give all handlers a fair chance of handling the messages
|
||||
logger.debug("An exception occurred while calling the FileReaderListener. ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send read log line to all registered listeners.
|
||||
*
|
||||
*/
|
||||
public void sendLineToListeners(String line) {
|
||||
for (FileReaderListener fileReaderListener : fileReaderListeners) {
|
||||
try {
|
||||
fileReaderListener.handle(line);
|
||||
} catch (Exception e) {
|
||||
// catch all exceptions give all handlers a fair chance of handling the messages
|
||||
logger.debug("An exception occurred while calling the FileReaderListener. ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send file rotation event to all registered listeners.
|
||||
*
|
||||
*/
|
||||
public void sendFileRotationToListeners() {
|
||||
for (FileReaderListener fileReaderListener : fileReaderListeners) {
|
||||
try {
|
||||
fileReaderListener.fileRotated();
|
||||
} catch (Exception e) {
|
||||
// catch all exceptions give all handlers a fair chance of handling the messages
|
||||
logger.debug("An exception occurred while calling the FileReaderListener. ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send exception event to all registered listeners.
|
||||
*
|
||||
*/
|
||||
public void sendExceptionToListeners(Exception e) {
|
||||
for (FileReaderListener fileReaderListener : fileReaderListeners) {
|
||||
try {
|
||||
fileReaderListener.handle(e);
|
||||
} catch (Exception ex) {
|
||||
// catch all exceptions give all handlers a fair chance of handling the messages
|
||||
logger.debug("An exception occurred while calling the FileReaderListener. ", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.logreader.internal.filereader;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import org.apache.commons.io.input.Tailer;
|
||||
import org.apache.commons.io.input.TailerListener;
|
||||
import org.apache.commons.io.input.TailerListenerAdapter;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.logreader.internal.filereader.api.FileReaderException;
|
||||
import org.openhab.binding.logreader.internal.filereader.api.LogFileReader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Apache Tailer based log file reader implementation.
|
||||
*
|
||||
* @author Pauli Anttila - Initial contribution
|
||||
*/
|
||||
public class FileTailer extends AbstractLogFileReader implements LogFileReader {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(FileTailer.class);
|
||||
|
||||
private Tailer tailer;
|
||||
private ExecutorService executor;
|
||||
|
||||
TailerListener logListener = new TailerListenerAdapter() {
|
||||
|
||||
@Override
|
||||
public void handle(@Nullable String line) {
|
||||
sendLineToListeners(line);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fileNotFound() {
|
||||
sendFileNotFoundToListeners();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(@Nullable Exception e) {
|
||||
sendExceptionToListeners(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fileRotated() {
|
||||
sendFileRotationToListeners();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void start(String filePath, long refreshRate) throws FileReaderException {
|
||||
tailer = new Tailer(new File(filePath), logListener, refreshRate, true, false, true);
|
||||
executor = Executors.newSingleThreadExecutor();
|
||||
try {
|
||||
logger.debug("Start executor");
|
||||
executor.execute(tailer);
|
||||
logger.debug("Executor started");
|
||||
} catch (Exception e) {
|
||||
throw new FileReaderException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
logger.debug("Shutdown");
|
||||
if (tailer != null) {
|
||||
tailer.stop();
|
||||
}
|
||||
if (executor != null) {
|
||||
executor.shutdown();
|
||||
}
|
||||
logger.debug("Shutdown complite");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.logreader.internal.filereader.api;
|
||||
|
||||
/**
|
||||
* Exception for file reader errors.
|
||||
*
|
||||
* @author Pauli Anttila - Initial contribution
|
||||
*/
|
||||
public class FileReaderException extends Exception {
|
||||
private static final long serialVersionUID = 1272957002073978608L;
|
||||
|
||||
public FileReaderException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public FileReaderException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.logreader.internal.filereader.api;
|
||||
|
||||
/**
|
||||
* Interface for file reader listeners.
|
||||
*
|
||||
* @author Pauli Anttila - Initial contribution
|
||||
*/
|
||||
public interface FileReaderListener {
|
||||
|
||||
/**
|
||||
* This method is called if the file is not found.
|
||||
*/
|
||||
void fileNotFound();
|
||||
|
||||
/**
|
||||
* This method is called if a file rotation is detected.
|
||||
*
|
||||
*/
|
||||
void fileRotated();
|
||||
|
||||
/**
|
||||
* This method is called when new line is detected.
|
||||
*
|
||||
* @param line the line.
|
||||
*/
|
||||
void handle(String line);
|
||||
|
||||
/**
|
||||
* This method is called when exception has occurred.
|
||||
*
|
||||
* @param ex the exception.
|
||||
*/
|
||||
void handle(Exception ex);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.logreader.internal.filereader.api;
|
||||
|
||||
/**
|
||||
* Interface for log file readers.
|
||||
*
|
||||
* @author Pauli Anttila - Initial contribution
|
||||
*/
|
||||
public interface LogFileReader {
|
||||
|
||||
/**
|
||||
* Register listener.
|
||||
*
|
||||
* @param fileReaderListener callback implementation to register.
|
||||
* @return true if registering successfully done.
|
||||
*/
|
||||
boolean registerListener(FileReaderListener fileReaderListener);
|
||||
|
||||
/**
|
||||
* Unregister listener.
|
||||
*
|
||||
* @param fileReaderListener callback implementation to unregister.
|
||||
* @return true if unregistering successfully done.
|
||||
*/
|
||||
boolean unregisterListener(FileReaderListener fileReaderListener);
|
||||
|
||||
/**
|
||||
* Start log file reader.
|
||||
*
|
||||
* @param filePath file to read.
|
||||
* @param refreshRate how often file is read.
|
||||
* @throws FileReaderException
|
||||
*/
|
||||
void start(String filePath, long refreshRate) throws FileReaderException;
|
||||
|
||||
/**
|
||||
* Stop log file reader.
|
||||
*/
|
||||
void stop();
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.logreader.internal.handler;
|
||||
|
||||
import static org.openhab.binding.logreader.internal.LogReaderBindingConstants.*;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
import org.openhab.binding.logreader.internal.config.LogReaderConfiguration;
|
||||
import org.openhab.binding.logreader.internal.filereader.api.FileReaderListener;
|
||||
import org.openhab.binding.logreader.internal.filereader.api.LogFileReader;
|
||||
import org.openhab.binding.logreader.internal.searchengine.SearchEngine;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link LogReaderHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Miika Jukka - Initial contribution
|
||||
* @author Pauli Anttila - Rewrite
|
||||
*/
|
||||
public class LogHandler extends BaseThingHandler implements FileReaderListener {
|
||||
private final Logger logger = LoggerFactory.getLogger(LogHandler.class);
|
||||
|
||||
private LogReaderConfiguration configuration;
|
||||
|
||||
private LogFileReader fileReader;
|
||||
|
||||
private SearchEngine errorEngine;
|
||||
private SearchEngine warningEngine;
|
||||
private SearchEngine customEngine;
|
||||
|
||||
public LogHandler(Thing thing, LogFileReader fileReader) {
|
||||
super(thing);
|
||||
this.fileReader = fileReader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_ERRORS:
|
||||
updateChannel(channelUID, command, errorEngine);
|
||||
break;
|
||||
|
||||
case CHANNEL_WARNINGS:
|
||||
updateChannel(channelUID, command, warningEngine);
|
||||
break;
|
||||
|
||||
case CHANNEL_CUSTOMEVENTS:
|
||||
updateChannel(channelUID, command, customEngine);
|
||||
break;
|
||||
|
||||
default:
|
||||
logger.debug("Unsupported command '{}' received for channel '{}'", command, channelUID);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
configuration = getConfigAs(LogReaderConfiguration.class);
|
||||
|
||||
configuration.filePath = configuration.filePath.replaceFirst("\\$\\{OPENHAB_LOGDIR\\}",
|
||||
System.getProperty("openhab.logdir"));
|
||||
|
||||
logger.debug("Using configuration: {}", configuration);
|
||||
|
||||
clearCounters();
|
||||
|
||||
try {
|
||||
warningEngine = new SearchEngine(configuration.warningPatterns, configuration.warningBlacklistingPatterns);
|
||||
errorEngine = new SearchEngine(configuration.errorPatterns, configuration.errorBlacklistingPatterns);
|
||||
customEngine = new SearchEngine(configuration.customPatterns, configuration.customBlacklistingPatterns);
|
||||
|
||||
} catch (PatternSyntaxException e) {
|
||||
logger.debug("Illegal search pattern syntax '{}'. ", e.getMessage(), e);
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug("Start file reader");
|
||||
|
||||
try {
|
||||
fileReader.registerListener(this);
|
||||
fileReader.start(configuration.filePath, configuration.refreshRate);
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} catch (Exception e) {
|
||||
logger.debug("Exception occurred during initalization: {}. ", e.getMessage(), e);
|
||||
shutdown();
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.debug("Stopping thing");
|
||||
shutdown();
|
||||
}
|
||||
|
||||
private void updateChannel(ChannelUID channelUID, Command command, SearchEngine matcher) {
|
||||
if (command instanceof DecimalType) {
|
||||
matcher.setMatchCount(((DecimalType) command).longValue());
|
||||
} else if (command instanceof RefreshType) {
|
||||
updateState(channelUID.getId(), new DecimalType(matcher.getMatchCount()));
|
||||
} else {
|
||||
logger.debug("Unsupported command '{}' received for channel '{}'", command, channelUID);
|
||||
}
|
||||
}
|
||||
|
||||
private void clearCounters() {
|
||||
if (errorEngine != null) {
|
||||
errorEngine.clearMatchCount();
|
||||
}
|
||||
if (warningEngine != null) {
|
||||
warningEngine.clearMatchCount();
|
||||
}
|
||||
if (customEngine != null) {
|
||||
customEngine.clearMatchCount();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateChannelIfLinked(String channelID, State state) {
|
||||
if (isLinked(channelID)) {
|
||||
updateState(channelID, state);
|
||||
}
|
||||
}
|
||||
|
||||
private void shutdown() {
|
||||
logger.debug("Stop file reader");
|
||||
fileReader.unregisterListener(this);
|
||||
fileReader.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fileNotFound() {
|
||||
final String msg = String.format("Log file '%s' does not exist", configuration.filePath);
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fileRotated() {
|
||||
logger.debug("Log rotated");
|
||||
updateChannelIfLinked(CHANNEL_LOGROTATED, new DateTimeType(ZonedDateTime.now()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(String line) {
|
||||
if (line == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(thing.getStatus() == ThingStatus.ONLINE)) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
|
||||
if (errorEngine.isMatching(line)) {
|
||||
updateChannelIfLinked(CHANNEL_ERRORS, new DecimalType(errorEngine.getMatchCount()));
|
||||
updateChannelIfLinked(CHANNEL_LASTERROR, new StringType(line));
|
||||
triggerChannel(CHANNEL_NEWERROR, line);
|
||||
}
|
||||
if (warningEngine.isMatching(line)) {
|
||||
updateChannelIfLinked(CHANNEL_WARNINGS, new DecimalType(warningEngine.getMatchCount()));
|
||||
updateChannelIfLinked(CHANNEL_LASTWARNING, new StringType(line));
|
||||
triggerChannel(CHANNEL_NEWWARNING, line);
|
||||
}
|
||||
if (customEngine.isMatching(line)) {
|
||||
updateChannelIfLinked(CHANNEL_CUSTOMEVENTS, new DecimalType(customEngine.getMatchCount()));
|
||||
updateChannelIfLinked(CHANNEL_LASTCUSTOMEVENT, new StringType(line));
|
||||
triggerChannel(CHANNEL_NEWCUSTOM, line);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Exception ex) {
|
||||
final String msg = ex != null ? ex.getMessage() : "";
|
||||
logger.debug("Error while trying to read log file: {}. ", msg, ex);
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.logreader.internal.searchengine;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* This class implements logic for regular expression based searching.
|
||||
*
|
||||
* @author Pauli Anttila - Initial contribution
|
||||
*/
|
||||
public class SearchEngine {
|
||||
|
||||
private List<Pattern> matchers;
|
||||
private List<Pattern> blacklistingMatchers;
|
||||
|
||||
private long matchCount;
|
||||
|
||||
/**
|
||||
* Initialize search patterns.
|
||||
*
|
||||
* @param patterns search patterns.
|
||||
* @param blacklistingPatterns search patterns to bypass results which have found by the initial search patterns.
|
||||
*
|
||||
*/
|
||||
public SearchEngine(String patterns, String blacklistingPatterns) throws PatternSyntaxException {
|
||||
matchers = compilePatterns(patterns);
|
||||
blacklistingMatchers = compilePatterns(blacklistingPatterns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if data is matching to one of the provided search patterns.
|
||||
*
|
||||
* @param data data against search will be done.
|
||||
* @return true if one of the search patterns found.
|
||||
*/
|
||||
public boolean isMatching(String data) {
|
||||
if (isMatching(matchers, data)) {
|
||||
if (notBlacklisted(data)) {
|
||||
matchCount++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public long getMatchCount() {
|
||||
return matchCount;
|
||||
}
|
||||
|
||||
public void setMatchCount(long matchCount) {
|
||||
this.matchCount = matchCount;
|
||||
}
|
||||
|
||||
public void clearMatchCount() {
|
||||
setMatchCount(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Split pattern string and precompile search patterns.
|
||||
*
|
||||
* @param patterns patterns which will handled.
|
||||
* @return list of precompiled patterns. If pattern parameter is null, empty list is returned.
|
||||
*/
|
||||
private List<Pattern> compilePatterns(@Nullable String patterns) throws PatternSyntaxException {
|
||||
List<Pattern> patternsList = new ArrayList<>();
|
||||
|
||||
if (patterns != null && !patterns.isEmpty()) {
|
||||
String list[] = patterns.split("\\|");
|
||||
if (list.length > 0) {
|
||||
for (String patternStr : list) {
|
||||
patternsList.add(Pattern.compile(patternStr));
|
||||
}
|
||||
}
|
||||
}
|
||||
return patternsList;
|
||||
}
|
||||
|
||||
private boolean notBlacklisted(String data) {
|
||||
return !isMatching(blacklistingMatchers, data);
|
||||
}
|
||||
|
||||
private boolean isMatching(@Nullable List<Pattern> patterns, String data) {
|
||||
if (patterns != null) {
|
||||
for (Pattern pattern : patterns) {
|
||||
Matcher matcher = pattern.matcher(data);
|
||||
if (matcher.find()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="logreader" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||
|
||||
<name>LogReader Binding</name>
|
||||
<description>Binding that reads through log files and searches e.g. errors and warnings</description>
|
||||
<author>Pauli Anttila, Miika Jukka</author>
|
||||
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="logreader"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<channel-type id="lastErrorEvent">
|
||||
<item-type>String</item-type>
|
||||
<label>Last Error Event</label>
|
||||
<description>Displays contents of last [ERROR] event</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
<channel-type id="lastWarningEvent">
|
||||
<item-type>String</item-type>
|
||||
<label>Last Warning Event</label>
|
||||
<description>Displays contents of last [WARN] event</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
<channel-type id="lastCustomEvent" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>Last Custom Event</label>
|
||||
<description>Displays contents of last custom event</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
<channel-type id="warningEvents">
|
||||
<item-type>Number</item-type>
|
||||
<label>Warning Events Matched</label>
|
||||
<description>Displays number of [WARN] lines matched to search pattern</description>
|
||||
</channel-type>
|
||||
<channel-type id="errorEvents">
|
||||
<item-type>Number</item-type>
|
||||
<label>Error Events Matched</label>
|
||||
<description>Displays number of [ERROR] lines matched to search pattern</description>
|
||||
</channel-type>
|
||||
<channel-type id="customEvents" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Custom Events Matched</label>
|
||||
<description>Displays number of custom lines matched to search pattern</description>
|
||||
</channel-type>
|
||||
<channel-type id="logRotated" advanced="true">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Log Rotated</label>
|
||||
<description>Last time when log rotated recognized</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="newErrorEvent">
|
||||
<kind>trigger</kind>
|
||||
<label>New Error Event</label>
|
||||
<description>Fires when a new [ERROR] appears in the log</description>
|
||||
<event>
|
||||
</event>
|
||||
</channel-type>
|
||||
<channel-type id="newWarningEvent">
|
||||
<kind>trigger</kind>
|
||||
<label>New Warning Event</label>
|
||||
<description>Fires when a new [WARN] appears in the log</description>
|
||||
<event>
|
||||
</event>
|
||||
</channel-type>
|
||||
<channel-type id="newCustomEvent" advanced="true">
|
||||
<kind>trigger</kind>
|
||||
<label>New Custom Event</label>
|
||||
<description>Fires when a new [CUSTOM] appears in the log</description>
|
||||
<event>
|
||||
</event>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="logreader"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<thing-type id="reader">
|
||||
|
||||
<label>LogReader</label>
|
||||
<description>Log reader to analyze log events</description>
|
||||
|
||||
<channels>
|
||||
<channel typeId="lastWarningEvent" id="lastWarningEvent"/>
|
||||
<channel typeId="lastErrorEvent" id="lastErrorEvent"/>
|
||||
<channel typeId="lastCustomEvent" id="lastCustomEvent"/>
|
||||
<channel typeId="warningEvents" id="warningEvents"/>
|
||||
<channel typeId="errorEvents" id="errorEvents"/>
|
||||
<channel typeId="customEvents" id="customEvents"/>
|
||||
<channel typeId="logRotated" id="logRotated"/>
|
||||
|
||||
<channel typeId="newWarningEvent" id="newWarningEvent"/>
|
||||
<channel typeId="newErrorEvent" id="newErrorEvent"/>
|
||||
<channel typeId="newCustomEvent" id="newCustomEvent"/>
|
||||
</channels>
|
||||
|
||||
<config-description>
|
||||
<parameter name="filePath" type="text" required="true">
|
||||
<label>Log File Path</label>
|
||||
<description>Path to log file. Empty will default to ${OPENHAB_LOGDIR}/openhab.log</description>
|
||||
<default>${OPENHAB_LOGDIR}/openhab.log</default>
|
||||
</parameter>
|
||||
<parameter name="refreshRate" type="integer" required="false">
|
||||
<label>Refresh Rate</label>
|
||||
<description>Refresh rate in milliseconds for reading logs</description>
|
||||
<default>1000</default>
|
||||
</parameter>
|
||||
<parameter name="errorPatterns" type="text" required="false">
|
||||
<label>Error Patterns</label>
|
||||
<description>Search patterns separated by | character for error events. Empty will default to ERROR+</description>
|
||||
<default>ERROR+</default>
|
||||
</parameter>
|
||||
<parameter name="errorBlacklistingPatterns" type="text" required="false">
|
||||
<label>Error Blacklisting Patterns</label>
|
||||
<description>Search patterns for blacklisting unwanted error events separated by | character. </description>
|
||||
</parameter>
|
||||
<parameter name="warningPatterns" type="text" required="false">
|
||||
<label>Warning Patterns</label>
|
||||
<description>Search patterns separated by | character for warning events. Empty will default to WARN+</description>
|
||||
<default>WARN+</default>
|
||||
</parameter>
|
||||
<parameter name="warningBlacklistingPatterns" type="text" required="false">
|
||||
<label>Warning Blacklisting Patterns</label>
|
||||
<description>Search patterns for blacklisting unwanted warning events separated by | character.</description>
|
||||
</parameter>
|
||||
<parameter name="customPatterns" type="text" required="false">
|
||||
<label>Custom Patterns</label>
|
||||
<description>Search patterns separated by | character for custom events.</description>
|
||||
</parameter>
|
||||
<parameter name="customBlacklistingPatterns" type="text" required="false">
|
||||
<label>Custom Blacklisting Patterns</label>
|
||||
<description>Search patterns for blacklisting unwanted custom events separated by | character.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
Reference in New Issue
Block a user