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 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 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 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();
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 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 (String) 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 ( Iterator iter = extension.getProvides().iterator(); iter.hasNext(); )
148 {
149 String attribute = (String)iter.next();
150 extendedAttributes.put( attribute, new Integer( i ) );
151 }
152 }
153 }
154
155 /** @since 1.1 */
156 public Attributes.Extension[] getExtensions()
157 {
158 return extensions;
159 }
160
161 /**
162 * Gets the extension index position which defines corresponding attribute.
163 *
164 * @return the extension index, or -1 if not found
165 * @since 1.1
166 */
167 public int getExtensionIndex( String attribute )
168 {
169 Integer index = (Integer) extendedAttributes.get( attribute );
170 return ( index == null ) ? -1 : index.intValue();
171 }
172
173 /**
174 * Get the attribute that represents the timestamp.
175 *
176 * @return the attribute count, or <code>-1</code> if this logtype does not have a timestamp
177 */
178 public int getTimestampAttribute()
179 {
180 return 1;
181 }
182
183 /**
184 * Get the group definitions specific to this log type that will be added to the generated rules configuration
185 * generated by the GUI.
186 *
187 * @return an XML fragment containing group definitions
188 */
189 public String getDefaultSpecificGroups()
190 {
191 return "";
192 }
193
194 /**
195 * Get the attributes that can be used as a sorting key to get useful event sampling in the last "unknown" group
196 * (separated with a quote when multiple attributes). They will be used as a default sampling rule
197 * configuration.
198 *
199 * @return "attr1[,attr2[,...]]"
200 */
201 public String getDefaultSamplingAttributes()
202 {
203 return "";
204 }
205
206 /**
207 * Find the attribute index corresponding to an attribute name (provided attributes only).
208 *
209 * @param name String the attribute name to search for
210 * @return int the index of the attribute, or -1 if not found
211 * @see #getExtensionIndex(String) to find an extension attribute index
212 */
213 public int getAttributeIndex( String name )
214 {
215 return attributeNames.indexOf( name );
216 }
217
218 public AttributeInfo getAttributeInfo( String name )
219 {
220 int index = getAttributeIndex( name );
221 if ( index > -1 )
222 {
223 return new AttributeInfo( index );
224 }
225 index = getExtensionIndex( name );
226 if ( index < 0 )
227 {
228 throw new IllegalArgumentException( "unknown attribute '" + name + "'. "
229 + "Provided attributes are: " + FormatUtil.join( ", ", getAttributeNames() )
230 + ", extended attributes are: " + FormatUtil.join( ", ", extendedAttributes.keySet() ) + "." );
231 }
232 Extension extension = extensions[index];
233 return new AttributeInfo( index, extension.getProvides().indexOf( name ) );
234 }
235
236 /**
237 * Create a new LogEvent factory for a log stream corresponding to this log description.
238 *
239 * @param reader the stream containing to parse
240 * @param logSource a textual description of the stream's source (useful when LogDistiller works on multiple
241 * simultaneous log sources)
242 */
243 public abstract LogEvent.Factory newFactory( Reader reader, String logSource )
244 throws IOException;
245 }
246
247 public static class AttributeInfo
248 {
249 public final boolean extended;
250
251 public final int index;
252
253 public final int regexpGroup;
254
255 AttributeInfo( int index )
256 {
257 extended = false;
258 this.index = index;
259 regexpGroup = -1;
260 }
261
262 AttributeInfo( int index, int regexpGroup )
263 {
264 extended = true;
265 this.index = index;
266 this.regexpGroup = regexpGroup;
267 }
268 }
269 }