summaryrefslogtreecommitdiffstats
path: root/vespalog/src/main/java/com/yahoo/log/LogMessage.java
blob: 608290026b6eae1c522ade5f8ab18f95991cf0cb (plain) (blame)
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
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.log;

import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.yahoo.log.event.Event;
import com.yahoo.log.event.MalformedEventException;

/**
 * This class implements the common ground log message used by
 * the logserver.  A LogMessage is immutable.  Note that we have
 * chosen the name LogMessage to avoid confusion with LogRecord
 * which is used in java.util.logging.
 *
 * @author  <a href="mailto:borud@yahoo-inc.com">Bjorn Borud</a>
 */
public class LogMessage
{
    private static Logger log = Logger.getLogger(LogMessage.class.getName());

    private static Pattern nativeFormat =
        Pattern.compile("^(\\d[^\t]+)\t" + // time
                        "([^\t]+)\t"  + // host
                        "([^\t]+)\t"  + // threadProcess
                        "([^\t]+)\t"  + // service
                        "([^\t]+)\t"  + // component
                        "([^\t]+)\t"  + // level
                        "(.+)$"         // payload
                        );

    private long     time;
    private String   timeStr;
    private String   host;
    private String   threadProcess;
    private String   service;
    private String   component;
    private Level    level;
    private String   payload;
    private Event    event;

    /**
     * Private constructor.  Log messages should never be instantiated
     * directly; only as the result of a static factory method.
     */
    private LogMessage (String timeStr, Long time, String host, String threadProcess,
                        String service, String component, Level level,
                        String payload)
    {
        this.timeStr = timeStr;
        this.time = time;
        this.host = host;
        this.threadProcess = threadProcess;
        this.service = service;
        this.component = component;
        this.level = level;
        this.payload = payload;
    }

    public long     getTime ()          {return time;}
    public long     getTimeInSeconds () {return time / 1000;}
    public String   getHost ()          {return host;}
    public String   getThreadProcess () {return threadProcess;}
    public String   getService ()       {return service;}
    public String   getComponent ()     {return component;}
    public Level    getLevel ()         {return level;}
    public String   getPayload ()       {return payload;}

    /**
     * Make a log message from the native format of the logging
     * package.
     *
     * @param msg The log message
     * @return Returns a LogMessage instance
     * @throws InvalidLogFormatException if the log message
     *    can not be parsed, ie. is invalid, we throw this
     *    exception.
     */
    public static LogMessage parseNativeFormat(String msg) throws InvalidLogFormatException {
        Matcher m = nativeFormat.matcher(msg);
        if (! m.matches()) {
            throw new InvalidLogFormatException(msg);
        }

        Level msgLevel = LogLevel.parse(m.group(6));
        Long timestamp = parseTimestamp(m.group(1));

        return new LogMessage(m.group(1), timestamp, m.group(2), m.group(3),
                              m.group(4), m.group(5), msgLevel,
                              m.group(7));
    }

    private static long parseTimestamp(String timeStr) throws InvalidLogFormatException {
        try {
            return (long) (Double.parseDouble(timeStr) * 1000);
        } catch (NumberFormatException e) {
            throw new InvalidLogFormatException("Invalid time string:" + timeStr);
        }
    }

    /**
     * If the LogMessage was an EVENT then this method can
     * be used to get the Event instance representing the
     * event.  The event instance created the first time
     * this method is called and then cached.
     *
     * TODO: make sure this throws exception!
     *
     * @return Returns Event instance if this is an event message
     *         and the payload is correctly formatted.  Otherwise
     *         it will return <code>null</code>.
     *
     */
    public Event getEvent () throws MalformedEventException {
        if ((level == LogLevel.EVENT) && (event == null)) {
            try {
                event = Event.parse(getPayload());
                event.setTime(time);
            }
            catch (MalformedEventException e) {
                log.log(LogLevel.DEBUG, "Got malformed event: " + getPayload());
                throw e;
            }
        }
        return event;
    }

    /**
     * Return valid representation of log message.
     */
    public String toString () {
        return new StringBuilder(timeStr.length()
                                + host.length()
                                + threadProcess.length()
                                + service.length()
                                + component.length()
                                + level.toString().length()
                                + payload.length()
                                + 1)
            .append(timeStr).append("\t")
            .append(host).append("\t")
            .append(threadProcess).append("\t")
            .append(service).append("\t")
            .append(component).append("\t")
            .append(level.toString().toLowerCase()).append("\t")
            .append(payload).append("\n")
            .toString();
    }
}