Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Grok Prepper Configuration and Boilerplate #302

Merged
merged 4 commits into from
Sep 27, 2021

Conversation

graytaylor0
Copy link
Member

@graytaylor0 graytaylor0 commented Sep 21, 2021

Signed-off-by: graytaylor0 [email protected]

Description

  • includes reading the configuration for Grok Prepper, which includes adding PluginSetting validation for Map<String, String>, List, and Map<String, List>.
  • includes boilerplate for Grok Prepper implementation of AbstractPrepper

Issues Resolved

#301

Check List

  • [ X ] New functionality includes testing.
    • [ X ] All tests pass
  • New functionality has been documented.
    • New functionality has javadoc added
  • [ X ] Commits are signed per the DCO using --signoff

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

@graytaylor0 graytaylor0 linked an issue Sep 21, 2021 that may be closed by this pull request
laneholloway
laneholloway previously approved these changes Sep 21, 2021
}

dependencies {
implementation "com.fasterxml.jackson.core:jackson-databind:2.12.4"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we have this already defined higher up in the hierarchy?

Copy link
Member Author

@graytaylor0 graytaylor0 Sep 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We actually don't. Could add this as a dependency to data-prepper-plugins but right now each individual plugin adds this if it is used. We do have mavenCentral() as part of the project's build.gradle but other plugins that have used dependencies from mavenCentral() had it again. Maybe they don't need it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not a dependency, but you can inherit the version number. So, you should remove the version number from this line.

See: https://github.com/opensearch-project/data-prepper/blob/main/build.gradle#L74

import java.util.Collections;
import java.util.List;

public class GrokPrepperTests {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are going to be adding more tests in here, right? ;)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha there will be more when actual functionality is added.

Comment on lines 155 to 158
((List<?>) object).stream().filter(o -> !(o instanceof String)).forEach(o -> {
throw new IllegalArgumentException(String.format(UNEXPECTED_ATTRIBUTE_TYPE_MSG, object.getClass(), attribute));
});
return (List<String>) object;
Copy link
Contributor

@cmanning09 cmanning09 Sep 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be simplified:

    ((List<?>) object).).forEach(o -> {
        if (!(o instanceof String)) {
            throw new IllegalArgumentException(String.format(UNEXPECTED_ATTRIBUTE_TYPE_MSG, object.getClass(), attribute));
        }
    }

* @return the value of the specified attribute, or {@code defaultValue} if this settings contains no value for
* the attribute
*/
@SuppressWarnings("unchecked")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is dangerous. What are we suppressing here?

Copy link
Member Author

@graytaylor0 graytaylor0 Sep 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It suppresses this warning which only comes from Intellij as far as I can tell.
Unchecked cast: 'java.lang.Object' to 'java.util.Map<java.lang.String,java.util.List<java.lang.String>>' . It is because of the cast on the return values from Object.

Comment on lines 206 to 208
((List<?>) value).stream().filter(o -> !(o instanceof String)).forEach(o -> {
throw new IllegalArgumentException(String.format(UNEXPECTED_ATTRIBUTE_TYPE_MSG, object.getClass(), attribute));
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See other comment above about improving this check

import com.amazon.dataprepper.model.record.Record;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should start using JUnit 5 for tests.

import java.util.Collection;


@DataPrepperPlugin(name = "grok_prepper", type = PluginType.PREPPER)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should name this grok so that users need only type grok in the configuration file.

e.g.

prepper:
  grok:
    match: "log"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good note

dependencies {
implementation project(':data-prepper-api')
implementation project(':data-prepper-plugins:common')
testImplementation project(':data-prepper-api').sourceSets.test.output
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we actually use this? Or was this line copied from another project?

* @return the value of the specified attribute, or {@code defaultValue} if this settings contains no value for
* the attribute
*/
public List<String> getStringListOrDefault(final String attribute, final List<String> defaultValue) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method and the other methods can probably be made somewhat more generic.

public <T> List<T> getTypedListOrDefault(final String attribute, final Class<T> type, final List<T> defaultValue)

You can replace your instanceof with isAssignableFrom.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had thought about this and wasn't sure if passing the Class type was considered good practice. Doing this definitely scales PluginSettings better though.

Object object = getAttributeOrDefault(attribute, defaultValue);
if (object == null) {
return null;
} else if (object instanceof Map) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code can be cleaner by throwing first.

I'd also create a variable just to avoid operating immediately after a cast, but I think that is of less importance.

if ( !(object instanceof Map))
  throw new IllegalArgumentException(...)

Map<?, ?> map = object;
map.forEach( ...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is definitely cleaner. Just to clarify you are not suggesting that this is done immediately after the getAttributeOrDefault call, but after the if statement for checking if object is null?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the behavior of a null value is to return null, then it should be after the null check.

Object object = getAttributeOrDefault(attribute, defaultValue);
if (object == null) {
    return null;

if ( !(object instanceof Map))
  throw new IllegalArgumentException(...)

Map<?, ?> map = object;
map.forEach( ...

Object object = getAttributeOrDefault(attribute, defaultValue);
if (object == null) {
return null;
} else if (object instanceof Map) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should try to avoid this nesting by throwing immediately. See my note above.

Comment on lines 203 to 216
if (key instanceof String) {
if (value instanceof List){
((List<?>) value).forEach(val -> {
if (!(val instanceof String)) {
throw new IllegalArgumentException(String.format(UNEXPECTED_ATTRIBUTE_TYPE_MSG, object.getClass(), attribute));
}
});
} else {
throw new IllegalArgumentException(String.format(UNEXPECTED_ATTRIBUTE_TYPE_MSG, object.getClass(), attribute));
}
} else {
throw new IllegalArgumentException(String.format(UNEXPECTED_ATTRIBUTE_TYPE_MSG, object.getClass(), attribute));
}
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instance check for String, List, Map is repeated in this class. Consider defining a function or java BiPredicate that takes in the object & type, and checks if they are of same type else throws exception. This code can be reused in different methods in this class.

@@ -180,4 +254,17 @@ public Long getLongOrDefault(final String attribute, final long defaultValue) {
throw new IllegalArgumentException(String.format(UNEXPECTED_ATTRIBUTE_TYPE_MSG, object.getClass(), attribute));
}

private <T> void checkObjectType(String attribute, Object object, Class<T> type) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: final for method params line 257 & 263 to be consistent with other methods

@@ -35,4 +35,5 @@ include 'data-prepper-plugins:otel-trace-group-prepper'
include 'data-prepper-plugins:otel-trace-source'
include 'data-prepper-plugins:peer-forwarder'
include 'data-prepper-plugins:blocking-buffer'
include 'data-prepper-plugins:grok-prepper'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you add this dependency? In general, our plugins should not depend on each other.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The settings.gradle file defines all of the internal projects. All of the plugin projects are required to go in here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are correct on this.

@@ -35,4 +35,5 @@ include 'data-prepper-plugins:otel-trace-group-prepper'
include 'data-prepper-plugins:otel-trace-source'
include 'data-prepper-plugins:peer-forwarder'
include 'data-prepper-plugins:blocking-buffer'
include 'data-prepper-plugins:grok-prepper'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are correct on this.

@graytaylor0 graytaylor0 merged commit 1cb44e1 into opensearch-project:main Sep 27, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Grok Prepper Configuration and Boilerplate
5 participants