@electrolux-oss/plugin-infrawallet-backend 1.1.0-20251216093006-79b0013 → 1.1.0-20251218080407-fbaf733
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -89,21 +89,22 @@ class DatadogClient extends InfraWalletClient.InfraWalletClient {
|
|
|
89
89
|
}
|
|
90
90
|
async fetchCosts(integrationConfig, client, query) {
|
|
91
91
|
const costData = [];
|
|
92
|
-
const startTime = moment__default.default(parseInt(query.startTime, 10));
|
|
93
|
-
const endTime = moment__default.default(parseInt(query.endTime, 10));
|
|
94
|
-
const
|
|
95
|
-
if (startTime.isBefore(
|
|
96
|
-
const historicalEndTime = moment__default.default.min(endTime,
|
|
97
|
-
const maxMonthRange =
|
|
92
|
+
const startTime = moment__default.default.utc(parseInt(query.startTime, 10)).startOf("month");
|
|
93
|
+
const endTime = moment__default.default.utc(parseInt(query.endTime, 10)).startOf("month");
|
|
94
|
+
const historicalCutoff = moment__default.default.utc().startOf("month").subtract(2, "months");
|
|
95
|
+
if (startTime.isBefore(historicalCutoff)) {
|
|
96
|
+
const historicalEndTime = moment__default.default.min(endTime, historicalCutoff.clone().subtract(1, "month"));
|
|
97
|
+
const maxMonthRange = 3;
|
|
98
98
|
let chunkStart = startTime.clone();
|
|
99
|
-
while (chunkStart.
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
historicalEndTime.clone()
|
|
103
|
-
|
|
99
|
+
while (chunkStart.isSameOrBefore(historicalEndTime)) {
|
|
100
|
+
let chunkEnd = chunkStart.clone().add(maxMonthRange - 1, "months");
|
|
101
|
+
if (chunkEnd.isAfter(historicalEndTime)) {
|
|
102
|
+
chunkEnd = historicalEndTime.clone();
|
|
103
|
+
}
|
|
104
|
+
const apiEndMonth = chunkEnd.clone().add(1, "month");
|
|
104
105
|
const historicalCost = await client.getHistoricalCostByOrg({
|
|
105
106
|
startMonth: chunkStart,
|
|
106
|
-
endMonth:
|
|
107
|
+
endMonth: apiEndMonth,
|
|
107
108
|
view: "sub-org"
|
|
108
109
|
});
|
|
109
110
|
try {
|
|
@@ -120,17 +121,15 @@ class DatadogClient extends InfraWalletClient.InfraWalletClient {
|
|
|
120
121
|
if (historicalCost.data) {
|
|
121
122
|
costData.push(...historicalCost.data);
|
|
122
123
|
}
|
|
123
|
-
chunkStart =
|
|
124
|
+
chunkStart = chunkStart.clone().add(maxMonthRange, "months");
|
|
124
125
|
}
|
|
125
126
|
}
|
|
126
|
-
if (endTime.isSameOrAfter(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
estimatedCostStartTime = firstDayOfLastMonth;
|
|
130
|
-
}
|
|
127
|
+
if (endTime.isSameOrAfter(historicalCutoff)) {
|
|
128
|
+
const estimatedStartTime = moment__default.default.max(startTime, historicalCutoff);
|
|
129
|
+
const apiEndTime = endTime.clone().add(1, "month");
|
|
131
130
|
const estimatedCost = await client.getEstimatedCostByOrg({
|
|
132
|
-
startMonth:
|
|
133
|
-
endMonth:
|
|
131
|
+
startMonth: estimatedStartTime,
|
|
132
|
+
endMonth: apiEndTime,
|
|
134
133
|
view: "sub-org"
|
|
135
134
|
});
|
|
136
135
|
try {
|
|
@@ -152,12 +151,13 @@ class DatadogClient extends InfraWalletClient.InfraWalletClient {
|
|
|
152
151
|
if (query.granularity === consts.GRANULARITY.MONTHLY) {
|
|
153
152
|
costData.forEach((costByOrg) => {
|
|
154
153
|
const orgName = costByOrg.attributes?.orgName;
|
|
155
|
-
|
|
154
|
+
const date = costByOrg.attributes?.date;
|
|
155
|
+
if (!this.evaluateIntegrationFilters(orgName, integrationConfig) || !date) {
|
|
156
156
|
return;
|
|
157
157
|
}
|
|
158
158
|
costs.push({
|
|
159
159
|
orgName,
|
|
160
|
-
date
|
|
160
|
+
date,
|
|
161
161
|
// only keep cost breakdown
|
|
162
162
|
charges: costByOrg.attributes?.charges?.filter((charge) => charge.chargeType !== "total")
|
|
163
163
|
});
|
|
@@ -165,10 +165,12 @@ class DatadogClient extends InfraWalletClient.InfraWalletClient {
|
|
|
165
165
|
} else {
|
|
166
166
|
costData.forEach((costByOrg) => {
|
|
167
167
|
const orgName = costByOrg.attributes?.orgName;
|
|
168
|
-
|
|
168
|
+
const date = costByOrg.attributes?.date;
|
|
169
|
+
if (!this.evaluateIntegrationFilters(orgName, integrationConfig) || !date) {
|
|
169
170
|
return;
|
|
170
171
|
}
|
|
171
|
-
const
|
|
172
|
+
const utcDate = moment__default.default.utc(date);
|
|
173
|
+
const daysInMonth = utcDate.daysInMonth();
|
|
172
174
|
costByOrg.attributes?.charges?.forEach((charge) => {
|
|
173
175
|
if (charge.chargeType === "total") {
|
|
174
176
|
return;
|
|
@@ -176,7 +178,7 @@ class DatadogClient extends InfraWalletClient.InfraWalletClient {
|
|
|
176
178
|
for (let i = 0; i < daysInMonth; i++) {
|
|
177
179
|
const dailyCost = {
|
|
178
180
|
orgName,
|
|
179
|
-
date:
|
|
181
|
+
date: utcDate.clone().add(i, "d"),
|
|
180
182
|
charges: [
|
|
181
183
|
{
|
|
182
184
|
productName: charge.productName,
|
|
@@ -219,7 +221,7 @@ class DatadogClient extends InfraWalletClient.InfraWalletClient {
|
|
|
219
221
|
if (query.granularity === consts.GRANULARITY.DAILY) {
|
|
220
222
|
periodFormat = "YYYY-MM-DD";
|
|
221
223
|
}
|
|
222
|
-
const dateObj = moment__default.default(costByOrg.date);
|
|
224
|
+
const dateObj = moment__default.default.utc(costByOrg.date);
|
|
223
225
|
if (!dateObj.isValid()) {
|
|
224
226
|
filteredOutInvalidDate++;
|
|
225
227
|
return accumulator;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DatadogClient.cjs.js","sources":["../../src/cost-clients/DatadogClient.ts"],"sourcesContent":["import { CacheService, DatabaseService, LoggerService } from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { v2 as datadogApiV2, client as datadogClient } from '@datadog/datadog-api-client';\nimport { reduce } from 'lodash';\nimport moment from 'moment';\nimport { CLOUD_PROVIDER, GRANULARITY, PROVIDER_TYPE } from '../service/consts';\nimport { parseCost } from '../service/functions';\nimport { CostQuery, Report } from '../service/types';\nimport { InfraWalletClient } from './InfraWalletClient';\nimport { DatadogCostByOrgResponseSchema } from '../schemas/DatadogBilling';\nimport { ZodError } from 'zod';\n\nexport class DatadogClient extends InfraWalletClient {\n static create(config: Config, database: DatabaseService, cache: CacheService, logger: LoggerService) {\n return new DatadogClient(CLOUD_PROVIDER.DATADOG, config, database, cache, logger);\n }\n\n protected convertServiceName(serviceName: string): string {\n let convertedName = serviceName;\n\n // Datadog doesn't have this documented offically, raise a PR if any service is missed\n const aliases = new Map<string, string>([\n ['apm_host', 'APM Hosts'],\n ['apm_host_enterprise', 'APM Enterprise Hosts'],\n ['application_vulnerability_management_oss_host', 'Application Security - SCA Host'],\n ['application_security_host', 'ASM - Threat Management Hosts'],\n ['audit_trail', 'Audit Trail'],\n ['ci_pipeline', 'CI Visibility Committers'],\n ['ci_pipeline_indexed_spans', 'CI Visibility Spans'],\n ['cloud_cost_management', 'Cloud Cost Hosts'],\n ['cspm_container', 'Cloud Security Management Containers Pro'],\n ['cspm_host', 'Cloud Security Management Hosts Pro'],\n ['csm_host_pro', 'Cloud Security Management Hosts Pro'],\n ['cws_host', 'Cloud Workload Security Hosts'],\n ['infra_container', 'Containers'],\n ['infra_container_excl_agent', 'Containers'],\n ['timeseries', 'Custom Metrics'],\n ['error_tracking', 'Error Tracking'],\n ['incident_management', 'Incident Management'],\n ['logs_indexed_15day', 'Indexed Logs (15-day Retention)'],\n ['logs_indexed_180day', 'Indexed Logs (180-day Retention)'],\n ['logs_indexed_1day', 'Indexed Logs (1-day Retention)'],\n ['logs_indexed_30day', 'Indexed Logs (30-day Retention)'],\n ['logs_indexed_360day', 'Indexed Logs (360-day Retention)'],\n ['logs_indexed_3day', 'Indexed Logs (3-day Retention)'],\n ['logs_indexed_45day', 'Indexed Logs (45-day Retention)'],\n ['logs_indexed_60day', 'Indexed Logs (60-day Retention)'],\n ['logs_indexed_7day', 'Indexed Logs (7-day Retention)'],\n ['logs_indexed_90day', 'Indexed Logs (90-day Retention)'],\n ['apm_trace_search', 'Indexed Spans'],\n ['infra_host', 'Infra Hosts'],\n ['logs_ingested', 'Ingested Logs'],\n ['ingested_spans', 'Ingested Spans'],\n ['iot', 'IoT Devices'],\n ['npm_host', 'Network Hosts'],\n ['prof_container', 'Profiled Containers'],\n ['prof_host', 'Profiled Hosts'],\n ['rum_lite', 'RUM Sessions'],\n ['rum_replay', 'RUM with Session Replay Sessions'],\n ['siem_indexed', 'Security Analyzed and Indexed Logs'],\n ['sensitive_data_scanner', 'Sensitive Data Scanner'],\n ['serverless_apps', 'Serverless App Instances'],\n ['serverless_apm', 'Serverless Traced Invocations'],\n ['serverless_infra', 'Serverless Workload Functions'],\n ['siem', 'SIEM - Analyzed Logs'],\n ['synthetics_api_tests', 'Synthetics API Test Runs'],\n ['synthetics_browser_checks', 'Synthetics Browser Test Runs'],\n ['ci_testing', 'Test Visibility Committers'],\n ['ci_test_indexed_spans', 'Test Visibility Spans'],\n ]);\n\n if (aliases.has(convertedName)) {\n convertedName = aliases.get(convertedName) || convertedName;\n }\n\n return `${this.provider}/${convertedName}`;\n }\n\n protected async initCloudClient(integrationConfig: any): Promise<any> {\n const apiKey = integrationConfig.getString('apiKey');\n const applicationKey = integrationConfig.getString('applicationKey');\n const ddSite = integrationConfig.getString('ddSite');\n const configuration = datadogClient.createConfiguration({\n baseServer: new datadogClient.BaseServerConfiguration(ddSite, {}),\n authMethods: {\n apiKeyAuth: apiKey,\n appKeyAuth: applicationKey,\n },\n });\n const client = new datadogApiV2.UsageMeteringApi(configuration);\n return client;\n }\n\n protected async fetchCosts(integrationConfig: Config, client: any, query: CostQuery): Promise<any> {\n const costData: datadogApiV2.CostByOrg[] = [];\n const startTime = moment(parseInt(query.startTime, 10));\n const endTime = moment(parseInt(query.endTime, 10));\n const firstDayOfLastMonth = moment().subtract(1, 'M').startOf('M');\n\n // check if costs prior to 2 months ago are in query, if yes, use historical_cost API\n // https://docs.datadoghq.com/api/latest/usage-metering/#get-historical-cost-across-your-account\n if (startTime.isBefore(firstDayOfLastMonth)) {\n const historicalEndTime = moment.min(endTime, firstDayOfLastMonth.clone().subtract(1, 'd'));\n const maxMonthRange = 2;\n let chunkStart = startTime.clone();\n\n while (chunkStart.isBefore(historicalEndTime)) {\n const chunkEnd = moment.min(\n chunkStart.clone().add(maxMonthRange, 'months').subtract(1, 'day'),\n historicalEndTime.clone(),\n );\n\n const historicalCost: datadogApiV2.CostByOrgResponse = await client.getHistoricalCostByOrg({\n startMonth: chunkStart,\n endMonth: chunkEnd,\n view: 'sub-org',\n });\n\n try {\n DatadogCostByOrgResponseSchema.parse(historicalCost);\n this.logger.debug(`Datadog historical cost response validation passed`);\n } catch (error) {\n if (error instanceof ZodError) {\n this.logger.warn(`Datadog historical cost response validation failed: ${error.message}`);\n this.logger.debug(`Sample validation errors: ${JSON.stringify(error.errors.slice(0, 3))}`);\n } else {\n this.logger.warn(`Unexpected validation error: ${error.message}`);\n }\n }\n\n if (historicalCost.data) {\n costData.push(...historicalCost.data);\n }\n\n chunkStart = chunkEnd.clone().add(1, 'day').startOf('month');\n }\n }\n\n // check if current/last month costs are in query, if yes, use estimated_cost API\n // https://docs.datadoghq.com/api/latest/usage-metering/#get-estimated-cost-across-your-account\n if (endTime.isSameOrAfter(firstDayOfLastMonth)) {\n let estimatedCostStartTime = startTime;\n if (startTime.isBefore(firstDayOfLastMonth)) {\n estimatedCostStartTime = firstDayOfLastMonth;\n }\n\n const estimatedCost: datadogApiV2.CostByOrgResponse = await client.getEstimatedCostByOrg({\n startMonth: estimatedCostStartTime,\n endMonth: endTime,\n view: 'sub-org',\n });\n\n try {\n DatadogCostByOrgResponseSchema.parse(estimatedCost);\n this.logger.debug(`Datadog estimated cost response validation passed`);\n } catch (error) {\n if (error instanceof ZodError) {\n this.logger.warn(`Datadog estimated cost response validation failed: ${error.message}`);\n this.logger.debug(`Sample validation errors: ${JSON.stringify(error.errors.slice(0, 3))}`);\n } else {\n this.logger.warn(`Unexpected validation error: ${error.message}`);\n }\n }\n\n if (estimatedCost.data) {\n costData.push(...estimatedCost.data);\n }\n }\n\n const costs: any[] = [];\n\n if (query.granularity === GRANULARITY.MONTHLY) {\n costData.forEach(costByOrg => {\n const orgName = costByOrg.attributes?.orgName as string;\n if (!this.evaluateIntegrationFilters(orgName, integrationConfig)) {\n return;\n }\n\n costs.push({\n orgName: orgName,\n date: costByOrg.attributes?.date,\n // only keep cost breakdown\n charges: costByOrg.attributes?.charges?.filter(charge => charge.chargeType !== 'total'),\n });\n });\n } else {\n // Datadog doesn't provide daily costs based on usage, so we allocate monthly costs evenly by day\n costData.forEach(costByOrg => {\n const orgName = costByOrg.attributes?.orgName as string;\n if (!this.evaluateIntegrationFilters(orgName, integrationConfig)) {\n return;\n }\n\n const daysInMonth = moment(costByOrg.attributes?.date).daysInMonth();\n costByOrg.attributes?.charges?.forEach(charge => {\n if (charge.chargeType === 'total') {\n // only keep cost breakdown\n return;\n }\n\n for (let i = 0; i < daysInMonth; i++) {\n const dailyCost = {\n orgName: orgName,\n date: moment(costByOrg.attributes?.date).add(i, 'd'),\n charges: [\n {\n productName: charge.productName,\n cost: (charge.cost || 0) / daysInMonth,\n chargeType: charge.chargeType,\n },\n ],\n };\n costs.push(dailyCost);\n }\n });\n });\n }\n\n return costs;\n }\n\n protected async transformCostsData(subAccountConfig: Config, query: CostQuery, costResponse: any): Promise<Report[]> {\n const tags = subAccountConfig.getOptionalStringArray('tags');\n const tagKeyValues: { [key: string]: string } = {};\n tags?.forEach(tag => {\n const [k, v] = tag.split(':');\n tagKeyValues[k.trim()] = v.trim();\n });\n\n // Initialize tracking variables\n let processedRecords = 0;\n let filteredOutZeroAmount = 0;\n let filteredOutMissingFields = 0;\n let filteredOutInvalidDate = 0;\n const filteredOutTimeRange = 0;\n const uniqueKeys = new Set<string>();\n const totalRecords = costResponse?.length || 0;\n\n const transformedData = reduce(\n costResponse,\n (accumulator: { [key: string]: Report }, costByOrg) => {\n const account = costByOrg.orgName;\n const charges = costByOrg.charges;\n\n // Check for missing fields\n if (!account || !costByOrg.date) {\n filteredOutMissingFields++;\n return accumulator;\n }\n\n let periodFormat = 'YYYY-MM';\n if (query.granularity === GRANULARITY.DAILY) {\n periodFormat = 'YYYY-MM-DD';\n }\n\n const dateObj = moment(costByOrg.date);\n if (!dateObj.isValid()) {\n filteredOutInvalidDate++;\n return accumulator;\n }\n\n const period = dateObj.format(periodFormat);\n\n if (charges) {\n charges.forEach((charge: datadogApiV2.ChargebackBreakdown) => {\n const productName = charge.productName;\n const cost = charge.cost;\n\n // Check for missing fields\n if (!productName || cost === undefined || cost === null) {\n filteredOutMissingFields++;\n return;\n }\n\n const amount = parseCost(cost);\n\n // Check for zero amount\n if (amount === 0) {\n filteredOutZeroAmount++;\n return;\n }\n\n const keyName = `${account}->${productName} (${charge.chargeType})`;\n\n if (!accumulator[keyName]) {\n uniqueKeys.add(keyName);\n accumulator[keyName] = {\n id: keyName,\n account: `${this.provider}/${account}`,\n service: `${this.convertServiceName(productName as string)} (${charge.chargeType})`,\n category: 'Observability',\n provider: this.provider,\n providerType: PROVIDER_TYPE.INTEGRATION,\n reports: {},\n ...tagKeyValues,\n };\n }\n\n accumulator[keyName].reports[period] = amount;\n processedRecords++;\n });\n }\n\n return accumulator;\n },\n {},\n );\n\n this.logTransformationSummary({\n processed: processedRecords,\n uniqueReports: uniqueKeys.size,\n zeroAmount: filteredOutZeroAmount,\n missingFields: filteredOutMissingFields,\n invalidDate: filteredOutInvalidDate,\n timeRange: filteredOutTimeRange,\n totalRecords,\n });\n\n return Object.values(transformedData);\n }\n}\n"],"names":["InfraWalletClient","CLOUD_PROVIDER","datadogClient","datadogApiV2","moment","DatadogCostByOrgResponseSchema","ZodError","GRANULARITY","reduce","parseCost","PROVIDER_TYPE"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DatadogClient.cjs.js","sources":["../../src/cost-clients/DatadogClient.ts"],"sourcesContent":["import { CacheService, DatabaseService, LoggerService } from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { v2 as datadogApiV2, client as datadogClient } from '@datadog/datadog-api-client';\nimport { reduce } from 'lodash';\nimport moment from 'moment';\nimport { CLOUD_PROVIDER, GRANULARITY, PROVIDER_TYPE } from '../service/consts';\nimport { parseCost } from '../service/functions';\nimport { CostQuery, Report } from '../service/types';\nimport { InfraWalletClient } from './InfraWalletClient';\nimport { DatadogCostByOrgResponseSchema } from '../schemas/DatadogBilling';\nimport { ZodError } from 'zod';\n\nexport class DatadogClient extends InfraWalletClient {\n static create(config: Config, database: DatabaseService, cache: CacheService, logger: LoggerService) {\n return new DatadogClient(CLOUD_PROVIDER.DATADOG, config, database, cache, logger);\n }\n\n protected convertServiceName(serviceName: string): string {\n let convertedName = serviceName;\n\n // Datadog doesn't have this documented offically, raise a PR if any service is missed\n const aliases = new Map<string, string>([\n ['apm_host', 'APM Hosts'],\n ['apm_host_enterprise', 'APM Enterprise Hosts'],\n ['application_vulnerability_management_oss_host', 'Application Security - SCA Host'],\n ['application_security_host', 'ASM - Threat Management Hosts'],\n ['audit_trail', 'Audit Trail'],\n ['ci_pipeline', 'CI Visibility Committers'],\n ['ci_pipeline_indexed_spans', 'CI Visibility Spans'],\n ['cloud_cost_management', 'Cloud Cost Hosts'],\n ['cspm_container', 'Cloud Security Management Containers Pro'],\n ['cspm_host', 'Cloud Security Management Hosts Pro'],\n ['csm_host_pro', 'Cloud Security Management Hosts Pro'],\n ['cws_host', 'Cloud Workload Security Hosts'],\n ['infra_container', 'Containers'],\n ['infra_container_excl_agent', 'Containers'],\n ['timeseries', 'Custom Metrics'],\n ['error_tracking', 'Error Tracking'],\n ['incident_management', 'Incident Management'],\n ['logs_indexed_15day', 'Indexed Logs (15-day Retention)'],\n ['logs_indexed_180day', 'Indexed Logs (180-day Retention)'],\n ['logs_indexed_1day', 'Indexed Logs (1-day Retention)'],\n ['logs_indexed_30day', 'Indexed Logs (30-day Retention)'],\n ['logs_indexed_360day', 'Indexed Logs (360-day Retention)'],\n ['logs_indexed_3day', 'Indexed Logs (3-day Retention)'],\n ['logs_indexed_45day', 'Indexed Logs (45-day Retention)'],\n ['logs_indexed_60day', 'Indexed Logs (60-day Retention)'],\n ['logs_indexed_7day', 'Indexed Logs (7-day Retention)'],\n ['logs_indexed_90day', 'Indexed Logs (90-day Retention)'],\n ['apm_trace_search', 'Indexed Spans'],\n ['infra_host', 'Infra Hosts'],\n ['logs_ingested', 'Ingested Logs'],\n ['ingested_spans', 'Ingested Spans'],\n ['iot', 'IoT Devices'],\n ['npm_host', 'Network Hosts'],\n ['prof_container', 'Profiled Containers'],\n ['prof_host', 'Profiled Hosts'],\n ['rum_lite', 'RUM Sessions'],\n ['rum_replay', 'RUM with Session Replay Sessions'],\n ['siem_indexed', 'Security Analyzed and Indexed Logs'],\n ['sensitive_data_scanner', 'Sensitive Data Scanner'],\n ['serverless_apps', 'Serverless App Instances'],\n ['serverless_apm', 'Serverless Traced Invocations'],\n ['serverless_infra', 'Serverless Workload Functions'],\n ['siem', 'SIEM - Analyzed Logs'],\n ['synthetics_api_tests', 'Synthetics API Test Runs'],\n ['synthetics_browser_checks', 'Synthetics Browser Test Runs'],\n ['ci_testing', 'Test Visibility Committers'],\n ['ci_test_indexed_spans', 'Test Visibility Spans'],\n ]);\n\n if (aliases.has(convertedName)) {\n convertedName = aliases.get(convertedName) || convertedName;\n }\n\n return `${this.provider}/${convertedName}`;\n }\n\n protected async initCloudClient(integrationConfig: any): Promise<any> {\n const apiKey = integrationConfig.getString('apiKey');\n const applicationKey = integrationConfig.getString('applicationKey');\n const ddSite = integrationConfig.getString('ddSite');\n const configuration = datadogClient.createConfiguration({\n baseServer: new datadogClient.BaseServerConfiguration(ddSite, {}),\n authMethods: {\n apiKeyAuth: apiKey,\n appKeyAuth: applicationKey,\n },\n });\n const client = new datadogApiV2.UsageMeteringApi(configuration);\n return client;\n }\n\n protected async fetchCosts(integrationConfig: Config, client: any, query: CostQuery): Promise<any> {\n const costData: datadogApiV2.CostByOrg[] = [];\n // Strict UTC to prevent month boundary drift\n const startTime = moment.utc(parseInt(query.startTime, 10)).startOf('month');\n const endTime = moment.utc(parseInt(query.endTime, 10)).startOf('month');\n const historicalCutoff = moment.utc().startOf('month').subtract(2, 'months');\n\n // check if costs prior to 2 months ago are in query, if yes, use historical_cost API\n // https://docs.datadoghq.com/api/latest/usage-metering/#get-historical-cost-across-your-account\n if (startTime.isBefore(historicalCutoff)) {\n const historicalEndTime = moment.min(endTime, historicalCutoff.clone().subtract(1, 'month'));\n // Datadog API quirk: To get data FOR a specific end month, the API request must include the NEXT month.\n const maxMonthRange = 3;\n let chunkStart = startTime.clone();\n\n while (chunkStart.isSameOrBefore(historicalEndTime)) {\n let chunkEnd = chunkStart.clone().add(maxMonthRange - 1, 'months');\n if (chunkEnd.isAfter(historicalEndTime)) {\n chunkEnd = historicalEndTime.clone();\n }\n\n const apiEndMonth = chunkEnd.clone().add(1, 'month');\n\n const historicalCost: datadogApiV2.CostByOrgResponse = await client.getHistoricalCostByOrg({\n startMonth: chunkStart,\n endMonth: apiEndMonth,\n view: 'sub-org',\n });\n\n try {\n DatadogCostByOrgResponseSchema.parse(historicalCost);\n this.logger.debug(`Datadog historical cost response validation passed`);\n } catch (error) {\n if (error instanceof ZodError) {\n this.logger.warn(`Datadog historical cost response validation failed: ${error.message}`);\n this.logger.debug(`Sample validation errors: ${JSON.stringify(error.errors.slice(0, 3))}`);\n } else {\n this.logger.warn(`Unexpected validation error: ${error.message}`);\n }\n }\n\n if (historicalCost.data) {\n costData.push(...historicalCost.data);\n }\n\n chunkStart = chunkStart.clone().add(maxMonthRange, 'months');\n }\n }\n\n // check if current/last month costs are in query, if yes, use estimated_cost API\n // https://docs.datadoghq.com/api/latest/usage-metering/#get-estimated-cost-across-your-account\n if (endTime.isSameOrAfter(historicalCutoff)) {\n const estimatedStartTime = moment.max(startTime, historicalCutoff);\n const apiEndTime = endTime.clone().add(1, 'month');\n\n const estimatedCost: datadogApiV2.CostByOrgResponse = await client.getEstimatedCostByOrg({\n startMonth: estimatedStartTime,\n endMonth: apiEndTime,\n view: 'sub-org',\n });\n\n try {\n DatadogCostByOrgResponseSchema.parse(estimatedCost);\n this.logger.debug(`Datadog estimated cost response validation passed`);\n } catch (error) {\n if (error instanceof ZodError) {\n this.logger.warn(`Datadog estimated cost response validation failed: ${error.message}`);\n this.logger.debug(`Sample validation errors: ${JSON.stringify(error.errors.slice(0, 3))}`);\n } else {\n this.logger.warn(`Unexpected validation error: ${error.message}`);\n }\n }\n\n if (estimatedCost.data) {\n costData.push(...estimatedCost.data);\n }\n }\n\n const costs: any[] = [];\n\n if (query.granularity === GRANULARITY.MONTHLY) {\n costData.forEach(costByOrg => {\n const orgName = costByOrg.attributes?.orgName as string;\n const date = costByOrg.attributes?.date;\n\n if (!this.evaluateIntegrationFilters(orgName, integrationConfig) || !date) {\n return;\n }\n\n costs.push({\n orgName: orgName,\n date: date,\n // only keep cost breakdown\n charges: costByOrg.attributes?.charges?.filter(charge => charge.chargeType !== 'total'),\n });\n });\n } else {\n // Datadog doesn't provide daily costs based on usage, so we allocate monthly costs evenly by day\n costData.forEach(costByOrg => {\n const orgName = costByOrg.attributes?.orgName as string;\n const date = costByOrg.attributes?.date;\n\n if (!this.evaluateIntegrationFilters(orgName, integrationConfig) || !date) {\n return;\n }\n\n const utcDate = moment.utc(date);\n const daysInMonth = utcDate.daysInMonth();\n\n costByOrg.attributes?.charges?.forEach(charge => {\n if (charge.chargeType === 'total') {\n // only keep cost breakdown\n return;\n }\n\n for (let i = 0; i < daysInMonth; i++) {\n const dailyCost = {\n orgName: orgName,\n date: utcDate.clone().add(i, 'd'),\n charges: [\n {\n productName: charge.productName,\n cost: (charge.cost || 0) / daysInMonth,\n chargeType: charge.chargeType,\n },\n ],\n };\n costs.push(dailyCost);\n }\n });\n });\n }\n\n return costs;\n }\n\n protected async transformCostsData(subAccountConfig: Config, query: CostQuery, costResponse: any): Promise<Report[]> {\n const tags = subAccountConfig.getOptionalStringArray('tags');\n const tagKeyValues: { [key: string]: string } = {};\n tags?.forEach(tag => {\n const [k, v] = tag.split(':');\n tagKeyValues[k.trim()] = v.trim();\n });\n\n // Initialize tracking variables\n let processedRecords = 0;\n let filteredOutZeroAmount = 0;\n let filteredOutMissingFields = 0;\n let filteredOutInvalidDate = 0;\n const filteredOutTimeRange = 0;\n const uniqueKeys = new Set<string>();\n const totalRecords = costResponse?.length || 0;\n\n const transformedData = reduce(\n costResponse,\n (accumulator: { [key: string]: Report }, costByOrg) => {\n const account = costByOrg.orgName;\n const charges = costByOrg.charges;\n\n // Check for missing fields\n if (!account || !costByOrg.date) {\n filteredOutMissingFields++;\n return accumulator;\n }\n\n let periodFormat = 'YYYY-MM';\n if (query.granularity === GRANULARITY.DAILY) {\n periodFormat = 'YYYY-MM-DD';\n }\n\n const dateObj = moment.utc(costByOrg.date);\n if (!dateObj.isValid()) {\n filteredOutInvalidDate++;\n return accumulator;\n }\n\n const period = dateObj.format(periodFormat);\n\n if (charges) {\n charges.forEach((charge: datadogApiV2.ChargebackBreakdown) => {\n const productName = charge.productName;\n const cost = charge.cost;\n\n // Check for missing fields\n if (!productName || cost === undefined || cost === null) {\n filteredOutMissingFields++;\n return;\n }\n\n const amount = parseCost(cost);\n\n // Check for zero amount\n if (amount === 0) {\n filteredOutZeroAmount++;\n return;\n }\n\n const keyName = `${account}->${productName} (${charge.chargeType})`;\n\n if (!accumulator[keyName]) {\n uniqueKeys.add(keyName);\n accumulator[keyName] = {\n id: keyName,\n account: `${this.provider}/${account}`,\n service: `${this.convertServiceName(productName as string)} (${charge.chargeType})`,\n category: 'Observability',\n provider: this.provider,\n providerType: PROVIDER_TYPE.INTEGRATION,\n reports: {},\n ...tagKeyValues,\n };\n }\n\n accumulator[keyName].reports[period] = amount;\n processedRecords++;\n });\n }\n\n return accumulator;\n },\n {},\n );\n\n this.logTransformationSummary({\n processed: processedRecords,\n uniqueReports: uniqueKeys.size,\n zeroAmount: filteredOutZeroAmount,\n missingFields: filteredOutMissingFields,\n invalidDate: filteredOutInvalidDate,\n timeRange: filteredOutTimeRange,\n totalRecords,\n });\n\n return Object.values(transformedData);\n }\n}\n"],"names":["InfraWalletClient","CLOUD_PROVIDER","datadogClient","datadogApiV2","moment","DatadogCostByOrgResponseSchema","ZodError","GRANULARITY","reduce","parseCost","PROVIDER_TYPE"],"mappings":"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"}
|