Remove major and minor code smells in dr-node
[dmaap/datarouter.git] / datarouter-node / src / main / java / org / onap / dmaap / datarouter / node / StatusLog.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.File;
29 import java.io.FileOutputStream;
30 import java.io.IOException;
31 import java.io.OutputStream;
32 import java.nio.file.Files;
33 import java.nio.file.Paths;
34 import java.text.SimpleDateFormat;
35 import java.util.Date;
36 import java.util.regex.Matcher;
37 import java.util.regex.Pattern;
38
39 /**
40  * Logging for data router delivery events (PUB/DEL/EXP)
41  */
42 public class StatusLog {
43
44     private static final String EXCEPTION = "Exception";
45     private static EELFLogger eelfLogger = EELFManager.getInstance().getLogger(StatusLog.class);
46     private static StatusLog instance = new StatusLog();
47     private SimpleDateFormat filedate = new SimpleDateFormat("-yyyyMMddHHmm");
48
49     private String prefix = "logs/events";
50     private String suffix = ".log";
51     private String plainfile;
52     private String curfile;
53     private long nexttime;
54     private OutputStream os;
55     private long intvl;
56     private NodeConfigManager config = NodeConfigManager.getInstance();
57
58     private StatusLog() {
59     }
60
61     /**
62      * Parse an interval of the form xxhyymzzs and round it to the nearest whole fraction of 24 hours.If no units are
63      * specified, assume seconds.
64      */
65     public static long parseInterval(String interval, int def) {
66         try {
67             Matcher m = Pattern.compile("(?:(\\d+)[Hh])?(?:(\\d+)[Mm])?(?:(\\d+)[Ss]?)?").matcher(interval);
68             if (m.matches()) {
69                 int dur = getDur(m);
70                 int best = 86400;
71                 int dist = best - dur;
72                 if (dur > best) {
73                     dist = dur - best;
74                 }
75                 best = getBest(dur, best, dist);
76                 def = best * 1000;
77             }
78         } catch (Exception e) {
79             eelfLogger.error(EXCEPTION, e);
80         }
81         return (def);
82     }
83
84     private static int getBest(int dur, int best, int dist) {
85         int base = 1;
86         for (int i = 0; i < 8; i++) {
87             int base2 = base;
88             base *= 2;
89             for (int j = 0; j < 4; j++) {
90                 int base3 = base2;
91                 base2 *= 3;
92                 for (int k = 0; k < 3; k++) {
93                     int cur = base3;
94                     base3 *= 5;
95                     int ndist = cur - dur;
96                     if (dur > cur) {
97                         ndist = dur - cur;
98                     }
99                     if (ndist < dist) {
100                         best = cur;
101                         dist = ndist;
102                     }
103                 }
104             }
105         }
106         return best;
107     }
108
109     private static int getDur(Matcher m) {
110         int dur = 0;
111         String x = m.group(1);
112         if (x != null) {
113             dur += 3600 * Integer.parseInt(x);
114         }
115         x = m.group(2);
116         if (x != null) {
117             dur += 60 * Integer.parseInt(x);
118         }
119         x = m.group(3);
120         if (x != null) {
121             dur += Integer.parseInt(x);
122         }
123         if (dur < 60) {
124             dur = 60;
125         }
126         return dur;
127     }
128
129     /**
130      * Get the name of the current log file
131      *
132      * @return The full path name of the current event log file
133      */
134     public static synchronized String getCurLogFile() {
135         try {
136             instance.checkRoll(System.currentTimeMillis());
137         } catch (Exception e) {
138             eelfLogger.error(EXCEPTION, e);
139         }
140         return (instance.curfile);
141     }
142
143     /**
144      * Log a received publication attempt.
145      *
146      * @param pubid The publish ID assigned by the node
147      * @param feedid The feed id given by the publisher
148      * @param requrl The URL of the received request
149      * @param method The method (DELETE or PUT) in the received request
150      * @param ctype The content type (if method is PUT and clen > 0)
151      * @param clen The content length (if method is PUT)
152      * @param srcip The IP address of the publisher
153      * @param user The identity of the publisher
154      * @param status The status returned to the publisher
155      */
156     public static void logPub(String pubid, String feedid, String requrl, String method, String ctype, long clen,
157             String srcip, String user, int status) {
158         instance.log(
159                 "PUB|" + pubid + "|" + feedid + "|" + requrl + "|" + method + "|" + ctype + "|" + clen + "|" + srcip
160                         + "|" + user + "|" + status);
161     }
162
163     /**
164      * Log a data transfer error receiving a publication attempt
165      *
166      * @param pubid The publish ID assigned by the node
167      * @param feedid The feed id given by the publisher
168      * @param requrl The URL of the received request
169      * @param method The method (DELETE or PUT) in the received request
170      * @param ctype The content type (if method is PUT and clen > 0)
171      * @param clen The expected content length (if method is PUT)
172      * @param rcvd The content length received
173      * @param srcip The IP address of the publisher
174      * @param user The identity of the publisher
175      * @param error The error message from the IO exception
176      */
177     public static void logPubFail(String pubid, String feedid, String requrl, String method, String ctype, long clen,
178             long rcvd, String srcip, String user, String error) {
179         instance.log("PBF|" + pubid + "|" + feedid + "|" + requrl + "|" + method + "|" + ctype + "|" + clen + "|" + rcvd
180                 + "|" + srcip + "|" + user + "|" + error);
181     }
182
183     /**
184      * Log a delivery attempt.
185      *
186      * @param pubid The publish ID assigned by the node
187      * @param feedid The feed ID
188      * @param subid The (space delimited list of) subscription ID
189      * @param requrl The URL used in the attempt
190      * @param method The method (DELETE or PUT) in the attempt
191      * @param ctype The content type (if method is PUT, not metaonly, and clen > 0)
192      * @param clen The content length (if PUT and not metaonly)
193      * @param user The identity given to the subscriber
194      * @param status The status returned by the subscriber or -1 if an exeception occured trying to connect
195      * @param xpubid The publish ID returned by the subscriber
196      */
197     public static void logDel(String pubid, String feedid, String subid, String requrl, String method, String ctype,
198             long clen, String user, int status, String xpubid) {
199         if (feedid == null) {
200             return;
201         }
202         instance.log(
203                 "DEL|" + pubid + "|" + feedid + "|" + subid + "|" + requrl + "|" + method + "|" + ctype + "|" + clen
204                         + "|" + user + "|" + status + "|" + xpubid);
205     }
206
207     /**
208      * Log delivery attempts expired
209      *
210      * @param pubid The publish ID assigned by the node
211      * @param feedid The feed ID
212      * @param subid The (space delimited list of) subscription ID
213      * @param requrl The URL that would be delivered to
214      * @param method The method (DELETE or PUT) in the request
215      * @param ctype The content type (if method is PUT, not metaonly, and clen > 0)
216      * @param clen The content length (if PUT and not metaonly)
217      * @param reason The reason the attempts were discontinued
218      * @param attempts The number of attempts made
219      */
220     public static void logExp(String pubid, String feedid, String subid, String requrl, String method, String ctype,
221             long clen, String reason, int attempts) {
222         if (feedid == null) {
223             return;
224         }
225         instance.log(
226                 "EXP|" + pubid + "|" + feedid + "|" + subid + "|" + requrl + "|" + method + "|" + ctype + "|" + clen
227                         + "|" + reason + "|" + attempts);
228     }
229
230     /**
231      * Log extra statistics about unsuccessful delivery attempts.
232      *
233      * @param pubid The publish ID assigned by the node
234      * @param feedid The feed ID
235      * @param subid The (space delimited list of) subscription ID
236      * @param clen The content length
237      * @param sent The # of bytes sent or -1 if subscriber returned an error instead of 100 Continue, otherwise, the
238      * number of bytes sent before an error occurred.
239      */
240     public static void logDelExtra(String pubid, String feedid, String subid, long clen, long sent) {
241         if (feedid == null) {
242             return;
243         }
244         instance.log("DLX|" + pubid + "|" + feedid + "|" + subid + "|" + clen + "|" + sent);
245     }
246
247     private synchronized void checkRoll(long now) throws IOException {
248         if (now >= nexttime) {
249             if (os != null) {
250                 os.close();
251                 os = null;
252             }
253             intvl = parseInterval(config.getEventLogInterval(), 300000);
254             prefix = config.getEventLogPrefix();
255             suffix = config.getEventLogSuffix();
256             nexttime = now - now % intvl + intvl;
257             curfile = prefix + filedate.format(new Date(nexttime - intvl)) + suffix;
258             plainfile = prefix + suffix;
259             notify();
260         }
261     }
262
263     private synchronized void log(String s) {
264         try {
265             long now = System.currentTimeMillis();
266             checkRoll(now);
267             if (os == null) {
268                 os = new FileOutputStream(curfile, true);
269                 (new File(plainfile)).delete();
270                 Files.createLink(Paths.get(plainfile), Paths.get(curfile));
271             }
272             os.write((NodeUtils.logts(new Date(now)) + '|' + s + '\n').getBytes());
273             os.flush();
274         } catch (IOException ioe) {
275             eelfLogger.error("IOException", ioe);
276         }
277     }
278 }