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

Track Self-describing event in a Object Orientated manner. #419

Open
rvp-diconium opened this issue Jan 13, 2021 · 2 comments
Open

Track Self-describing event in a Object Orientated manner. #419

rvp-diconium opened this issue Jan 13, 2021 · 2 comments
Labels
type:enhancement New features or improvements to existing features.

Comments

@rvp-diconium
Copy link

I'm fairly new to snowplow so maybe that's just a question and not feature request, but I'll write as feature request.
Preface the data team on my project will use snowplow 100% on self-describing events

Is your feature request related to a problem? Please describe.
It's general bad idea to have scattered strings around the code to track items (those strings are usually the same for big parts of the project and making it so is error prone). Having a schema to conform to opens the possibility to using an object instead.
But unfortunately, from what I understood reading the documentation and the code the only way to track self-describing events is by adding to a Map like:

Map<String, String> eventData = new HashMap<>();
eventData.put("Event", "Data")
SelfDescribingJson json = new SelfDescribingJson("iglu:com.acme/example/jsonschema/1-0-0", eventData);
tracker.track(json);

Describe the solution you'd like
Taking heavy inspiration in libraries like Retrofit or Room I would rather use objects. Meaning, I would copy/paste the Json schema, to a data generator website, have a Kotlin data class auto-generated and pasted back into our code repository.
Then to track we would:

MyCustomEvent event = MyCustomEvent(123, "param1", "param2")
MoshiEvent data = MoshiEvent(MyCustomEvent.SCHEMA,event ) // it could be gson, jackson, it doesn't matter
tracker.track(data)

Describe alternatives you've considered
I see the in SelfDescribingJson it uses the toString calling Util.mapToJSONObject(payload).toString(); and that Util uses the JSONObject(map) constructor from org.json.
That makes it seems I could use any Json library I want to get the String, and build the object with JsonObject(jsonString), but that option is not officially documented and seems kind of hacky. At the end it would be something like:

MyCustomEvent event = MyCustomEvent(123, "param1", "param2")
JsonObject jsonEvent = JsonObject(moshiAdapter.toJson(event))
SelfDescribingJson data = SelfDescribingJson(MyCustomEvent.SCHEMA, jsonEvent)
tracker.track(data)

Is that how others do it? If yes, it should be documented and guaranteed to be not a breaking behavior.

Hope it was clear.

@rvp-diconium rvp-diconium added the type:enhancement New features or improvements to existing features. label Jan 13, 2021
@AlexBenny
Copy link
Contributor

Thanks @rvp-diconium for raising this proposal. We are not planning to change the behaviour of SelfDescribingJson shortly but the idea of a custom event generator tool is something we have experimented recently but not yet ready. If you are interested to work on this as open source tool, we would be really happy to collaborate.

Meanwhile, as you suggest, the cleanest solution is to create proper custom events.

If you are interested to an alternative to the SelfDescribingJson approach I would suggest to directly extend the abstract class AbstractSelfDescribing and implement the two methods:

  • @NonNull Map<String, Object> getDataPayload()
  • @NonNull String getSchema()

An example (in Java):

public class MyCustomEvent extends AbstractSelfDescribing {
    private final String KEY_PROP1 = "prop1";
    private final String KEY_PROP2 = "prop2";

    String property1;
    String property2;

    // Mandatory methods to implement

    @Override
    public @NonNull String getSchema() {
        return MyConstants.SCHEMA_CUSTOM_EVENT;
    }

    @Override
    public @NonNull Map<String, Object> getDataPayload() {
        HashMap<String, Object> map = new HashMap<>();
        map.put(KEY_PROP1, property1);
        map.put(KEY_PROP2, property2);
        return map;
    }
}

It can be used in this way:

MyCustomEvent event = new MyCustomEvent();
event.property1 = "something";
event.property2 = "something_else";

tracker.track(event)

This is just a basic example, you can decorate the class with more constructors and utility methods.

It's important that the map generated by `getDataPayload is json serializable. If so, the tracker will take care of your custom event exactly like a SelfDescribingJson.

@rvp-diconium
Copy link
Author

Hi @AlexBenny thanks for the full detailed response.

From a library perspective, I understand you shouldn't be favoring any json serialization library over another, so this solution usually goes around doing adapters interface so that any one can be plugged-in.

The MyCustomEvent the way you suggested, it eliminates the spread of static strings around the code, but there still a bit too much manual boilerplate for my taste :)

On my current project I'll give a shot (whenever the ticket gets prioritized) to create a MoshiEvent extends AbstractSelfDescribing. This will receives object, schema and moshi instance over constructor and getDataPayload() can be automated by iterating the JsonObject. That way I can still use auto-generators like this to get the data class matching the schema the data team is generating.

And if from there I have something I can contribute back I'll report back here.

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:enhancement New features or improvements to existing features.
Projects
None yet
Development

No branches or pull requests

2 participants