]> git.basschouten.com Git - openhab-addons.git/blob
d5f8eef16f28d714bdacb4453bc59d2d3f8dd342
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.logreader.internal.handler;
14
15 import static org.openhab.binding.logreader.internal.LogReaderBindingConstants.*;
16
17 import java.time.ZonedDateTime;
18 import java.util.regex.PatternSyntaxException;
19
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.openhab.binding.logreader.internal.config.LogReaderConfiguration;
23 import org.openhab.binding.logreader.internal.filereader.api.FileReaderListener;
24 import org.openhab.binding.logreader.internal.filereader.api.LogFileReader;
25 import org.openhab.binding.logreader.internal.searchengine.SearchEngine;
26 import org.openhab.core.library.types.DateTimeType;
27 import org.openhab.core.library.types.DecimalType;
28 import org.openhab.core.library.types.StringType;
29 import org.openhab.core.thing.ChannelUID;
30 import org.openhab.core.thing.Thing;
31 import org.openhab.core.thing.ThingStatus;
32 import org.openhab.core.thing.ThingStatusDetail;
33 import org.openhab.core.thing.binding.BaseThingHandler;
34 import org.openhab.core.types.Command;
35 import org.openhab.core.types.RefreshType;
36 import org.openhab.core.types.State;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 /**
41  * The {@link LogHandler} is responsible for handling commands, which are
42  * sent to one of the channels.
43  *
44  * @author Miika Jukka - Initial contribution
45  * @author Pauli Anttila - Rewrite
46  */
47 @NonNullByDefault
48 public class LogHandler extends BaseThingHandler implements FileReaderListener {
49     private final Logger logger = LoggerFactory.getLogger(LogHandler.class);
50
51     private final LogFileReader fileReader;
52
53     private @NonNullByDefault({}) LogReaderConfiguration configuration;
54
55     private @Nullable SearchEngine errorEngine;
56     private @Nullable SearchEngine warningEngine;
57     private @Nullable SearchEngine customEngine;
58
59     public LogHandler(Thing thing, LogFileReader fileReader) {
60         super(thing);
61         this.fileReader = fileReader;
62     }
63
64     @Override
65     public void handleCommand(ChannelUID channelUID, Command command) {
66         switch (channelUID.getId()) {
67             case CHANNEL_ERRORS:
68                 updateChannel(channelUID, command, errorEngine);
69                 break;
70
71             case CHANNEL_WARNINGS:
72                 updateChannel(channelUID, command, warningEngine);
73                 break;
74
75             case CHANNEL_CUSTOMEVENTS:
76                 updateChannel(channelUID, command, customEngine);
77                 break;
78
79             default:
80                 logger.debug("Unsupported command '{}' received for channel '{}'", command, channelUID);
81         }
82     }
83
84     @Override
85     public void initialize() {
86         String logDir = System.getProperty("openhab.logdir");
87         if (logDir == null) {
88             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
89                     "Cannot determine system log directory.");
90             return;
91         }
92
93         configuration = getConfigAs(LogReaderConfiguration.class);
94         configuration.filePath = configuration.filePath.replaceFirst("\\$\\{OPENHAB_LOGDIR\\}", logDir);
95
96         logger.debug("Using configuration: {}", configuration);
97
98         clearCounters();
99
100         try {
101             warningEngine = new SearchEngine(configuration.warningPatterns, configuration.warningBlacklistingPatterns);
102             errorEngine = new SearchEngine(configuration.errorPatterns, configuration.errorBlacklistingPatterns);
103             String customPatterns = configuration.customPatterns;
104             customEngine = new SearchEngine(customPatterns != null ? customPatterns : "",
105                     configuration.customBlacklistingPatterns);
106         } catch (PatternSyntaxException e) {
107             logger.debug("Illegal search pattern syntax '{}'. ", e.getMessage(), e);
108             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, e.getMessage());
109             return;
110         }
111
112         logger.debug("Start file reader");
113
114         try {
115             fileReader.registerListener(this);
116             fileReader.start(configuration.filePath, configuration.refreshRate);
117             updateStatus(ThingStatus.ONLINE);
118         } catch (Exception e) {
119             logger.debug("Exception occurred during initalization: {}. ", e.getMessage(), e);
120             shutdown();
121             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, e.getMessage());
122         }
123     }
124
125     @Override
126     public void dispose() {
127         logger.debug("Stopping thing");
128         shutdown();
129     }
130
131     private void updateChannel(ChannelUID channelUID, Command command, @Nullable SearchEngine matcher) {
132         if (matcher != null) {
133             if (command instanceof DecimalType) {
134                 matcher.setMatchCount(((DecimalType) command).longValue());
135             } else if (command instanceof RefreshType) {
136                 updateState(channelUID.getId(), new DecimalType(matcher.getMatchCount()));
137             } else {
138                 logger.debug("Unsupported command '{}' received for channel '{}'", command, channelUID);
139             }
140         } else {
141             logger.debug("Cannot update channel as SearchEngine is null.");
142         }
143     }
144
145     private void clearCounters() {
146         if (errorEngine != null) {
147             errorEngine.clearMatchCount();
148         }
149         if (warningEngine != null) {
150             warningEngine.clearMatchCount();
151         }
152         if (customEngine != null) {
153             customEngine.clearMatchCount();
154         }
155     }
156
157     private void updateChannelIfLinked(String channelID, State state) {
158         if (isLinked(channelID)) {
159             updateState(channelID, state);
160         }
161     }
162
163     private void shutdown() {
164         logger.debug("Stop file reader");
165         fileReader.unregisterListener(this);
166         fileReader.stop();
167     }
168
169     @Override
170     public void fileNotFound() {
171         final String msg = String.format("Log file '%s' does not exist", configuration.filePath);
172         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, msg);
173     }
174
175     @Override
176     public void fileRotated() {
177         logger.debug("Log rotated");
178         updateChannelIfLinked(CHANNEL_LOGROTATED, new DateTimeType(ZonedDateTime.now()));
179     }
180
181     @Override
182     public void handle(@Nullable String line) {
183         if (line == null) {
184             return;
185         }
186
187         if (!(thing.getStatus() == ThingStatus.ONLINE)) {
188             updateStatus(ThingStatus.ONLINE);
189         }
190
191         if (errorEngine != null && errorEngine.isMatching(line)) {
192             updateChannelIfLinked(CHANNEL_ERRORS, new DecimalType(errorEngine.getMatchCount()));
193             updateChannelIfLinked(CHANNEL_LASTERROR, new StringType(line));
194             triggerChannel(CHANNEL_NEWERROR, line);
195         }
196         if (warningEngine != null && warningEngine.isMatching(line)) {
197             updateChannelIfLinked(CHANNEL_WARNINGS, new DecimalType(warningEngine.getMatchCount()));
198             updateChannelIfLinked(CHANNEL_LASTWARNING, new StringType(line));
199             triggerChannel(CHANNEL_NEWWARNING, line);
200         }
201         if (customEngine != null && customEngine.isMatching(line)) {
202             updateChannelIfLinked(CHANNEL_CUSTOMEVENTS, new DecimalType(customEngine.getMatchCount()));
203             updateChannelIfLinked(CHANNEL_LASTCUSTOMEVENT, new StringType(line));
204             triggerChannel(CHANNEL_NEWCUSTOM, line);
205         }
206     }
207
208     @Override
209     public void handle(@Nullable Exception ex) {
210         final String msg = ex != null ? ex.getMessage() : "";
211         logger.debug("Error while trying to read log file: {}. ", msg, ex);
212         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, msg);
213     }
214 }