[DMAAP-48] Initial code import
[dmaap/datarouter.git] / datarouter-node / src / main / java / com / att / research / datarouter / node / StatusLog.java
1 /*******************************************************************************\r
2  * ============LICENSE_START==================================================\r
3  * * org.onap.dmaap\r
4  * * ===========================================================================\r
5  * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
6  * * ===========================================================================\r
7  * * Licensed under the Apache License, Version 2.0 (the "License");\r
8  * * you may not use this file except in compliance with the License.\r
9  * * You may obtain a copy of the License at\r
10  * * \r
11  *  *      http://www.apache.org/licenses/LICENSE-2.0\r
12  * * \r
13  *  * Unless required by applicable law or agreed to in writing, software\r
14  * * distributed under the License is distributed on an "AS IS" BASIS,\r
15  * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
16  * * See the License for the specific language governing permissions and\r
17  * * limitations under the License.\r
18  * * ============LICENSE_END====================================================\r
19  * *\r
20  * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
21  * *\r
22  ******************************************************************************/\r
23 \r
24 package com.att.research.datarouter.node;\r
25 \r
26 import java.util.regex.*;\r
27 import java.util.*;\r
28 import java.io.*;\r
29 import java.nio.file.*;\r
30 import java.text.*;\r
31 \r
32 /**\r
33  *      Logging for data router delivery events (PUB/DEL/EXP)\r
34  */\r
35 public class StatusLog  {\r
36         private static StatusLog instance = new StatusLog();\r
37         private HashSet<String> toship = new HashSet<String>();\r
38         private SimpleDateFormat        filedate;\r
39         private String  prefix = "logs/events";\r
40         private String  suffix = ".log";\r
41         private String  plainfile;\r
42         private String  curfile;\r
43         private long    nexttime;\r
44         private OutputStream    os;\r
45         private long    intvl;\r
46         private NodeConfigManager       config = NodeConfigManager.getInstance();\r
47         {\r
48                 try { filedate = new SimpleDateFormat("-yyyyMMddHHmm"); } catch (Exception e) {}\r
49         }\r
50         /**\r
51          *      Parse an interval of the form xxhyymzzs and round it to the nearest whole fraction of 24 hours.  If no units are specified, assume seconds.\r
52          */\r
53         public static long parseInterval(String interval, int def) {\r
54                 try {\r
55                         Matcher m = Pattern.compile("(?:(\\d+)[Hh])?(?:(\\d+)[Mm])?(?:(\\d+)[Ss]?)?").matcher(interval);\r
56                         if (m.matches()) {\r
57                                 int dur = 0;\r
58                                 String x = m.group(1);\r
59                                 if (x != null) {\r
60                                         dur += 3600 * Integer.parseInt(x);\r
61                                 }\r
62                                 x = m.group(2);\r
63                                 if (x != null) {\r
64                                         dur += 60 * Integer.parseInt(x);\r
65                                 }\r
66                                 x = m.group(3);\r
67                                 if (x != null) {\r
68                                         dur += Integer.parseInt(x);\r
69                                 }\r
70                                 if (dur < 60) {\r
71                                         dur = 60;\r
72                                 }\r
73                                 int best = 86400;\r
74                                 int dist = best - dur;\r
75                                 if (dur > best) {\r
76                                         dist = dur - best;\r
77                                 }\r
78                                 int base = 1;\r
79                                 for (int i = 0; i < 8; i++) {\r
80                                         int base2 = base;\r
81                                         base *= 2;\r
82                                         for (int j = 0; j < 4; j++) {\r
83                                                 int base3 = base2;\r
84                                                 base2 *= 3;\r
85                                                 for (int k = 0; k < 3; k++) {\r
86                                                         int cur = base3;\r
87                                                         base3 *= 5;\r
88                                                         int ndist = cur - dur;\r
89                                                         if (dur > cur) {\r
90                                                                 ndist = dur - cur;\r
91                                                         }\r
92                                                         if (ndist < dist) {\r
93                                                                 best = cur;\r
94                                                                 dist = ndist;\r
95                                                         }\r
96                                                 }\r
97                                         }\r
98                                 }\r
99                                 def = best * 1000;\r
100                         }\r
101                 } catch (Exception e) {\r
102                 }\r
103                 return(def);\r
104         }\r
105         private synchronized void checkRoll(long now) throws IOException {\r
106                 if (now >= nexttime) {\r
107                         if (os != null) {\r
108                                 os.close();\r
109                                 os = null;\r
110                         }\r
111                         intvl = parseInterval(config.getEventLogInterval(), 300000);\r
112                         prefix = config.getEventLogPrefix();\r
113                         suffix = config.getEventLogSuffix();\r
114                         nexttime = now - now % intvl + intvl;\r
115                         curfile = prefix + filedate.format(new Date(nexttime - intvl)) + suffix;\r
116                         plainfile = prefix + suffix;\r
117                         notify();\r
118                 }\r
119         }\r
120         /**\r
121          *      Get the name of the current log file\r
122          *      @return The full path name of the current event log file\r
123          */\r
124         public static synchronized String getCurLogFile() {\r
125                 try {\r
126                         instance.checkRoll(System.currentTimeMillis());\r
127                 } catch (Exception e) {\r
128                 }\r
129                 return(instance.curfile);\r
130         }\r
131         private synchronized void log(String s) {\r
132                 try {\r
133                         long now = System.currentTimeMillis();\r
134                         checkRoll(now);\r
135                         if (os == null) {\r
136                                 os = new FileOutputStream(curfile, true);\r
137                                 (new File(plainfile)).delete();\r
138                                 Files.createLink(Paths.get(plainfile), Paths.get(curfile));\r
139                         }\r
140                         os.write((NodeUtils.logts(new Date(now)) + '|' + s + '\n').getBytes());\r
141                         os.flush();\r
142                 } catch (IOException ioe) {\r
143                 }\r
144         }\r
145         /**\r
146          *      Log a received publication attempt.\r
147          *      @param pubid    The publish ID assigned by the node\r
148          *      @param feedid   The feed id given by the publisher\r
149          *      @param requrl   The URL of the received request\r
150          *      @param method   The method (DELETE or PUT) in the received request\r
151          *      @param ctype    The content type (if method is PUT and clen > 0)\r
152          *      @param clen     The content length (if method is PUT)\r
153          *      @param srcip    The IP address of the publisher\r
154          *      @param user     The identity of the publisher\r
155          *      @param status   The status returned to the publisher\r
156          */\r
157         public static void logPub(String pubid, String feedid, String requrl, String method, String ctype, long clen, String srcip, String user, int status) {\r
158                 instance.log("PUB|" + pubid + "|" + feedid + "|" + requrl + "|" + method + "|" + ctype + "|" + clen + "|" + srcip + "|" + user + "|" + status);\r
159         }\r
160         /**\r
161          *      Log a data transfer error receiving a publication attempt\r
162          *      @param pubid    The publish ID assigned by the node\r
163          *      @param feedid   The feed id given by the publisher\r
164          *      @param requrl   The URL of the received request\r
165          *      @param method   The method (DELETE or PUT) in the received request\r
166          *      @param ctype    The content type (if method is PUT and clen > 0)\r
167          *      @param clen     The expected content length (if method is PUT)\r
168          *      @param rcvd     The content length received\r
169          *      @param srcip    The IP address of the publisher\r
170          *      @param user     The identity of the publisher\r
171          *      @param error    The error message from the IO exception\r
172          */\r
173         public static void logPubFail(String pubid, String feedid, String requrl, String method, String ctype, long clen, long rcvd, String srcip, String user, String error) {\r
174                 instance.log("PBF|" + pubid + "|" + feedid + "|" + requrl + "|" + method + "|" + ctype + "|" + clen + "|" + rcvd + "|" + srcip + "|" + user + "|" + error);\r
175         }\r
176         /**\r
177          *      Log a delivery attempt.\r
178          *      @param pubid    The publish ID assigned by the node\r
179          *      @param feedid   The feed ID\r
180          *      @param subid    The (space delimited list of) subscription ID\r
181          *      @param requrl   The URL used in the attempt\r
182          *      @param method   The method (DELETE or PUT) in the attempt\r
183          *      @param ctype    The content type (if method is PUT, not metaonly, and clen > 0)\r
184          *      @param clen     The content length (if PUT and not metaonly)\r
185          *      @param user     The identity given to the subscriber\r
186          *      @param status   The status returned by the subscriber or -1 if an exeception occured trying to connect\r
187          *      @param xpubid   The publish ID returned by the subscriber\r
188          */\r
189         public static void logDel(String pubid, String feedid, String subid, String requrl, String method, String ctype, long clen, String user, int status, String xpubid) {\r
190                 if (feedid == null) {\r
191                         return;\r
192                 }\r
193                 instance.log("DEL|" + pubid + "|" + feedid + "|" + subid + "|" + requrl + "|" + method + "|" + ctype + "|" + clen + "|" + user + "|" + status + "|" + xpubid);\r
194         }\r
195         /**\r
196          *      Log delivery attempts expired\r
197          *      @param pubid    The publish ID assigned by the node\r
198          *      @param feedid   The feed ID\r
199          *      @param subid    The (space delimited list of) subscription ID\r
200          *      @param requrl   The URL that would be delivered to\r
201          *      @param method   The method (DELETE or PUT) in the request\r
202          *      @param ctype    The content type (if method is PUT, not metaonly, and clen > 0)\r
203          *      @param clen     The content length (if PUT and not metaonly)\r
204          *      @param reason   The reason the attempts were discontinued\r
205          *      @param attempts The number of attempts made\r
206          */\r
207         public static void logExp(String pubid, String feedid, String subid, String requrl, String method, String ctype, long clen, String reason, int attempts) {\r
208                 if (feedid == null) {\r
209                         return;\r
210                 }\r
211                 instance.log("EXP|" + pubid + "|" + feedid + "|" + subid + "|" + requrl + "|" + method + "|" + ctype + "|" + clen + "|" + reason + "|" + attempts);\r
212         }\r
213         /**\r
214          *      Log extra statistics about unsuccessful delivery attempts.\r
215          *      @param pubid    The publish ID assigned by the node\r
216          *      @param feedid   The feed ID\r
217          *      @param subid    The (space delimited list of) subscription ID\r
218          *      @param clen     The content length\r
219          *      @param sent     The # of bytes sent or -1 if subscriber returned an error instead of 100 Continue, otherwise, the number of bytes sent before an error occurred.\r
220          */\r
221         public static void logDelExtra(String pubid, String feedid, String subid, long clen, long sent) {\r
222                 if (feedid == null) {\r
223                         return;\r
224                 }\r
225                 instance.log("DLX|" + pubid + "|" + feedid + "|" + subid + "|" + clen + "|" + sent);\r
226         }\r
227         private StatusLog() {\r
228         }\r
229 }\r