Convert Cost Management data to FOCUS
This document provides guidance for converting Cost Management actual and amortized datasets to the FinOps Open Cost and Usage Specification (FOCUS). To learn more about FOCUS, refer to the FOCUS overview.
How to convert Cost Management data to FOCUS
In order to convert cost and usage data to FOCUS, you will need both the actual and amortized cost datasets:
- Keep all rows from the amortized cost data.
- Filter the actual cost data to only include rows where ChargeType == "Purchase" or "Refund" and PricingModel == "Reservation" or "SavingsPlan".
Apply the following logic to all of the rows:
FOCUS column | Cost Management column | Transform |
---|---|---|
BilledCost | CostInBillingCurrency | If ChargeType == "Usage" and PricingModel == "Reservation" or "SavingsPlan", then 0 ; otherwise, use CostInBillingCurrency |
BillingAccountId | • Enterprise Agreement: BillingAccountId • Microsoft Customer Agreement: BillingProfileId |
None |
BillingAccountName | • Enterprise Agreement: BillingAccountName • Microsoft Customer Agreement: BillingProfileName |
None |
BillingCurrency | • Enterprise Agreement: BillingCurrencyCode • Microsoft Customer Agreement: BillingCurrency |
None |
BillingPeriodEnd | BillingPeriodEndDate | Add one day for the exclusive end date |
BillingPeriodStart | BillingPeriodStartDate | None |
ChargeCategory | ChargeType | If Usage , Purchase , Credit , or Tax , same value; if UnusedReservation or UnusedSavingsPlan , then Usage ; if Refund , Purchase ; otherwise, Adjustment |
ChargeClass | ChargeType | If Refund , then use Correction |
ChargeDescription | ProductName | None |
ChargeFrequency | Frequency | If OneTime , One-Time ; if Recurring , Recurring ; if UsageBased , Usage-Based ; otherwise, Other |
ChargePeriodEnd | Date | Add one day for the exclusive end date |
ChargePeriodStart | Date | None |
CommitmentDiscountCategory | BenefitId | If BenefitId contains /microsoft.capacity/ (case-insensitive), Usage ; if it contains /microsoft.billingbenefits/ , use Spend ; otherwise, null |
CommitmentDiscountId | BenefitId | None |
CommitmentDiscountName | BenefitName | None |
CommitmentDiscountStatus | ChargeType | If UnusedReservation or UnusedSavingsPlan , then Unused ; else if PricingModel == Reservation or SavingsPlan , then Used ; otherwise, null |
CommitmentDiscountType | BenefitId | If BenefitId contains /microsoft.capacity/ (case-insensitive), Reservation ; if it contains /microsoft.billingbenefits/ , Savings Plan ; otherwise, null |
ConsumedQuantity | Quantity | If ChargeType == Usage , then Quantity; otherwise, null |
ConsumedUnit | UnitOfMeasure | If ChargeType == Usage , then map using Pricing units data file ; otherwise, null |
ContractedCost | UnitPrice * Quantity / focus:x_PricingBlockSize | Note that x_PricingBlockSize requires a mapping. See column notes for details. |
ContractedUnitPrice | UnitPrice | None |
EffectiveCost | CostInBillingCurrency | If ChargeType == "Purchase" or "Refund" and PricingModel == "Reservation" or "SavingsPlan", then 0 ; otherwise, use CostInBillingCurrency |
InvoiceIssuerName | PartnerName | If PartnerName is empty, use Microsoft |
ListCost | • Enterprise Agreement: Not available • Microsoft Customer Agreement: PaygCostInBillingCurrency |
None |
ListUnitPrice | • Enterprise Agreement: PayGPrice • Microsoft Customer Agreement: PayGPrice * ExchangeRate |
None |
PricingCategory | PricingModel | If OnDemand , then Standard ; if Spot , then Dynamic ; if Reservation or Savings Plan , then Committed ; otherwise, null |
PricingQuantity | Quantity / focus:x_PricingBlockSize | Note that x_PricingBlockSize requires a mapping. See column notes for details. |
PricingUnit | DistinctUnits (lookup) | Map UnitOfMeasure to DistinctUnits using Pricing units data file |
ProviderName | Microsoft |
None |
PublisherName | PublisherName | None |
RegionId | focus:RegionName | Lowercase and remove spaces |
RegionName | ResourceLocation | Map ResourceLocation (OriginalValue) to RegionName using Regions data file2 |
ResourceId | ResourceId | None |
ResourceName | EA: ResourceName MCA: last(split(ResourceId, "/")) |
Azure resource names include multiple levels (e.g., "SqlServerName/SqlDbName"), which requires more processing. This is a simplified approach to only use the last, most-specific segment. |
ResourceType | SingularDisplayName (lookup) | Map ResourceType to SingularDisplayName using Resource types data file |
ServiceCategory | ServiceCategory (lookup) | Map ConsumedService and ResourceType to ServiceCategory using Services data file |
ServiceName | ServiceName (lookup) | Map ConsumedService and ResourceType to ServiceName using Services data file |
SkuId | • Enterprise Agreement: Not available • Microsoft Customer Agreement: ProductId |
None |
SkuPriceId | Not available | None |
SubAccountId | SubscriptionId | None |
SubAccountName | SubscriptionName | None |
Tags | Tags | Wrap in { and } if needed |
¹ Quantity in Cost Management is the consumed (usage) quantity.
² While RegionName is a direct mapping of ResourceLocation, Cost Management and FinOps toolkit reports do additional data cleansing to ensure consistency in values based on the Regions data file.
Feedback about FOCUS columns
If you have feedback about our mappings or about our full FOCUS support plans, start a thread in FinOps toolkit discussions. If you believe you have a bug, create an issue.
If you have feedback about FOCUS, create an issue in the FOCUS repository. We also encourage you to consider contributing to the FOCUS project. The project is looking for more practitioners to help bring their experience to help guide efforts and make it the most useful spec it can be. To learn more about FOCUS or to contribute to the project, visit focus.finops.org.
Related content
Related resources:
Related products:
Related solutions: