aboutsummaryrefslogtreecommitdiffstats
path: root/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/StatusLog.java
blob: 2e646043913aa852a1587779419adff7f8aa5ec3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
/*******************************************************************************
 * ============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;
            notifyAll();
        }
    }

    private synchronized void log(String string) {
        try {
            long now = System.currentTimeMillis();
            checkRoll(now);
            if (os == null) {
                os = new FileOutputStream(curfile, true);
                Files.deleteIfExists(new File(plainfile).toPath());
                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);
        }
    }
}