1 package net.sf.logdistiller;
2
3 /*
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 import java.io.IOException;
18 import java.io.Reader;
19 import java.util.*;
20
21 import net.sf.logdistiller.Attributes.Extension;
22 import net.sf.logdistiller.util.FormatUtil;
23
24 /**
25 * Base class for log type implementation. A log type identifies the log format, which can be customized depending on
26 * parameter's values. When defining a new log type, {@link #newDescription newDescription(Map params)} method has to be
27 * implemented to define and handle log type's parameters.
28 *
29 * @see LogType.Basic
30 * @see LogType.Description
31 * @see LogTypes
32 */
33 public abstract class LogType
34 {
35 private final String id;
36
37 protected LogType( String id )
38 {
39 this.id = id;
40 }
41
42 /**
43 * Create a new log description customized with parameters.
44 *
45 * @param params the parameters to customize the log type definition
46 */
47 public abstract Description newDescription( Map<String, String> params );
48
49 public String getId()
50 {
51 return id;
52 }
53
54 /**
55 * Basic logtype definition that does not provide any parameters for customization. It always returns the same
56 * Description instance, which must have been set by calling {@link #setDescription}.
57 */
58 public static class Basic
59 extends LogType
60 {
61 private Description description;
62
63 public Basic( String id )
64 {
65 super( id );
66 }
67
68 public void setDescription( Description description )
69 {
70 this.description = description;
71 }
72
73 public Description newDescription( Map<String, String> params )
74 {
75 if ( description == null )
76 {
77 throw new IllegalStateException( "description must be set before basic logtype use" );
78 }
79 return description;
80 }
81 }
82
83 /**
84 * Description of a log format corresponding to a log type. It must be subclassed for every log type to implement
85 * specialized {@link #newFactory(Reader, String)} method.
86 */
87 public static abstract class Description
88 {
89 private final LogType logtype;
90
91 private final List<String> attributeNames;
92
93 /**
94 * Extensions of the log type attributes. Each extension can define multiple extension attributes.
95 * @since 1.1
96 */
97 private Attributes.Extension[] extensions = Attributes.NO_EXTENSIONS;
98
99 /**
100 * Attributes defined by extensions, with corresponding extension index position.
101 * @since 1.1
102 */
103 private Map<String, Integer> extendedAttributes = new HashMap<String, Integer>();
104
105 /**
106 * Create a new LogType description. By convention, the first attribute should be <code>logSource</code> and the
107 * second should be the timestamp (if this notion is relevant for the log type).
108 *
109 * @param logtype
110 * @param attributeNames
111 * @see #getTimestampAttribute()
112 * @see LogEvent#getTimestamp()
113 */
114 public Description( LogType logtype, String[] attributeNames )
115 {
116 this.logtype = logtype;
117 this.attributeNames = Collections.unmodifiableList( Arrays.asList( attributeNames ) );
118 }
119
120 public LogType getLogType()
121 {
122 return logtype;
123 }
124
125 public List<String> getAttributeNames()
126 {
127 return attributeNames;
128 }
129
130 public int getAttributesCount()
131 {
132 return attributeNames.size();
133 }
134
135 public String getAttributeName( int pos )
136 {
137 return attributeNames.get( pos );
138 }
139
140 /** @since 1.1 */
141 public void setExtensions( Attributes.Extension[] extensions )
142 {
143 this.extensions = extensions;
144 for ( int i = extensions.length - 1; i >= 0; i-- )
145 {
146 Attributes.Extension extension = extensions[i];
147 for ( String attribute : extension.getProvides() )
148 {
149 extendedAttributes.put( attribute, new Integer( i ) );
150 }
151 }
152 }
153
154 /** @since 1.1 */
155 public Attributes.Extension[] getExtensions()
156 {
157 return extensions;
158 }
159
160 /**
161 * Gets the extension index position which defines corresponding attribute.
162 *
163 * @return the extension index, or -1 if not found
164 * @since 1.1
165 */
166 public int getExtensionIndex( String attribute )
167 {
168 Integer index = extendedAttributes.get( attribute );
169 return ( index == null ) ? -1 : index.intValue();
170 }
171
172 /**
173 * Get the attribute that represents the timestamp.
174 *
175 * @return the attribute count, or <code>-1</code> if this logtype does not have a timestamp
176 */
177 public int getTimestampAttribute()
178 {
179 return 1;
180 }
181
182 /**
183 * Get the group definitions specific to this log type that will be added to the generated rules configuration
184 * generated by the GUI.
185 *
186 * @return an XML fragment containing group definitions
187 */
188 public String getDefaultSpecificGroups()
189 {
190 return "";
191 }
192
193 /**
194 * Get the attributes that can be used as a sorting key to get useful event sampling in the last "unknown" group
195 * (separated with a quote when multiple attributes). They will be used as a default sampling rule
196 * configuration.
197 *
198 * @return "attr1[,attr2[,...]]"
199 */
200 public String getDefaultSamplingAttributes()
201 {
202 return "";
203 }
204
205 /**
206 * Find the attribute index corresponding to an attribute name (provided attributes only).
207 *
208 * @param name String the attribute name to search for
209 * @return int the index of the attribute, or -1 if not found
210 * @see #getExtensionIndex(String) to find an extension attribute index
211 */
212 public int getAttributeIndex( String name )
213 {
214 return attributeNames.indexOf( name );
215 }
216
217 public AttributeInfo getAttributeInfo( String name )
218 {
219 int index = getAttributeIndex( name );
220 if ( index > -1 )
221 {
222 return new AttributeInfo( index );
223 }
224 index = getExtensionIndex( name );
225 if ( index < 0 )
226 {
227 throw new IllegalArgumentException( "unknown attribute '" + name + "'. "
228 + "Provided attributes are: " + FormatUtil.join( ", ", getAttributeNames() )
229 + ", extended attributes are: " + FormatUtil.join( ", ", extendedAttributes.keySet() ) + "." );
230 }
231 Extension extension = extensions[index];
232 return new AttributeInfo( index, extension.getProvides().indexOf( name ) );
233 }
234
235 /**
236 * Create a new LogEvent factory for a log stream corresponding to this log description.
237 *
238 * @param reader the stream containing to parse
239 * @param logSource a textual description of the stream's source (useful when LogDistiller works on multiple
240 * simultaneous log sources)
241 */
242 public abstract LogEvent.Factory newFactory( Reader reader, String logSource )
243 throws IOException;
244 }
245
246 public static class AttributeInfo
247 {
248 public final boolean extended;
249
250 public final int index;
251
252 public final int regexpGroup;
253
254 AttributeInfo( int index )
255 {
256 extended = false;
257 this.index = index;
258 regexpGroup = -1;
259 }
260
261 AttributeInfo( int index, int regexpGroup )
262 {
263 extended = true;
264 this.index = index;
265 this.regexpGroup = regexpGroup;
266 }
267 }
268 }