2727import org .elasticsearch .ingest .useragent .UserAgentParser .Details ;
2828import org .elasticsearch .ingest .useragent .UserAgentParser .VersionedName ;
2929
30+ import java .lang .reflect .Field ;
3031import java .util .Arrays ;
3132import java .util .EnumSet ;
3233import java .util .HashMap ;
34+ import java .util .HashSet ;
3335import java .util .List ;
3436import java .util .Locale ;
3537import java .util .Map ;
@@ -51,15 +53,17 @@ public class UserAgentProcessor extends AbstractProcessor {
5153 private final Set <Property > properties ;
5254 private final UserAgentParser parser ;
5355 private final boolean ignoreMissing ;
56+ private final boolean useECS ;
5457
5558 public UserAgentProcessor (String tag , String field , String targetField , UserAgentParser parser , Set <Property > properties ,
56- boolean ignoreMissing ) {
59+ boolean ignoreMissing , boolean useECS ) {
5760 super (tag );
5861 this .field = field ;
5962 this .targetField = targetField ;
6063 this .parser = parser ;
6164 this .properties = properties ;
6265 this .ignoreMissing = ignoreMissing ;
66+ this .useECS = useECS ;
6367 }
6468
6569 boolean isIgnoreMissing () {
@@ -80,68 +84,135 @@ public IngestDocument execute(IngestDocument ingestDocument) {
8084
8185 Map <String , Object > uaDetails = new HashMap <>();
8286
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+ }
106112 }
107113 }
114+ uaDetails .put ("version" , version .toString ());
108115 }
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+ }
126132 }
127133 }
134+ osDetails .put ("version" , sb .toString ());
135+ osDetails .put ("full" , uaClient .operatingSystem .name + " " + sb .toString ());
128136 }
129- osDetails .put ("version" , sb .toString ());
130- osDetails .put ("full" , uaClient .operatingSystem .name + " " + sb .toString ());
137+ uaDetails .put ("os" , osDetails );
131138 }
132- uaDetails .put ("os" , osDetails );
133139 }
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+ }
145216 }
146217 }
147218
@@ -201,6 +272,10 @@ UserAgentParser getUaParser() {
201272 return parser ;
202273 }
203274
275+ public boolean isUseECS () {
276+ return useECS ;
277+ }
278+
204279 public static final class Factory implements Processor .Factory {
205280
206281 private final Map <String , UserAgentParser > userAgentParsers ;
@@ -217,10 +292,7 @@ public UserAgentProcessor create(Map<String, Processor.Factory> factories, Strin
217292 String regexFilename = readStringProperty (TYPE , processorTag , config , "regex_file" , IngestUserAgentPlugin .DEFAULT_PARSER_NAME );
218293 List <String > propertyNames = readOptionalList (TYPE , processorTag , config , "properties" );
219294 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 );
224296
225297 UserAgentParser parser = userAgentParsers .get (regexFilename );
226298 if (parser == null ) {
@@ -242,22 +314,53 @@ public UserAgentProcessor create(Map<String, Processor.Factory> factories, Strin
242314 properties = EnumSet .allOf (Property .class );
243315 }
244316
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 );
246323 }
247324 }
248325
249326 enum Property {
250327
251328 NAME ,
329+ // Deprecated in 6.7 (superceded by VERSION), to be removed in 8.0
330+ @ Deprecated MAJOR ,
331+ @ Deprecated MINOR ,
332+ @ Deprecated PATCH ,
252333 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 ,
253338 DEVICE ,
339+ @ Deprecated BUILD , // Same deprecated as OS_* above
254340 ORIGINAL ,
255341 VERSION ;
256342
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+
257355 public static Property parseProperty (String propertyName ) {
258356 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 ) {
261364 throw new IllegalArgumentException ("illegal property value [" + propertyName + "]. valid values are " +
262365 Arrays .toString (EnumSet .allOf (Property .class ).toArray ()));
263366 }
0 commit comments