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

Express Events #64

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions components/NewRelicAgent/EETask.brs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
'**********************************************************
' EETask.brs
' New Relic Agent background task for Express Events.
'
' Copyright 2023 New Relic Inc. All Rights Reserved.
'**********************************************************

sub init()
m.top.functionName = "nrTaskMain"
m.loggingState = false
end sub

function nrPushEvent(event as Object) as Object
jsonString = FormatJson(event)

rport = CreateObject("roMessagePort")
urlReq = CreateObject("roUrlTransfer")

urlReq.SetUrl(m.eventApiUrl)
urlReq.RetainBodyOnError(true)
urlReq.EnablePeerVerification(false)
urlReq.EnableHostVerification(false)
urlReq.EnableEncodings(true)
urlReq.AddHeader("Api-Key", m.apikey)
urlReq.SetMessagePort(rport)
urlReq.AsyncPostFromString(jsonString)

'Use a short connection timeout (5 seconds) to unlock the task asap
msg = wait(5000, rport)
if type(msg) = "roUrlEvent" then
return msg.GetResponseCode()
else
'Connection timeout, cancel transfer and return error code (0)
nrLog("-- Express Event Task nrPushSamples: timeout, cancel request --")
urlReq.AsyncCancel()
return 0
end if
end function

function isStatusErr(res) as boolean
return res >= 400 or res = 0
end function

function nrTaskMain() as Void
if m.nr = invalid
'Assuming that parent node is com.newrelic.NRAgent
m.nr = m.top.getParent()
m.apiKey = m.top.apiKey
m.loggingState = m.nr.callFunc("nrCheckLoggingState")
end if

attributes = m.top.attributes.getFields()
'Remove garbage introduced by ContentNode
attributes.Delete("id")
attributes.Delete("focusedChild")
attributes.Delete("focusable")
attributes.Delete("change")

res = nrPushEvent(attributes)
if isStatusErr(res)
nrLog("-- Express Event Push FAILED with code " + Str(res) + " --")
if res = 429 or res = 408 or res = 503 or res = 0
'Too many requests, request timeout, service temporary unavailable, or connection timeout
nrLog("-- Express Event ERROR: unable to complete request or send data --")

'TODO: Disable EE for T seconds.
else if res = 413
'Request too large
nrLog("-- Express Event ERROR: request too large --")
else if res = 403
'Invalid key
nrLog("-- Express Event ERROR: invalid key --")
end if
else
nrLog("Express Event successfully sent")
end if
end function

function onConfigUpdate() as Void
m.eventApiUrl = m.top.eventApiUrl
end function

function nrLog(msg as Dynamic) as Void
if m.loggingState = true then m.nr.callFunc("nrLog", msg)
end function
21 changes: 21 additions & 0 deletions components/NewRelicAgent/EETask.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>

<!--
**********************************************************
EETask.xml
New Relic Agent background task for Express Events.

Copyright 2023 New Relic Inc. All Rights Reserved.
**********************************************************
-->

<component name="com.newrelic.EETask" extends="Task">
<interface>
<!-- Properties -->
<field id="eventApiUrl" type="string" onChange="onConfigUpdate" value=""/>
<field id="apiKey" type="string" value=""/>
<field id="attributes" type="node" />
</interface>

<script type="text/brightscript" uri="EETask.brs"/>
</component>
42 changes: 39 additions & 3 deletions components/NewRelicAgent/NRAgent.brs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ function NewRelicInit(account as String, apikey as String, region as String) as
m.bgTaskMetrics.setField("metricApiUrl", m.metricApiUrl)
m.bgTaskMetrics.sampleType = "metric"

'Create and configure Express Events task
m.eeTask = m.top.findNode("EETask")
m.eeTask.setField("apiKey", m.nrInsightsApiKey)
m.eeTask.setField("eventApiUrl", m.eventApiUrl)

'Init harvest timer (events)
m.nrHarvestTimerEvents = m.top.findNode("nrHarvestTimerEvents")
m.nrHarvestTimerEvents.ObserveField("fire", "nrHarvestTimerHandlerEvents")
Expand Down Expand Up @@ -233,6 +238,37 @@ function nrSceneLoaded(sceneName as String) as Void
nrSendCustomEvent("RokuSystem", "SCENE_LOADED", {"sceneName": sceneName})
end function

function nrSendExpressEvent(eventType as String, actionName as String, attr = invalid as Object) as boolean
nrLog("nrSendExpressEvent")
if m.eeTask.state = "run"
nrLog("Express Events Task still running")
return false
else
ev = nrCreateEvent(eventType, actionName)
if attr <> invalid
ev.Append(attr)
end if

nrLog(["Express Event ev = ", ev])

nodeAttr = createObject("RoSGNode","ContentNode")
if nodeAttr.addFields(ev) = false
nrLog("Error adding fields to EE attributes")
return false
end if
m.eeTask.setField("attributes", nodeAttr)

'Try to avoid a race condition: check again just in case another thread sent an EE between the first check and now.
if m.eeTask.state = "run"
nrLog("Express Events Task still running (last chance)")
return false
else
m.eeTask.control = "RUN"
return true
end if
end if
end function

function nrSendCustomEvent(eventType as String, actionName as String, attr = invalid as Object) as Void
nrLog("nrSendCustomEvent")
ev = nrCreateEvent(eventType, actionName)
Expand Down Expand Up @@ -1518,7 +1554,7 @@ end function
function nrHarvestTimerHandlerEvents() as Void
nrLog("--- nrHarvestTimerHandlerEvents ---")

if LCase(m.bgTaskEvents.state) = "run"
if m.bgTaskEvents.state = "run"
nrLog("NRTaskEvents still running, abort")
return
end if
Expand All @@ -1529,7 +1565,7 @@ end function
function nrHarvestTimerHandlerLogs() as Void
nrLog("--- nrHarvestTimerHandlerLogs ---")

if LCase(m.bgTaskLogs.state) = "run"
if m.bgTaskLogs.state = "run"
nrLog("NRTaskLogs still running, abort")
return
end if
Expand All @@ -1542,7 +1578,7 @@ function nrHarvestTimerHandlerMetrics() as Void

nrSendHttpCountMetrics()

if LCase(m.bgTaskMetrics.state) = "run"
if m.bgTaskMetrics.state = "run"
nrLog("NRTaskMetrics still running, abort")
return
end if
Expand Down
2 changes: 2 additions & 0 deletions components/NewRelicAgent/NRAgent.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<function name="nrAddDomainSubstitution"/>
<function name="nrDelDomainSubstitution"/>
<function name="nrAppStarted"/>
<function name="nrSendExpressEvent"/>
<function name="nrSendCustomEvent"/>
<function name="nrSendSystemEvent"/>
<function name="nrSendVideoEvent"/>
Expand Down Expand Up @@ -68,5 +69,6 @@
<Timer id="nrHarvestTimerLogs" repeat="true"/>
<com.newrelic.NRTask id="NRTaskMetrics"/>
<Timer id="nrHarvestTimerMetrics" repeat="true"/>
<com.newrelic.EETask id="EETask"/>
</children>
</component>
5 changes: 5 additions & 0 deletions source/Main.brs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ sub Main(aa as Object)
m.syslog = NewRelicSystemStart(m.port)

runSearchTask("hello")

'TODO: use wrapper
m.nr.callFunc("nrSendExpressEvent", "ExpressEvent", "AppInit", {"a_int": 100, "a_str": "hello"})
m.nr.callFunc("nrSendExpressEvent", "ExpressEvent", "AppInit", {"a_int": 100, "a_str": "hello"})
m.nr.callFunc("nrSendExpressEvent", "ExpressEvent", "AppInit", {"a_int": 100, "a_str": "hello"})

while(true)
msg = wait(0, m.port)
Expand Down