001 package net.sf.logdistiller;
002
003 /*
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 import java.io.IOException;
018 import java.io.Reader;
019 import java.util.*;
020
021 import net.sf.logdistiller.Attributes.Extension;
022 import net.sf.logdistiller.util.FormatUtil;
023
024 /**
025 * Base class for log type implementation. A log type identifies the log format, which can be customized depending on
026 * parameter's values. When defining a new log type, {@link #newDescription newDescription(Map params)} method has to be
027 * implemented to define and handle log type's parameters.
028 *
029 * @see LogType.Basic
030 * @see LogType.Description
031 * @see LogTypes
032 */
033 public abstract class LogType
034 {
035 private final String id;
036
037 protected LogType( String id )
038 {
039 this.id = id;
040 }
041
042 /**
043 * Create a new log description customized with parameters.
044 *
045 * @param params the parameters to customize the log type definition
046 */
047 public abstract Description newDescription( Map params );
048
049 public String getId()
050 {
051 return id;
052 }
053
054 /**
055 * Basic logtype definition that does not provide any parameters for customization. It always returns the same
056 * Description instance, which must have been set by calling {@link #setDescription}.
057 */
058 public static class Basic
059 extends LogType
060 {
061 private Description description;
062
063 public Basic( String id )
064 {
065 super( id );
066 }
067
068 public void setDescription( Description description )
069 {
070 this.description = description;
071 }
072
073 public Description newDescription( Map params )
074 {
075 if ( description == null )
076 {
077 throw new IllegalStateException( "description must be set before basic logtype use" );
078 }
079 return description;
080 }
081 }
082
083 /**
084 * Description of a log format corresponding to a log type. It must be subclassed for every log type to implement
085 * specialized {@link #newFactory(Reader, String)} method.
086 */
087 public static abstract class Description
088 {
089 private final LogType logtype;
090
091 private final List attributeNames;
092
093 /**
094 * Extensions of the log type attributes. Each extension can define multiple extension attributes.
095 * @since 1.1
096 */
097 private Attributes.Extension[] extensions = Attributes.NO_EXTENSIONS;
098
099 /**
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 }