Skip to content

Commit

Permalink
Extended attribute types to preserve types when sending data
Browse files Browse the repository at this point in the history
fixed include path
  • Loading branch information
pasotee committed Aug 3, 2023
1 parent d5cdd3d commit fac3abd
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 9 deletions.
1 change: 1 addition & 0 deletions Source/Aptabase/Aptabase.Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public Aptabase(ReadOnlyTargetRules Target) : base(Target)
"EngineSettings",
"Slate",
"HTTP",
"Json",
"JsonUtilities",
"Projects",
"SlateCore",
Expand Down
40 changes: 37 additions & 3 deletions Source/Aptabase/Private/AptabaseAnalyticsProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
#include "AptabaseData.h"
#include "AptabaseLog.h"
#include "AptabaseSettings.h"
#include "ExtendedAnalyticsEventAttribute.h"

void FAptabaseAnalyticsProvider::RecordExtendedEvent(const FString& EventName, const TArray<FExtendedAnalyticsEventAttribute>& Attributes)
{
RecordEventInternal(EventName, Attributes);
}

bool FAptabaseAnalyticsProvider::StartSession(const TArray<FAnalyticsEventAttribute>& Attributes)
{
Expand Down Expand Up @@ -73,6 +79,19 @@ FString FAptabaseAnalyticsProvider::GetUserID() const
}

void FAptabaseAnalyticsProvider::RecordEvent(const FString& EventName, const TArray<FAnalyticsEventAttribute>& Attributes)
{
TArray<FExtendedAnalyticsEventAttribute> ExtendedAttributes;
for (const FAnalyticsEventAttribute& Attribute : Attributes)
{
FExtendedAnalyticsEventAttribute& NewAttribute = ExtendedAttributes.Emplace_GetRef();
NewAttribute.Key = Attribute.GetName();
NewAttribute.Value.Set<FString>(Attribute.GetValue());
}

RecordEventInternal(EventName, ExtendedAttributes);
}

void FAptabaseAnalyticsProvider::RecordEventInternal(const FString& EventName, const TArray<FExtendedAnalyticsEventAttribute>& Attributes)
{
const UAptabaseSettings* Settings = GetDefault<UAptabaseSettings>();
const TSharedPtr<IPlugin> AptabasePlugin = IPluginManager::Get().FindPlugin("Aptabase");
Expand All @@ -88,15 +107,30 @@ void FAptabaseAnalyticsProvider::RecordEvent(const FString& EventName, const TAr
EventPayload.SystemProps.OsVersion = FPlatformMisc::GetOSVersion();
EventPayload.SystemProps.IsDebug = !UE_BUILD_SHIPPING;

for (const FAnalyticsEventAttribute& Attribute : Attributes)
const TSharedPtr<FJsonObject> Props = MakeShared<FJsonObject>();

for (const FExtendedAnalyticsEventAttribute& Attribute : Attributes)
{
EventPayload.Props.Emplace(Attribute.GetName(), Attribute.GetValue());
const auto& AttributeValue = Attribute.Value;

if (AttributeValue.IsType<double>())
{
Props->SetField(Attribute.Key, MakeShared<FJsonValueNumber>(AttributeValue.Get<double>()));
}
else
{
Props->SetField(Attribute.Key, MakeShared<FJsonValueString>(AttributeValue.Get<FString>()));
}
}

const FString RequestUrl = FString::Printf(TEXT("%s/api/v0/event"), *Settings->GetApiUrl());

FString RequestJsonPayload;
FJsonObjectConverter::UStructToJsonObjectString(EventPayload, RequestJsonPayload);
const TSharedPtr<FJsonObject> Payload = FJsonObjectConverter::UStructToJsonObject(EventPayload);
Payload->SetObjectField("props", Props);

const TSharedRef<TJsonWriter<>> JsonWriter = TJsonWriterFactory<>::Create(&RequestJsonPayload, 0);
FJsonSerializer::Serialize(Payload.ToSharedRef(), JsonWriter);

UE_LOG(LogAptabase, Verbose, TEXT("Sending event: %s to %s Payload: %s"), *EventName, *RequestUrl, *RequestJsonPayload);

Expand Down
12 changes: 12 additions & 0 deletions Source/Aptabase/Private/AptabaseAnalyticsProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,19 @@
#include <Interfaces/IAnalyticsProvider.h>
#include <Interfaces/IHttpRequest.h>

struct FExtendedAnalyticsEventAttribute;

/**
* Implementation of Aptabase Analytics provider
*/
class FAptabaseAnalyticsProvider : public IAnalyticsProvider
{
public:
/**
* Overload for RecordEvent that takes an array of ExtendedAttributes
*/
void RecordExtendedEvent(const FString& EventName, const TArray<FExtendedAnalyticsEventAttribute>& Attributes);

private:
// Being IAnalyticsProvider Interface
virtual bool StartSession(const TArray<FAnalyticsEventAttribute>& Attributes) override;
Expand All @@ -19,6 +27,10 @@ class FAptabaseAnalyticsProvider : public IAnalyticsProvider
virtual FString GetUserID() const override;
virtual void RecordEvent(const FString& EventName, const TArray<FAnalyticsEventAttribute>& Attributes) override;
// End IAnalyticsProvider Interface
/**
* Internal function for common code in recording events
*/
void RecordEventInternal(const FString& EventName, const TArray<FExtendedAnalyticsEventAttribute>& Attributes);
/**
* @brief Callback executed when an event is successfully recoded by the analytics backend.
*/
Expand Down
6 changes: 0 additions & 6 deletions Source/Aptabase/Private/AptabaseData.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,4 @@ struct FAptabaseEventPayload
*/
UPROPERTY()
FAptabaseSystemProperties SystemProps;

/**
* @brief Custom attributes attached to the event
*/
UPROPERTY()
TMap<FString, FString> Props;
};
43 changes: 43 additions & 0 deletions Source/Aptabase/Private/ExtendedAnalyticsBlueprintLibrary.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include "ExtendedAnalyticsBlueprintLibrary.h"

#include <Analytics.h>
#include <Interfaces/IAnalyticsProvider.h>

#include "AptabaseAnalyticsProvider.h"
#include "AptabaseLog.h"
#include "ExtendedAnalyticsEventAttribute.h"

FExtendedAnalyticsEventAttribute UExtendedAnalyticsBlueprintLibrary::MakeExtendedAnalyticsEventStringAttribute(const FString& Name, const FString& Value)
{
FExtendedAnalyticsEventAttribute Attribute;
Attribute.Key = Name;
Attribute.Value.Set<FString>(Value);
return Attribute;
}

FExtendedAnalyticsEventAttribute UExtendedAnalyticsBlueprintLibrary::MakeExtendedAnalyticsEventNumberAttribute(const FString& Name, const double Value)
{
FExtendedAnalyticsEventAttribute Attribute;
Attribute.Key = Name;
Attribute.Value.Set<double>(Value);
return Attribute;
}

void UExtendedAnalyticsBlueprintLibrary::RecordEventWithAttributes(const FString& EventName, const TArray<FExtendedAnalyticsEventAttribute>& Attributes)
{
const TSharedPtr<IAnalyticsProvider> Provider = FAnalytics::Get().GetDefaultConfiguredProvider();
if (!Provider.IsValid())
{
UE_LOG(LogAptabase, Warning, TEXT("RecordEventWithAttributes: Failed to get the default analytics provider. Double check your [Analytics] configuration in your INI"));
return;
}

const TSharedPtr<FAptabaseAnalyticsProvider> AptabaseProvider = StaticCastSharedPtr<FAptabaseAnalyticsProvider>(Provider);
if (!AptabaseProvider.IsValid())
{
UE_LOG(LogAptabase, Warning, TEXT("RecordEventWithAttributes: Attributes of type FExtendedAnalyticsEventAttribute only works with Aptabase analytics"));
return;
}

AptabaseProvider->RecordExtendedEvent(EventName, Attributes);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#include "ExtendedAnalyticsEventAttribute.h"
32 changes: 32 additions & 0 deletions Source/Aptabase/Public/ExtendedAnalyticsBlueprintLibrary.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#pragma once

#include <CoreMinimal.h>
#include <Kismet/BlueprintFunctionLibrary.h>

#include "ExtendedAnalyticsBlueprintLibrary.generated.h"

/**
* A C++ and Blueprint accessible library of utility functions for extended analytics tracking
*/
UCLASS()
class APTABASE_API UExtendedAnalyticsBlueprintLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()

public:
/**
* Creates and ExtendedAnalyticsEventAttribute with a name and a string value
*/
UFUNCTION(BlueprintPure, Category = "Analytics")
static FExtendedAnalyticsEventAttribute MakeExtendedAnalyticsEventStringAttribute(const FString& Name, const FString& Value);
/**
* Creates and ExtendedAnalyticsEventAttribute with a name and a number (double) value
*/
UFUNCTION(BlueprintPure, Category = "Analytics")
static FExtendedAnalyticsEventAttribute MakeExtendedAnalyticsEventNumberAttribute(const FString& Name, const double Value);
/**
* Records an event has happened by name with an array of ExtendedAttributes (preserve native type)
*/
UFUNCTION(BlueprintCallable, Category = "Analytics")
static void RecordEventWithAttributes(const FString& EventName, const TArray<FExtendedAnalyticsEventAttribute>& Attributes);
};
27 changes: 27 additions & 0 deletions Source/Aptabase/Public/ExtendedAnalyticsEventAttribute.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#pragma once

#include <Misc/TVariant.h>

#include "ExtendedAnalyticsEventAttribute.generated.h"

/**
* Struct to hold type specific data for analytics events.
* @note similar to FAnalyticsEventAttribute::AttrTypeEnum leveraging the TVariant type
* @note properties are not blueprint exposed because TVariant is not blueprint friendly
*/
USTRUCT(BlueprintType)
struct FExtendedAnalyticsEventAttribute
{
GENERATED_BODY();

/**
* Name of the Attribute
*/
FString Key;

/**
* Value of the Attribute
* @note we can support more types but they need to be converted to the correct JSON type before sending
*/
TVariant<FString, double> Value;
};

0 comments on commit fac3abd

Please sign in to comment.