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

[Stratconn-2879] | Set up DataDog dashboard to track requests to Oauth Supported Destinations. #2103

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { RequestClient } from '@segment/actions-core'
import { RequestClient, StatsContext } from '@segment/actions-core'
import type { Payload as ProspectsPayload } from './prospects/generated-types'
import { ProspectsType } from './pa-type'

Expand All @@ -20,9 +20,10 @@ export default class Pardot {
this.request = request
}

upsertRecord = async (payload: ProspectsPayload) => {
upsertRecord = async (payload: ProspectsPayload, statsContext?: StatsContext) => {
const prospect = this.buildProspectJSON(payload)

statsContext?.statsClient?.incr('oauth_app_api_call', 1, [...statsContext?.tags, `endpoint:upsert-prospect-record`])
return this.request<ProspectUpsertResponseData>(
`${this.baseUrl}/api/${PARDOT_API_VERSION}/objects/prospects/do/upsertLatestByEmail`,
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,11 @@ const action: ActionDefinition<Settings, Payload> = {
},
customFields: customFields
},
perform: async (request, { settings, payload }) => {
perform: async (request, { settings, payload, statsContext }) => {
const baseUrl = settings.isSandbox ? 'https://pi.demo.pardot.com' : 'https://pi.pardot.com'
const pa: Pardot = new Pardot(settings.businessUnitID, baseUrl, request)
try {
return await pa.upsertRecord(payload)
return await pa.upsertRecord(payload, statsContext)
} catch (err) {
const error = err as HTTPError
if (!error.response) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ const destination: AudienceDestinationDefinition<Settings, AudienceSettings> = {
full_audience_sync: false // If true, we send the entire audience. If false, we just send the delta.
},
async createAudience(request, createAudienceInput) {
const { audienceName, audienceSettings, settings } = createAudienceInput
const { audienceName, audienceSettings, settings, statsContext } = createAudienceInput
const endpoint = settings.region
const description = audienceSettings?.description
const advertiser_id = audienceSettings?.advertiserId
Expand Down Expand Up @@ -206,7 +206,7 @@ const destination: AudienceDestinationDefinition<Settings, AudienceSettings> = {
// Regular expression to find a advertiserId numeric string and replace the quoted advertiserId string with an unquoted number
// AdvertiserId is very big number string and can not be assigned or converted to number directly as it changes the value due to integer overflow.
payloadString = payloadString.replace(REGEX_ADVERTISERID, '"advertiserId":$1')

statsContext?.statsClient?.incr('oauth_app_api_call', 1, [...statsContext?.tags, `endpoint:createAudience`])
const response = await request(`${endpoint}/amc/audiences/metadata`, {
method: 'POST',
body: payloadString,
Expand All @@ -227,7 +227,7 @@ const destination: AudienceDestinationDefinition<Settings, AudienceSettings> = {
async getAudience(request, getAudienceInput) {
// getAudienceInput.externalId represents audience ID that was created in createAudience
const audience_id = getAudienceInput.externalId
const { settings } = getAudienceInput
const { settings, statsContext } = getAudienceInput
const endpoint = settings.region

if (!audience_id) {
Expand All @@ -236,6 +236,7 @@ const destination: AudienceDestinationDefinition<Settings, AudienceSettings> = {
// @ts-ignore - TS doesn't know about the oauth property
const authSettings = getAuthSettings(settings)
const authToken = await getAuthToken(request, settings, authSettings)
statsContext?.statsClient?.incr('oauth_app_api_call', 1, [...statsContext?.tags, `endpoint:getAudience`])
const response = await request(`${endpoint}/amc/audiences/metadata/${audience_id}`, {
method: 'GET',
headers: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ActionDefinition, RequestClient } from '@segment/actions-core'
import type { ActionDefinition, RequestClient, StatsContext } from '@segment/actions-core'
import type { AudienceSettings, Settings } from '../generated-types'
import type { Payload } from './generated-types'
import { CONSTANTS, RecordsResponseType } from '../utils'
Expand Down Expand Up @@ -109,23 +109,25 @@ const action: ActionDefinition<Settings, Payload> = {
default: 10000
}
},
perform: (request, { settings, payload, audienceSettings }) => {
return processPayload(request, settings, [payload], audienceSettings)
perform: (request, { settings, payload, audienceSettings, statsContext }) => {
return processPayload(request, settings, [payload], audienceSettings, statsContext)
},
performBatch: (request, { settings, payload: payloads, audienceSettings }) => {
return processPayload(request, settings, payloads, audienceSettings)
performBatch: (request, { settings, payload: payloads, audienceSettings, statsContext }) => {
return processPayload(request, settings, payloads, audienceSettings, statsContext)
}
}

async function processPayload(
request: RequestClient,
settings: Settings,
payload: Payload[],
audienceSettings: AudienceSettings
audienceSettings: AudienceSettings,
statsContext: StatsContext | undefined
) {
const payloadRecord = createPayloadToUploadRecords(payload, audienceSettings)
// Regular expression to find a audienceId numeric string and replace the quoted audienceId string with an unquoted number
const payloadString = JSON.stringify(payloadRecord).replace(/"audienceId":"(\d+)"/, '"audienceId":$1')
statsContext?.statsClient?.incr('oauth_app_api_call', 1, [...statsContext?.tags, `endpoint:uploadAudienceRecords`])

const response = await request<RecordsResponseType>(`${settings.region}/amc/audiences/records`, {
method: 'POST',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ const action: ActionDefinition<Settings, Payload> = {
}
},

perform: async (request, { payload, settings }) => {
perform: async (request, { payload, settings, statsContext }) => {
/* Enforcing this here since Conversion ID is required for the Enhanced Conversions API
but not for the Google Ads API. */
if (!settings.conversionTrackingId) {
Expand Down Expand Up @@ -251,6 +251,8 @@ const action: ActionDefinition<Settings, Payload> = {
})

try {
statsContext?.statsClient?.incr('oauth_app_api_call', 1, [...statsContext?.tags, `endpoint:postConversion`])

return await request('https://www.google.com/ads/event/api/v1', {
method: 'post',
searchParams: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ const action: ActionDefinition<Settings, Payload> = {
customVariableIds.data[0].results
)
}
statsContext?.statsClient?.incr('oauth_app_api_call', 1, [...statsContext?.tags, `endpoint:uploadCallConversions`])
const response: ModifiedResponse<PartialErrorResponse> = await request(
`https://googleads.googleapis.com/${getApiVersion(features, statsContext)}/customers/${
settings.customerId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ const action: ActionDefinition<Settings, Payload> = {
hashedPhoneNumber: isHashedInformation(payload.phone_number) ? payload.phone_number : hash(phoneNumber)
} as UserIdentifierInterface)
}
statsContext?.statsClient?.incr('oauth_app_api_call', 1, [...statsContext?.tags, `endpoint:uploadClickConversions`])

const response: ModifiedResponse<PartialErrorResponse> = await request(
`https://googleads.googleapis.com/${getApiVersion(features, statsContext)}/customers/${
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,10 @@ const action: ActionDefinition<Settings, Payload> = {
}
})
}
statsContext?.statsClient?.incr('oauth_app_api_call', 1, [
...statsContext?.tags,
`endpoint:uploadConversionAdjustments`
])

const response: ModifiedResponse<PartialErrorResponse> = await request(
`https://googleads.googleapis.com/${getApiVersion(features, statsContext)}/customers/${
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,11 @@ const action: ActionDefinition<Settings, Payload> = {
default: true
}
},
perform: (request, { payload }) => {
return processData(request, [payload])
perform: (request, { payload, statsContext }) => {
return processData(request, [payload], statsContext)
},
performBatch: (request, { payload }) => {
return processData(request, payload)
performBatch: (request, { payload, statsContext }) => {
return processData(request, payload, statsContext)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Payload } from './generated-types'
import { IntegrationError, RequestClient } from '@segment/actions-core'
import { IntegrationError, RequestClient, StatsContext } from '@segment/actions-core'
import { GoogleSheets, GetResponse } from '../googleapis/index'
import { CONSTANTS } from '../constants'

Expand Down Expand Up @@ -119,7 +119,12 @@ function processGetSpreadsheetResponse(response: GetResponse, events: Payload[],
* @param updateBatch array of events to commit to the spreadsheet
* @param gs interface object capable of interacting with Google Sheets API
*/
async function processUpdateBatch(mappingSettings: MappingSettings, updateBatch: UpdateBatch[], gs: GoogleSheets) {
async function processUpdateBatch(
mappingSettings: MappingSettings,
updateBatch: UpdateBatch[],
gs: GoogleSheets,
statsContext: StatsContext | undefined
) {
// Utility function used to calculate which range an event should be written to
const getRange = (targetIndex: number, columnCount: number) => {
const targetRange = new A1(1, targetIndex)
Expand All @@ -142,7 +147,7 @@ async function processUpdateBatch(mappingSettings: MappingSettings, updateBatch:
range: `${mappingSettings.spreadsheetName}!${headerRowRange.toString()}`,
values: [['id', ...mappingSettings.columns]]
})

statsContext?.statsClient?.incr('oauth_app_api_call', 1, [...statsContext?.tags, `endpoint:batchUpdate`])
return gs.batchUpdate(mappingSettings, batchPayload)
}

Expand Down Expand Up @@ -186,7 +191,12 @@ async function processUpdateBatch(mappingSettings: MappingSettings, updateBatch:
* @param gs interface object capable of interacting with Google Sheets API
* @returns
*/
async function processAppendBatch(mappingSettings: MappingSettings, appendBatch: AppendBatch[], gs: GoogleSheets) {
async function processAppendBatch(
mappingSettings: MappingSettings,
appendBatch: AppendBatch[],
gs: GoogleSheets,
statsContext: StatsContext | undefined
) {
if (appendBatch.length <= 0) {
return
}
Expand All @@ -195,7 +205,7 @@ async function processAppendBatch(mappingSettings: MappingSettings, appendBatch:
const values = appendBatch.map(({ identifier, event }) =>
generateColumnValuesFromFields(identifier, event, mappingSettings.columns)
)

statsContext?.statsClient?.incr('oauth_app_api_call', 1, [...statsContext?.tags, `endpoint:append-spreadsheet`])
return gs.append(mappingSettings, `A${DATA_ROW_OFFSET}`, values)
}

Expand All @@ -204,7 +214,7 @@ async function processAppendBatch(mappingSettings: MappingSettings, appendBatch:
* @param request request object used to perform HTTP calls
* @param events array of events to commit to the spreadsheet
*/
async function processData(request: RequestClient, events: Payload[]) {
async function processData(request: RequestClient, events: Payload[], statsContext: StatsContext | undefined) {
// These are assumed to be constant across all events
const mappingSettings = {
spreadsheetId: events[0].spreadsheet_id,
Expand All @@ -214,16 +224,16 @@ async function processData(request: RequestClient, events: Payload[]) {
}

const gs: GoogleSheets = new GoogleSheets(request)

statsContext?.statsClient?.incr('oauth_app_api_call', 1, [...statsContext?.tags, `endpoint:get-spreadsheet`])
// Get all of the row identifiers (assumed to be in the first column A)
const response = await gs.get(mappingSettings, `A${DATA_ROW_OFFSET}:A`)

// Use the retrieved row identifiers along with the incoming events to decide which ones should be appended or updated.
const { appendBatch, updateBatch } = processGetSpreadsheetResponse(response.data, events, mappingSettings)

const promises = [
processUpdateBatch(mappingSettings, updateBatch, gs),
processAppendBatch(mappingSettings, appendBatch, gs)
processUpdateBatch(mappingSettings, updateBatch, gs, statsContext),
processAppendBatch(mappingSettings, appendBatch, gs, statsContext)
]

return await Promise.all(promises)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HTTPError } from '@segment/actions-core'
import { HTTPError, StatsContext } from '@segment/actions-core'
import { ModifiedResponse } from '@segment/actions-core'
import { RequestClient } from '@segment/actions-core'
import { CustomSearchToAssociateThrowableError } from '../errors'
Expand Down Expand Up @@ -35,7 +35,8 @@ export class Hubspot {
searchFields: { [key: string]: unknown },
objectType: string,
responseProperties: string[],
responseSortBy: string[]
responseSortBy: string[],
statsContext?: StatsContext
) {
if (typeof searchFields === 'object' && Object.keys(searchFields).length > 0) {
const searchPayload: SearchPayload = {
Expand All @@ -54,6 +55,10 @@ export class Hubspot {
]
})
}
statsContext?.statsClient?.incr('oauth_app_api_call', 1, [
...statsContext?.tags,
`endpoint:search-${this.objectType}-object`
])

return this.request<SearchResponse>(`${HUBSPOT_BASE_URL}/crm/v3/objects/${objectType}/search`, {
method: 'POST',
Expand All @@ -70,7 +75,16 @@ export class Hubspot {
* @param {{[key: string]: unknown}} properties A list of key-value pairs of properties of the object
* @returns {Promise<ModifiedResponse<UpsertCompanyResponse>>} A promise that resolves the updated object
*/
async create(properties: { [key: string]: unknown }, associations: CreateAssociation[] = []) {
async create(
properties: { [key: string]: unknown },
associations: CreateAssociation[] = [],
statsContext?: StatsContext
) {
statsContext?.statsClient?.incr('oauth_app_api_call', 1, [
...statsContext?.tags,
`endpoint:create-${this.objectType}-object`
])

return this.request<UpsertRecordResponse>(`${HUBSPOT_BASE_URL}/crm/v3/objects/${this.objectType}`, {
method: 'POST',
json: {
Expand All @@ -87,7 +101,17 @@ export class Hubspot {
* @param {String} [idProperty] Unique property of object record to match with uniqueIdentifier, if this parameter is not defined then uniqueIdentifier is matched with HubSpot generated record ID
* @returns {Promise<ModifiedResponse<UpsertRecordResponse>>} A promise that resolves the updated object
*/
async update(uniqueIdentifier: string, properties: { [key: string]: unknown }, idProperty?: string) {
async update(
uniqueIdentifier: string,
properties: { [key: string]: unknown },
idProperty?: string,
statsContext?: StatsContext
) {
statsContext?.statsClient?.incr('oauth_app_api_call', 1, [
...statsContext?.tags,
`endpoint:update-${this.objectType}-object`
])

// Construct the URL to update record of given objectType
// URL to update record by ID: /crm/v3/objects/{objectType}/{objectId}
// URL to update record by unique property: /crm/v3/objects/{objectType}/{uniqueIdentifier}?idProperty={uniquePropertyInternalName}
Expand All @@ -110,7 +134,8 @@ export class Hubspot {
* @param {batchInput[]} input Unique property of object record to match with uniqueIdentifier, if this parameter is not defined then uniqueIdentifier is matched with HubSpot generated record ID
* @returns {Promise<ModifiedResponse<UpsertRecordResponse>>} A promise that resolves the updated object
*/
async associate(objectId: string, toObjectId: string, associations: AssociationType[]) {
async associate(objectId: string, toObjectId: string, associations: AssociationType[], statsContext?: StatsContext) {
statsContext?.statsClient?.incr('oauth_app_api_call', 1, [...statsContext?.tags, `endpoint:associate-objects`])
const associateURL = `${HUBSPOT_BASE_URL}/crm/v4/objects/${this.objectType}/${objectId}/associations/${this.toObjectType}/${toObjectId}`

return this.request<UpsertRecordResponse>(associateURL, {
Expand All @@ -121,7 +146,8 @@ export class Hubspot {

async getObjectResponseToAssociate(
searchFieldsToAssociateCustomObjects: { [key: string]: unknown } | undefined,
associationType: AssociationType | null
associationType: AssociationType | null,
statsContext?: StatsContext
) {
try {
if (
Expand All @@ -136,7 +162,8 @@ export class Hubspot {
{ ...searchFieldsToAssociateCustomObjects },
this.toObjectType,
[],
[]
[],
statsContext
)
if (searchCustomResponseToAssociate?.data && searchCustomResponseToAssociate?.data?.total) {
return searchCustomResponseToAssociate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ const action: ActionDefinition<Settings, Payload> = {
}
}
},
perform: (request, { payload, settings }) => {
perform: (request, { payload, settings, statsContext }) => {
const eventName = transformEventName(payload.eventName)

const event: CustomBehavioralEvent = {
Expand All @@ -118,7 +118,10 @@ const action: ActionDefinition<Settings, Payload> = {
if (!payload.utk && !payload.email && !payload.objectId) {
throw new PayloadValidationError(`One of the following parameters: email, user token, or objectId is required`)
}

statsContext?.statsClient?.incr('oauth_app_api_call', 1, [
...statsContext?.tags,
`endpoint:send-custom-behavioural-event`
])
return request(`${HUBSPOT_BASE_URL}/events/v3/send`, {
method: 'post',
json: event
Expand Down
Loading
Loading