Logging changes and unit tests
[dmaap/datarouter.git] / datarouter-node / src / main / java / org / onap / dmaap / datarouter / node / StatusLog.java
index 109eef2..a9a48ad 100644 (file)
-/*******************************************************************************\r
- * ============LICENSE_START==================================================\r
- * * org.onap.dmaap\r
- * * ===========================================================================\r
- * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
- * * ===========================================================================\r
- * * Licensed under the Apache License, Version 2.0 (the "License");\r
- * * you may not use this file except in compliance with the License.\r
- * * You may obtain a copy of the License at\r
- * * \r
- *  *      http://www.apache.org/licenses/LICENSE-2.0\r
- * * \r
- *  * Unless required by applicable law or agreed to in writing, software\r
- * * distributed under the License is distributed on an "AS IS" BASIS,\r
- * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * * See the License for the specific language governing permissions and\r
- * * limitations under the License.\r
- * * ============LICENSE_END====================================================\r
- * *\r
- * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
- * *\r
- ******************************************************************************/\r
-\r
-package org.onap.dmaap.datarouter.node;\r
-\r
-import java.util.regex.*;\r
-import java.util.*;\r
-import java.io.*;\r
-import java.nio.file.*;\r
-import java.text.*;\r
-\r
-/**\r
- *     Logging for data router delivery events (PUB/DEL/EXP)\r
- */\r
-public class StatusLog {\r
-       private static StatusLog instance = new StatusLog();\r
-       private HashSet<String> toship = new HashSet<String>();\r
-       private SimpleDateFormat        filedate;\r
-       private String  prefix = "logs/events";\r
-       private String  suffix = ".log";\r
-       private String  plainfile;\r
-       private String  curfile;\r
-       private long    nexttime;\r
-       private OutputStream    os;\r
-       private long    intvl;\r
-       private NodeConfigManager       config = NodeConfigManager.getInstance();\r
-       {\r
-               try { filedate = new SimpleDateFormat("-yyyyMMddHHmm"); } catch (Exception e) {}\r
-       }\r
-       /**\r
-        *      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
-        */\r
-       public static long parseInterval(String interval, int def) {\r
-               try {\r
-                       Matcher m = Pattern.compile("(?:(\\d+)[Hh])?(?:(\\d+)[Mm])?(?:(\\d+)[Ss]?)?").matcher(interval);\r
-                       if (m.matches()) {\r
-                               int dur = 0;\r
-                               String x = m.group(1);\r
-                               if (x != null) {\r
-                                       dur += 3600 * Integer.parseInt(x);\r
-                               }\r
-                               x = m.group(2);\r
-                               if (x != null) {\r
-                                       dur += 60 * Integer.parseInt(x);\r
-                               }\r
-                               x = m.group(3);\r
-                               if (x != null) {\r
-                                       dur += Integer.parseInt(x);\r
-                               }\r
-                               if (dur < 60) {\r
-                                       dur = 60;\r
-                               }\r
-                               int best = 86400;\r
-                               int dist = best - dur;\r
-                               if (dur > best) {\r
-                                       dist = dur - best;\r
-                               }\r
-                               int base = 1;\r
-                               for (int i = 0; i < 8; i++) {\r
-                                       int base2 = base;\r
-                                       base *= 2;\r
-                                       for (int j = 0; j < 4; j++) {\r
-                                               int base3 = base2;\r
-                                               base2 *= 3;\r
-                                               for (int k = 0; k < 3; k++) {\r
-                                                       int cur = base3;\r
-                                                       base3 *= 5;\r
-                                                       int ndist = cur - dur;\r
-                                                       if (dur > cur) {\r
-                                                               ndist = dur - cur;\r
-                                                       }\r
-                                                       if (ndist < dist) {\r
-                                                               best = cur;\r
-                                                               dist = ndist;\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                               }\r
-                               def = best * 1000;\r
-                       }\r
-               } catch (Exception e) {\r
-               }\r
-               return(def);\r
-       }\r
-       private synchronized void checkRoll(long now) throws IOException {\r
-               if (now >= nexttime) {\r
-                       if (os != null) {\r
-                               os.close();\r
-                               os = null;\r
-                       }\r
-                       intvl = parseInterval(config.getEventLogInterval(), 300000);\r
-                       prefix = config.getEventLogPrefix();\r
-                       suffix = config.getEventLogSuffix();\r
-                       nexttime = now - now % intvl + intvl;\r
-                       curfile = prefix + filedate.format(new Date(nexttime - intvl)) + suffix;\r
-                       plainfile = prefix + suffix;\r
-                       notify();\r
-               }\r
-       }\r
-       /**\r
-        *      Get the name of the current log file\r
-        *      @return The full path name of the current event log file\r
-        */\r
-       public static synchronized String getCurLogFile() {\r
-               try {\r
-                       instance.checkRoll(System.currentTimeMillis());\r
-               } catch (Exception e) {\r
-               }\r
-               return(instance.curfile);\r
-       }\r
-       private synchronized void log(String s) {\r
-               try {\r
-                       long now = System.currentTimeMillis();\r
-                       checkRoll(now);\r
-                       if (os == null) {\r
-                               os = new FileOutputStream(curfile, true);\r
-                               (new File(plainfile)).delete();\r
-                               Files.createLink(Paths.get(plainfile), Paths.get(curfile));\r
-                       }\r
-                       os.write((NodeUtils.logts(new Date(now)) + '|' + s + '\n').getBytes());\r
-                       os.flush();\r
-               } catch (IOException ioe) {\r
-               }\r
-       }\r
-       /**\r
-        *      Log a received publication attempt.\r
-        *      @param pubid    The publish ID assigned by the node\r
-        *      @param feedid   The feed id given by the publisher\r
-        *      @param requrl   The URL of the received request\r
-        *      @param method   The method (DELETE or PUT) in the received request\r
-        *      @param ctype    The content type (if method is PUT and clen > 0)\r
-        *      @param clen     The content length (if method is PUT)\r
-        *      @param srcip    The IP address of the publisher\r
-        *      @param user     The identity of the publisher\r
-        *      @param status   The status returned to the publisher\r
-        */\r
-       public static void logPub(String pubid, String feedid, String requrl, String method, String ctype, long clen, String srcip, String user, int status) {\r
-               instance.log("PUB|" + pubid + "|" + feedid + "|" + requrl + "|" + method + "|" + ctype + "|" + clen + "|" + srcip + "|" + user + "|" + status);\r
-       }\r
-       /**\r
-        *      Log a data transfer error receiving a publication attempt\r
-        *      @param pubid    The publish ID assigned by the node\r
-        *      @param feedid   The feed id given by the publisher\r
-        *      @param requrl   The URL of the received request\r
-        *      @param method   The method (DELETE or PUT) in the received request\r
-        *      @param ctype    The content type (if method is PUT and clen > 0)\r
-        *      @param clen     The expected content length (if method is PUT)\r
-        *      @param rcvd     The content length received\r
-        *      @param srcip    The IP address of the publisher\r
-        *      @param user     The identity of the publisher\r
-        *      @param error    The error message from the IO exception\r
-        */\r
-       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
-               instance.log("PBF|" + pubid + "|" + feedid + "|" + requrl + "|" + method + "|" + ctype + "|" + clen + "|" + rcvd + "|" + srcip + "|" + user + "|" + error);\r
-       }\r
-       /**\r
-        *      Log a delivery attempt.\r
-        *      @param pubid    The publish ID assigned by the node\r
-        *      @param feedid   The feed ID\r
-        *      @param subid    The (space delimited list of) subscription ID\r
-        *      @param requrl   The URL used in the attempt\r
-        *      @param method   The method (DELETE or PUT) in the attempt\r
-        *      @param ctype    The content type (if method is PUT, not metaonly, and clen > 0)\r
-        *      @param clen     The content length (if PUT and not metaonly)\r
-        *      @param user     The identity given to the subscriber\r
-        *      @param status   The status returned by the subscriber or -1 if an exeception occured trying to connect\r
-        *      @param xpubid   The publish ID returned by the subscriber\r
-        */\r
-       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
-               if (feedid == null) {\r
-                       return;\r
-               }\r
-               instance.log("DEL|" + pubid + "|" + feedid + "|" + subid + "|" + requrl + "|" + method + "|" + ctype + "|" + clen + "|" + user + "|" + status + "|" + xpubid);\r
-       }\r
-       /**\r
-        *      Log delivery attempts expired\r
-        *      @param pubid    The publish ID assigned by the node\r
-        *      @param feedid   The feed ID\r
-        *      @param subid    The (space delimited list of) subscription ID\r
-        *      @param requrl   The URL that would be delivered to\r
-        *      @param method   The method (DELETE or PUT) in the request\r
-        *      @param ctype    The content type (if method is PUT, not metaonly, and clen > 0)\r
-        *      @param clen     The content length (if PUT and not metaonly)\r
-        *      @param reason   The reason the attempts were discontinued\r
-        *      @param attempts The number of attempts made\r
-        */\r
-       public static void logExp(String pubid, String feedid, String subid, String requrl, String method, String ctype, long clen, String reason, int attempts) {\r
-               if (feedid == null) {\r
-                       return;\r
-               }\r
-               instance.log("EXP|" + pubid + "|" + feedid + "|" + subid + "|" + requrl + "|" + method + "|" + ctype + "|" + clen + "|" + reason + "|" + attempts);\r
-       }\r
-       /**\r
-        *      Log extra statistics about unsuccessful delivery attempts.\r
-        *      @param pubid    The publish ID assigned by the node\r
-        *      @param feedid   The feed ID\r
-        *      @param subid    The (space delimited list of) subscription ID\r
-        *      @param clen     The content length\r
-        *      @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
-        */\r
-       public static void logDelExtra(String pubid, String feedid, String subid, long clen, long sent) {\r
-               if (feedid == null) {\r
-                       return;\r
-               }\r
-               instance.log("DLX|" + pubid + "|" + feedid + "|" + subid + "|" + clen + "|" + sent);\r
-       }\r
-       private StatusLog() {\r
-       }\r
-}\r
+/*******************************************************************************
+ * ============LICENSE_START==================================================
+ * * org.onap.dmaap
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * ===========================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ *  *      http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ *  * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+
+package org.onap.dmaap.datarouter.node;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Logging for data router delivery events (PUB/DEL/EXP).
+ */
+public class StatusLog {
+
+    private static final String EXCEPTION = "Exception";
+    private static EELFLogger eelfLogger = EELFManager.getInstance().getLogger(StatusLog.class);
+    private static StatusLog instance = new StatusLog();
+    private SimpleDateFormat filedate = new SimpleDateFormat("-yyyyMMddHHmm");
+
+    private String prefix = "logs/events";
+    private String suffix = ".log";
+    private String plainfile;
+    private String curfile;
+    private long nexttime;
+    private OutputStream os;
+    private long intvl;
+    private static NodeConfigManager config = NodeConfigManager.getInstance();
+
+    private StatusLog() {
+    }
+
+    /**
+     * 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.
+     */
+    public static long parseInterval(String interval, int def) {
+        try {
+            Matcher matcher = Pattern.compile("(?:(\\d+)[Hh])?(?:(\\d+)[Mm])?(?:(\\d+)[Ss]?)?").matcher(interval);
+            if (matcher.matches()) {
+                int dur = getDur(matcher);
+                int best = 86400;
+                int dist = best - dur;
+                if (dur > best) {
+                    dist = dur - best;
+                }
+                best = getBest(dur, best, dist);
+                def = best * 1000;
+            }
+        } catch (Exception e) {
+            eelfLogger.error(EXCEPTION, e);
+        }
+        return (def);
+    }
+
+    private static int getBest(int dur, int best, int dist) {
+        int base = 1;
+        for (int i = 0; i < 8; i++) {
+            int base2 = base;
+            base *= 2;
+            for (int j = 0; j < 4; j++) {
+                int base3 = base2;
+                base2 *= 3;
+                for (int k = 0; k < 3; k++) {
+                    int cur = base3;
+                    base3 *= 5;
+                    int ndist = cur - dur;
+                    if (dur > cur) {
+                        ndist = dur - cur;
+                    }
+                    if (ndist < dist) {
+                        best = cur;
+                        dist = ndist;
+                    }
+                }
+            }
+        }
+        return best;
+    }
+
+    private static int getDur(Matcher matcher) {
+        int dur = 0;
+        String match = matcher.group(1);
+        if (match != null) {
+            dur += 3600 * Integer.parseInt(match);
+        }
+        match = matcher.group(2);
+        if (match != null) {
+            dur += 60 * Integer.parseInt(match);
+        }
+        match = matcher.group(3);
+        if (match != null) {
+            dur += Integer.parseInt(match);
+        }
+        if (dur < 60) {
+            dur = 60;
+        }
+        return dur;
+    }
+
+    /**
+     * Get the name of the current log file.
+     *
+     * @return The full path name of the current event log file
+     */
+    public static synchronized String getCurLogFile() {
+        try {
+            instance.checkRoll(System.currentTimeMillis());
+        } catch (Exception e) {
+            eelfLogger.error(EXCEPTION, e);
+        }
+        return (instance.curfile);
+    }
+
+    /**
+     * Log a received publication attempt.
+     *
+     * @param pubid The publish ID assigned by the node
+     * @param feedid The feed id given by the publisher
+     * @param requrl The URL of the received request
+     * @param method The method (DELETE or PUT) in the received request
+     * @param ctype The content type (if method is PUT and clen > 0)
+     * @param clen The content length (if method is PUT)
+     * @param srcip The IP address of the publisher
+     * @param user The identity of the publisher
+     * @param status The status returned to the publisher
+     */
+    public static void logPub(String pubid, String feedid, String requrl, String method, String ctype, long clen,
+            String srcip, String user, int status) {
+        instance.log(
+                "PUB|" + pubid + "|" + feedid + "|" + requrl + "|" + method + "|" + ctype + "|" + clen + "|" + srcip
+                        + "|" + user + "|" + status);
+        eelfLogger.info("PUB|" + pubid + "|" + feedid + "|" + requrl + "|" + method + "|" + ctype + "|" + clen + "|" + srcip
+                                + "|" + user + "|" + status);
+    }
+
+    /**
+     * Log a data transfer error receiving a publication attempt.
+     *
+     * @param pubid The publish ID assigned by the node
+     * @param feedid The feed id given by the publisher
+     * @param requrl The URL of the received request
+     * @param method The method (DELETE or PUT) in the received request
+     * @param ctype The content type (if method is PUT and clen > 0)
+     * @param clen The expected content length (if method is PUT)
+     * @param rcvd The content length received
+     * @param srcip The IP address of the publisher
+     * @param user The identity of the publisher
+     * @param error The error message from the IO exception
+     */
+    public static void logPubFail(String pubid, String feedid, String requrl, String method, String ctype, long clen,
+            long rcvd, String srcip, String user, String error) {
+        instance.log("PBF|" + pubid + "|" + feedid + "|" + requrl + "|" + method + "|" + ctype + "|" + clen + "|" + rcvd
+                + "|" + srcip + "|" + user + "|" + error);
+        eelfLogger.info("PBF|" + pubid + "|" + feedid + "|" + requrl + "|" + method + "|" + ctype + "|" + clen + "|" + rcvd
+                                + "|" + srcip + "|" + user + "|" + error);
+    }
+
+    /**
+     * Log a delivery attempt.
+     *
+     * @param pubid The publish ID assigned by the node
+     * @param feedid The feed ID
+     * @param subid The (space delimited list of) subscription ID
+     * @param requrl The URL used in the attempt
+     * @param method The method (DELETE or PUT) in the attempt
+     * @param ctype The content type (if method is PUT, not metaonly, and clen > 0)
+     * @param clen The content length (if PUT and not metaonly)
+     * @param user The identity given to the subscriber
+     * @param status The status returned by the subscriber or -1 if an exeception occured trying to connect
+     * @param xpubid The publish ID returned by the subscriber
+     */
+    public static void logDel(String pubid, String feedid, String subid, String requrl, String method, String ctype,
+            long clen, String user, int status, String xpubid) {
+        if (feedid == null) {
+            return;
+        }
+        instance.log(
+                "DEL|" + pubid + "|" + feedid + "|" + subid + "|" + requrl + "|" + method + "|" + ctype + "|" + clen
+                        + "|" + user + "|" + status + "|" + xpubid);
+        eelfLogger.info("DEL|" + pubid + "|" + feedid + "|" + subid + "|" + requrl + "|" + method + "|" + ctype + "|" + clen
+                                + "|" + user + "|" + status + "|" + xpubid);
+    }
+
+    /**
+     * Log delivery attempts expired.
+     *
+     * @param pubid The publish ID assigned by the node
+     * @param feedid The feed ID
+     * @param subid The (space delimited list of) subscription ID
+     * @param requrl The URL that would be delivered to
+     * @param method The method (DELETE or PUT) in the request
+     * @param ctype The content type (if method is PUT, not metaonly, and clen > 0)
+     * @param clen The content length (if PUT and not metaonly)
+     * @param reason The reason the attempts were discontinued
+     * @param attempts The number of attempts made
+     */
+    public static void logExp(String pubid, String feedid, String subid, String requrl, String method, String ctype,
+            long clen, String reason, int attempts) {
+        if (feedid == null) {
+            return;
+        }
+        instance.log(
+                "EXP|" + pubid + "|" + feedid + "|" + subid + "|" + requrl + "|" + method + "|" + ctype + "|" + clen
+                        + "|" + reason + "|" + attempts);
+        eelfLogger.info("EXP|" + pubid + "|" + feedid + "|" + subid + "|" + requrl + "|" + method + "|" + ctype + "|" + clen
+                                + "|" + reason + "|" + attempts);
+    }
+
+    /**
+     * Log extra statistics about unsuccessful delivery attempts.
+     *
+     * @param pubid The publish ID assigned by the node
+     * @param feedid The feed ID
+     * @param subid The (space delimited list of) subscription ID
+     * @param clen The content length
+     * @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.
+     */
+    public static void logDelExtra(String pubid, String feedid, String subid, long clen, long sent) {
+        if (feedid == null) {
+            return;
+        }
+        instance.log("DLX|" + pubid + "|" + feedid + "|" + subid + "|" + clen + "|" + sent);
+        eelfLogger.info("DLX|" + pubid + "|" + feedid + "|" + subid + "|" + clen + "|" + sent);
+    }
+
+    private synchronized void checkRoll(long now) throws IOException {
+        if (now >= nexttime) {
+            if (os != null) {
+                os.close();
+                os = null;
+            }
+            intvl = parseInterval(config.getEventLogInterval(), 300000);
+            prefix = config.getEventLogPrefix();
+            suffix = config.getEventLogSuffix();
+            nexttime = now - now % intvl + intvl;
+            curfile = prefix + filedate.format(new Date(nexttime - intvl)) + suffix;
+            plainfile = prefix + suffix;
+            notify();
+        }
+    }
+
+    private synchronized void log(String string) {
+        try {
+            long now = System.currentTimeMillis();
+            checkRoll(now);
+            if (os == null) {
+                os = new FileOutputStream(curfile, true);
+                (new File(plainfile)).delete();
+                Files.createLink(Paths.get(plainfile), Paths.get(curfile));
+            }
+            os.write((NodeUtils.logts(new Date(now)) + '|' + string + '\n').getBytes());
+            os.flush();
+        } catch (IOException ioe) {
+            eelfLogger.error("IOException", ioe);
+        }
+    }
+}