Removing code smells
[dmaap/datarouter.git] / datarouter-node / src / main / java / org / onap / dmaap / datarouter / node / LogManager.java
1 /*******************************************************************************
2  * ============LICENSE_START==================================================
3  * * org.onap.dmaap
4  * * ===========================================================================
5  * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6  * * ===========================================================================
7  * * Licensed under the Apache License, Version 2.0 (the "License");
8  * * you may not use this file except in compliance with the License.
9  * * You may obtain a copy of the License at
10  * *
11  *  *      http://www.apache.org/licenses/LICENSE-2.0
12  * *
13  *  * Unless required by applicable law or agreed to in writing, software
14  * * distributed under the License is distributed on an "AS IS" BASIS,
15  * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * * See the License for the specific language governing permissions and
17  * * limitations under the License.
18  * * ============LICENSE_END====================================================
19  * *
20  * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
21  * *
22  ******************************************************************************/
23
24 package org.onap.dmaap.datarouter.node;
25
26 import com.att.eelf.configuration.EELFLogger;
27 import com.att.eelf.configuration.EELFManager;
28 import java.io.BufferedReader;
29 import java.io.File;
30 import java.io.FileReader;
31 import java.io.FileWriter;
32 import java.io.IOException;
33 import java.io.Writer;
34 import java.nio.file.Files;
35 import java.nio.file.Paths;
36 import java.util.Arrays;
37 import java.util.TimerTask;
38 import java.util.regex.Matcher;
39 import java.util.regex.Pattern;
40 import org.jetbrains.annotations.NotNull;
41
42 /**
43  * Cleanup of old log files.
44  *
45  * <p>Periodically scan the log directory for log files that are older than the log file retention interval, and delete
46  * them.  In a future release, This class will also be responsible for uploading events logs to the log server to
47  * support the log query APIs.
48  */
49
50 public class LogManager extends TimerTask {
51
52     private static final String EXCEPTION = "Exception";
53     private EELFLogger logger = EELFManager.getInstance().getLogger(LogManager.class);
54     private NodeConfigManager config;
55     private Matcher isnodelog;
56     private Matcher iseventlog;
57     private Uploader worker;
58     private String uploaddir;
59     private String logdir;
60
61     /**
62      * Construct a log manager
63      *
64      * <p>The log manager will check for expired log files every 5 minutes at 20 seconds after the 5 minute boundary.
65      * (Actually, the interval is the event log rollover interval, which defaults to 5 minutes).
66      */
67     public LogManager(NodeConfigManager config) {
68         this.config = config;
69         try {
70             isnodelog = Pattern.compile("node\\.log\\.\\d{8}").matcher("");
71             iseventlog = Pattern.compile("events-\\d{12}\\.log").matcher("");
72         } catch (Exception e) {
73             logger.error(EXCEPTION, e);
74         }
75         logdir = config.getLogDir();
76         uploaddir = logdir + "/.spool";
77         (new File(uploaddir)).mkdirs();
78         long now = System.currentTimeMillis();
79         long intvl = StatusLog.parseInterval(config.getEventLogInterval(), 30000);
80         long when = now - now % intvl + intvl + 20000L;
81         config.getTimer().scheduleAtFixedRate(this, when - now, intvl);
82         worker = new Uploader();
83     }
84
85     /**
86      * Trigger check for expired log files and log files to upload.
87      */
88     public void run() {
89         worker.poke();
90     }
91
92     public Uploader getWorker() {
93         return worker;
94     }
95
96     class Uploader extends Thread implements DeliveryQueueHelper {
97
98         private static final String META = "/.meta";
99         private EELFLogger logger = EELFManager.getInstance().getLogger(Uploader.class);
100         private DeliveryQueue dq;
101
102         Uploader() {
103             dq = new DeliveryQueue(this,
104                     new DestInfoBuilder().setName("LogUpload").setSpool(uploaddir).setSubid(null).setLogdata(null)
105                             .setUrl(null).setAuthuser(config.getMyName()).setAuthentication(config.getMyAuth())
106                             .setMetaonly(false).setUse100(false).setPrivilegedSubscriber(false)
107                             .setFollowRedirects(false)
108                             .setDecompress(false).createDestInfo());
109             setDaemon(true);
110             setName("Log Uploader");
111             start();
112         }
113
114         public long getInitFailureTimer() {
115             return (10000L);
116         }
117
118         public long getWaitForFileProcessFailureTimer() {
119             return (600000L);
120         }
121
122         public double getFailureBackoff() {
123             return (2.0);
124         }
125
126         public long getMaxFailureTimer() {
127             return (150000L);
128         }
129
130         public long getExpirationTimer() {
131             return (604800000L);
132         }
133
134         public int getFairFileLimit() {
135             return (10000);
136         }
137
138         public long getFairTimeLimit() {
139             return (86400000);
140         }
141
142         public String getDestURL(DestInfo destinationInfo, String fileid) {
143             return (config.getEventLogUrl());
144         }
145
146         public void handleUnreachable(DestInfo destinationInfo) {
147             throw new UnsupportedOperationException();
148         }
149
150         public boolean handleRedirection(DestInfo destinationInfo, String location, String fileid) {
151             return (false);
152         }
153
154         public boolean isFollowRedirects() {
155             return (false);
156         }
157
158         public String getFeedId(String subid) {
159             return (null);
160         }
161
162         private synchronized void snooze() {
163             try {
164                 wait(10000);
165             } catch (Exception e) {
166                 logger.error(EXCEPTION, e);
167             }
168         }
169
170         private synchronized void poke() {
171             notifyAll();
172         }
173
174         @Override
175         public void run() {
176             while (true) {
177                 scan();
178                 dq.run();
179                 snooze();
180             }
181         }
182
183         private void scan() {
184             long threshold = System.currentTimeMillis() - config.getLogRetention();
185             File dir = new File(logdir);
186             String[] fns = dir.list();
187             Arrays.sort(fns);
188             String lastqueued = "events-000000000000.log";
189             String curlog = StatusLog.getCurLogFile();
190             curlog = curlog.substring(curlog.lastIndexOf('/') + 1);
191             try {
192                 Writer writer = new FileWriter(uploaddir + META);
193                 writer.write("POST\tlogdata\nContent-Type\ttext/plain\n");
194                 writer.close();
195                 BufferedReader br = new BufferedReader(new FileReader(uploaddir + "/.lastqueued"));
196                 lastqueued = br.readLine();
197                 br.close();
198             } catch (Exception e) {
199                 logger.error(EXCEPTION, e);
200             }
201             for (String fn : fns) {
202                 if (!isnodelog.reset(fn).matches()) {
203                     if (!iseventlog.reset(fn).matches()) {
204                         continue;
205                     }
206                     lastqueued = setLastQueued(lastqueued, curlog, fn);
207                 }
208                 File file = new File(dir, fn);
209                 if (file.lastModified() < threshold) {
210                     try {
211                         Files.deleteIfExists(file.toPath());
212                     } catch (IOException e) {
213                         logger.error("Failed to delete file: " + file.getPath(), e);
214                     }
215                 }
216             }
217             try (Writer w = new FileWriter(uploaddir + "/.lastqueued")) {
218                 Files.deleteIfExists(new File(uploaddir + META).toPath());
219                 w.write(lastqueued + "\n");
220             } catch (Exception e) {
221                 logger.error(EXCEPTION, e);
222             }
223         }
224
225         @NotNull
226         private String setLastQueued(String lastqueued, String curlog, String fn) {
227             if (lastqueued.compareTo(fn) < 0 && curlog.compareTo(fn) > 0) {
228                 lastqueued = fn;
229                 try {
230                     String pid = config.getPublishId();
231                     Files.createLink(Paths.get(uploaddir + "/" + pid), Paths.get(logdir + "/" + fn));
232                     Files.createLink(Paths.get(uploaddir + "/" + pid + ".M"), Paths.get(uploaddir + META));
233                 } catch (Exception e) {
234                     logger.error(EXCEPTION, e);
235                 }
236             }
237             return lastqueued;
238         }
239     }
240 }