27
27
import org .elasticsearch .ingest .useragent .UserAgentParser .Details ;
28
28
import org .elasticsearch .ingest .useragent .UserAgentParser .VersionedName ;
29
29
30
+ import java .lang .reflect .Field ;
30
31
import java .util .Arrays ;
31
32
import java .util .EnumSet ;
32
33
import java .util .HashMap ;
34
+ import java .util .HashSet ;
33
35
import java .util .List ;
34
36
import java .util .Locale ;
35
37
import java .util .Map ;
@@ -51,15 +53,17 @@ public class UserAgentProcessor extends AbstractProcessor {
51
53
private final Set <Property > properties ;
52
54
private final UserAgentParser parser ;
53
55
private final boolean ignoreMissing ;
56
+ private final boolean useECS ;
54
57
55
58
public UserAgentProcessor (String tag , String field , String targetField , UserAgentParser parser , Set <Property > properties ,
56
- boolean ignoreMissing ) {
59
+ boolean ignoreMissing , boolean useECS ) {
57
60
super (tag );
58
61
this .field = field ;
59
62
this .targetField = targetField ;
60
63
this .parser = parser ;
61
64
this .properties = properties ;
62
65
this .ignoreMissing = ignoreMissing ;
66
+ this .useECS = useECS ;
63
67
}
64
68
65
69
boolean isIgnoreMissing () {
@@ -80,68 +84,135 @@ public IngestDocument execute(IngestDocument ingestDocument) {
80
84
81
85
Map <String , Object > uaDetails = new HashMap <>();
82
86
83
- // Parse the user agent in the ECS (Elastic Common Schema) format
84
- for (Property property : this .properties ) {
85
- switch (property ) {
86
- case ORIGINAL :
87
- uaDetails .put ("original" , userAgent );
88
- break ;
89
- case NAME :
90
- if (uaClient .userAgent != null && uaClient .userAgent .name != null ) {
91
- uaDetails .put ("name" , uaClient .userAgent .name );
92
- } else {
93
- uaDetails .put ("name" , "Other" );
94
- }
95
- break ;
96
- case VERSION :
97
- StringBuilder version = new StringBuilder ();
98
- if (uaClient .userAgent != null && uaClient .userAgent .major != null ) {
99
- version .append (uaClient .userAgent .major );
100
- if (uaClient .userAgent .minor != null ) {
101
- version .append ("." ).append (uaClient .userAgent .minor );
102
- if (uaClient .userAgent .patch != null ) {
103
- version .append ("." ).append (uaClient .userAgent .patch );
104
- if (uaClient .userAgent .build != null ) {
105
- version .append ("." ).append (uaClient .userAgent .build );
87
+ if (useECS ) {
88
+ // Parse the user agent in the ECS (Elastic Common Schema) format
89
+ for (Property property : this .properties ) {
90
+ switch (property ) {
91
+ case ORIGINAL :
92
+ uaDetails .put ("original" , userAgent );
93
+ break ;
94
+ case NAME :
95
+ if (uaClient .userAgent != null && uaClient .userAgent .name != null ) {
96
+ uaDetails .put ("name" , uaClient .userAgent .name );
97
+ } else {
98
+ uaDetails .put ("name" , "Other" );
99
+ }
100
+ break ;
101
+ case VERSION :
102
+ StringBuilder version = new StringBuilder ();
103
+ if (uaClient .userAgent != null && uaClient .userAgent .major != null ) {
104
+ version .append (uaClient .userAgent .major );
105
+ if (uaClient .userAgent .minor != null ) {
106
+ version .append ("." ).append (uaClient .userAgent .minor );
107
+ if (uaClient .userAgent .patch != null ) {
108
+ version .append ("." ).append (uaClient .userAgent .patch );
109
+ if (uaClient .userAgent .build != null ) {
110
+ version .append ("." ).append (uaClient .userAgent .build );
111
+ }
106
112
}
107
113
}
114
+ uaDetails .put ("version" , version .toString ());
108
115
}
109
- uaDetails .put ("version" , version .toString ());
110
- }
111
- break ;
112
- case OS :
113
- if (uaClient .operatingSystem != null ) {
114
- Map <String , String > osDetails = new HashMap <>(3 );
115
- if (uaClient .operatingSystem .name != null ) {
116
- osDetails .put ("name" , uaClient .operatingSystem .name );
117
- StringBuilder sb = new StringBuilder ();
118
- if (uaClient .operatingSystem .major != null ) {
119
- sb .append (uaClient .operatingSystem .major );
120
- if (uaClient .operatingSystem .minor != null ) {
121
- sb .append ("." ).append (uaClient .operatingSystem .minor );
122
- if (uaClient .operatingSystem .patch != null ) {
123
- sb .append ("." ).append (uaClient .operatingSystem .patch );
124
- if (uaClient .operatingSystem .build != null ) {
125
- sb .append ("." ).append (uaClient .operatingSystem .build );
116
+ break ;
117
+ case OS :
118
+ if (uaClient .operatingSystem != null ) {
119
+ Map <String , String > osDetails = new HashMap <>(3 );
120
+ if (uaClient .operatingSystem .name != null ) {
121
+ osDetails .put ("name" , uaClient .operatingSystem .name );
122
+ StringBuilder sb = new StringBuilder ();
123
+ if (uaClient .operatingSystem .major != null ) {
124
+ sb .append (uaClient .operatingSystem .major );
125
+ if (uaClient .operatingSystem .minor != null ) {
126
+ sb .append ("." ).append (uaClient .operatingSystem .minor );
127
+ if (uaClient .operatingSystem .patch != null ) {
128
+ sb .append ("." ).append (uaClient .operatingSystem .patch );
129
+ if (uaClient .operatingSystem .build != null ) {
130
+ sb .append ("." ).append (uaClient .operatingSystem .build );
131
+ }
126
132
}
127
133
}
134
+ osDetails .put ("version" , sb .toString ());
135
+ osDetails .put ("full" , uaClient .operatingSystem .name + " " + sb .toString ());
128
136
}
129
- osDetails .put ("version" , sb .toString ());
130
- osDetails .put ("full" , uaClient .operatingSystem .name + " " + sb .toString ());
137
+ uaDetails .put ("os" , osDetails );
131
138
}
132
- uaDetails .put ("os" , osDetails );
133
139
}
134
- }
135
- break ;
136
- case DEVICE :
137
- Map <String , String > deviceDetails = new HashMap <>(1 );
138
- if (uaClient .device != null && uaClient .device .name != null ) {
139
- deviceDetails .put ("name" , uaClient .device .name );
140
- } else {
141
- deviceDetails .put ("name" , "Other" );
142
- }
143
- uaDetails .put ("device" , deviceDetails );
144
- break ;
140
+ break ;
141
+ case DEVICE :
142
+ Map <String , String > deviceDetails = new HashMap <>(1 );
143
+ if (uaClient .device != null && uaClient .device .name != null ) {
144
+ deviceDetails .put ("name" , uaClient .device .name );
145
+ } else {
146
+ deviceDetails .put ("name" , "Other" );
147
+ }
148
+ uaDetails .put ("device" , deviceDetails );
149
+ break ;
150
+ }
151
+ }
152
+ } else {
153
+ // Deprecated format, removed in 8.0
154
+ for (Property property : this .properties ) {
155
+ switch (property ) {
156
+ case NAME :
157
+ if (uaClient .userAgent != null && uaClient .userAgent .name != null ) {
158
+ uaDetails .put ("name" , uaClient .userAgent .name );
159
+ } else {
160
+ uaDetails .put ("name" , "Other" );
161
+ }
162
+ break ;
163
+ case MAJOR :
164
+ if (uaClient .userAgent != null && uaClient .userAgent .major != null ) {
165
+ uaDetails .put ("major" , uaClient .userAgent .major );
166
+ }
167
+ break ;
168
+ case MINOR :
169
+ if (uaClient .userAgent != null && uaClient .userAgent .minor != null ) {
170
+ uaDetails .put ("minor" , uaClient .userAgent .minor );
171
+ }
172
+ break ;
173
+ case PATCH :
174
+ if (uaClient .userAgent != null && uaClient .userAgent .patch != null ) {
175
+ uaDetails .put ("patch" , uaClient .userAgent .patch );
176
+ }
177
+ break ;
178
+ case BUILD :
179
+ if (uaClient .userAgent != null && uaClient .userAgent .build != null ) {
180
+ uaDetails .put ("build" , uaClient .userAgent .build );
181
+ }
182
+ break ;
183
+ case OS :
184
+ if (uaClient .operatingSystem != null ) {
185
+ uaDetails .put ("os" , buildFullOSName (uaClient .operatingSystem ));
186
+ } else {
187
+ uaDetails .put ("os" , "Other" );
188
+ }
189
+
190
+ break ;
191
+ case OS_NAME :
192
+ if (uaClient .operatingSystem != null && uaClient .operatingSystem .name != null ) {
193
+ uaDetails .put ("os_name" , uaClient .operatingSystem .name );
194
+ } else {
195
+ uaDetails .put ("os_name" , "Other" );
196
+ }
197
+ break ;
198
+ case OS_MAJOR :
199
+ if (uaClient .operatingSystem != null && uaClient .operatingSystem .major != null ) {
200
+ uaDetails .put ("os_major" , uaClient .operatingSystem .major );
201
+ }
202
+ break ;
203
+ case OS_MINOR :
204
+ if (uaClient .operatingSystem != null && uaClient .operatingSystem .minor != null ) {
205
+ uaDetails .put ("os_minor" , uaClient .operatingSystem .minor );
206
+ }
207
+ break ;
208
+ case DEVICE :
209
+ if (uaClient .device != null && uaClient .device .name != null ) {
210
+ uaDetails .put ("device" , uaClient .device .name );
211
+ } else {
212
+ uaDetails .put ("device" , "Other" );
213
+ }
214
+ break ;
215
+ }
145
216
}
146
217
}
147
218
@@ -201,6 +272,10 @@ UserAgentParser getUaParser() {
201
272
return parser ;
202
273
}
203
274
275
+ public boolean isUseECS () {
276
+ return useECS ;
277
+ }
278
+
204
279
public static final class Factory implements Processor .Factory {
205
280
206
281
private final Map <String , UserAgentParser > userAgentParsers ;
@@ -217,10 +292,7 @@ public UserAgentProcessor create(Map<String, Processor.Factory> factories, Strin
217
292
String regexFilename = readStringProperty (TYPE , processorTag , config , "regex_file" , IngestUserAgentPlugin .DEFAULT_PARSER_NAME );
218
293
List <String > propertyNames = readOptionalList (TYPE , processorTag , config , "properties" );
219
294
boolean ignoreMissing = readBooleanProperty (TYPE , processorTag , config , "ignore_missing" , false );
220
- Object ecsValue = config .remove ("ecs" );
221
- if (ecsValue != null ) {
222
- deprecationLogger .deprecated ("setting [ecs] is deprecated as ECS format is the default and only option" );
223
- }
295
+ boolean useECS = readBooleanProperty (TYPE , processorTag , config , "ecs" , true );
224
296
225
297
UserAgentParser parser = userAgentParsers .get (regexFilename );
226
298
if (parser == null ) {
@@ -242,22 +314,53 @@ public UserAgentProcessor create(Map<String, Processor.Factory> factories, Strin
242
314
properties = EnumSet .allOf (Property .class );
243
315
}
244
316
245
- return new UserAgentProcessor (processorTag , field , targetField , parser , properties , ignoreMissing );
317
+ if (useECS == false ) {
318
+ deprecationLogger .deprecated ("setting [ecs] to false for non-common schema " +
319
+ "format is deprecated and will be removed in 8.0, set to true or remove to use the non-deprecated format" );
320
+ }
321
+
322
+ return new UserAgentProcessor (processorTag , field , targetField , parser , properties , ignoreMissing , useECS );
246
323
}
247
324
}
248
325
249
326
enum Property {
250
327
251
328
NAME ,
329
+ // Deprecated in 6.7 (superceded by VERSION), to be removed in 8.0
330
+ @ Deprecated MAJOR ,
331
+ @ Deprecated MINOR ,
332
+ @ Deprecated PATCH ,
252
333
OS ,
334
+ // Deprecated in 6.7 (superceded by just using OS), to be removed in 8.0
335
+ @ Deprecated OS_NAME ,
336
+ @ Deprecated OS_MAJOR ,
337
+ @ Deprecated OS_MINOR ,
253
338
DEVICE ,
339
+ @ Deprecated BUILD , // Same deprecated as OS_* above
254
340
ORIGINAL ,
255
341
VERSION ;
256
342
343
+ private static Set <Property > DEPRECATED_PROPERTIES ;
344
+
345
+ static {
346
+ Set <Property > deprecated = new HashSet <>();
347
+ for (Field field : Property .class .getFields ()) {
348
+ if (field .isEnumConstant () && field .isAnnotationPresent (Deprecated .class )) {
349
+ deprecated .add (valueOf (field .getName ()));
350
+ }
351
+ }
352
+ DEPRECATED_PROPERTIES = deprecated ;
353
+ }
354
+
257
355
public static Property parseProperty (String propertyName ) {
258
356
try {
259
- return valueOf (propertyName .toUpperCase (Locale .ROOT ));
260
- } catch (IllegalArgumentException e ) {
357
+ Property value = valueOf (propertyName .toUpperCase (Locale .ROOT ));
358
+ if (DEPRECATED_PROPERTIES .contains (value )) {
359
+ deprecationLogger .deprecated ("the [{}] property is deprecated for the user-agent processor" , propertyName );
360
+ }
361
+ return value ;
362
+ }
363
+ catch (IllegalArgumentException e ) {
261
364
throw new IllegalArgumentException ("illegal property value [" + propertyName + "]. valid values are " +
262
365
Arrays .toString (EnumSet .allOf (Property .class ).toArray ()));
263
366
}
0 commit comments