Update import statements for ProductType in multiple files

This commit is contained in:
Simon Larsen 2024-04-04 20:56:03 +01:00
parent 1fbdc19645
commit abcde37960
No known key found for this signature in database
GPG Key ID: AB45983AA9C81CDE
11 changed files with 60 additions and 102 deletions

View File

@ -0,0 +1,8 @@
enum ProductType {
Logs = 'Logs',
Traces = 'Traces',
Metrics = 'Metrics',
ActiveMonitoring = 'ActiveMonitoring',
}
export default ProductType;

View File

@ -1,5 +1,4 @@
import SubscriptionPlan from 'Common/Types/Billing/SubscriptionPlan'; import SubscriptionPlan from 'Common/Types/Billing/SubscriptionPlan';
import MeteredPlan from 'Common/Types/Billing/MeteredPlan';
import OneUptimeDate from 'Common/Types/Date'; import OneUptimeDate from 'Common/Types/Date';
import APIException from 'Common/Types/Exception/ApiException'; import APIException from 'Common/Types/Exception/ApiException';
import BadDataException from 'Common/Types/Exception/BadDataException'; import BadDataException from 'Common/Types/Exception/BadDataException';
@ -15,7 +14,7 @@ import BaseService from './BaseService';
import Email from 'Common/Types/Email'; import Email from 'Common/Types/Email';
import Dictionary from 'Common/Types/Dictionary'; import Dictionary from 'Common/Types/Dictionary';
import Errors from '../Utils/Errors'; import Errors from '../Utils/Errors';
import { ProductType } from 'Model/Models/UsageBilling'; import ProductType from 'Common/Types/MeteredPlan/ProductType';
export type SubscriptionItem = Stripe.SubscriptionItem; export type SubscriptionItem = Stripe.SubscriptionItem;
@ -876,59 +875,6 @@ export class BillingService extends BaseService {
'Plan with productType ' + productType + ' not found' 'Plan with productType ' + productType + ' not found'
); );
} }
public async getMeteredPlan(data: {
productType: ProductType;
projectId: ObjectID;
}): Promise<MeteredPlan> {
if (data.productType === ProductType.ActiveMonitoring) {
return new MeteredPlan({
priceId: this.getMeteredPlanPriceId(data.productType),
pricePerUnitInUSD: 1,
unitName: 'Active Monitor',
});
}
// const dataRetentionDays: number =
// await ProjectService.getTelemetryDataRetentionInDays(
// data.projectId
// );
const dataRetentionDays: number = 15;
const dataRetentionMultiplier: number = 0.1; // if the retention is 10 days for example, the cost per GB will be 0.01$ per GB per day (0.10 * dataRetentionDays * dataRetentionMultiplier).
if (data.productType === ProductType.Logs) {
return new MeteredPlan({
priceId: this.getMeteredPlanPriceId(data.productType),
pricePerUnitInUSD:
0.1 * dataRetentionDays * dataRetentionMultiplier,
unitName: `GB (${dataRetentionDays} days data retention)`,
});
}
if (data.productType === ProductType.Traces) {
return new MeteredPlan({
priceId: this.getMeteredPlanPriceId(data.productType),
pricePerUnitInUSD:
0.1 * dataRetentionDays * dataRetentionMultiplier,
unitName: `GB (${dataRetentionDays} days data retention)`,
});
}
if (data.productType === ProductType.Metrics) {
return new MeteredPlan({
priceId: this.getMeteredPlanPriceId(data.productType),
pricePerUnitInUSD:
0.1 * dataRetentionDays * dataRetentionMultiplier,
unitName: `GB (${dataRetentionDays} days data retention)`,
});
}
throw new BadDataException(
'Plan with name ' + data.productType + ' not found'
);
}
} }
export default new BillingService(); export default new BillingService();

View File

@ -1,5 +1,6 @@
import PostgresDatabase from '../Infrastructure/PostgresDatabase'; import PostgresDatabase from '../Infrastructure/PostgresDatabase';
import Model, { ProductType } from 'Model/Models/TelemetryUsageBilling'; import Model from 'Model/Models/TelemetryUsageBilling';
import ProductType from 'Common/Types/MeteredPlan/ProductType';
import DatabaseService from './DatabaseService'; import DatabaseService from './DatabaseService';
import ObjectID from 'Common/Types/ObjectID'; import ObjectID from 'Common/Types/ObjectID';
import { LIMIT_PER_PROJECT } from 'Common/Types/Database/LimitMax'; import { LIMIT_PER_PROJECT } from 'Common/Types/Database/LimitMax';
@ -7,10 +8,9 @@ import OneUptimeDate from 'Common/Types/Date';
import QueryHelper from '../Types/Database/QueryHelper'; import QueryHelper from '../Types/Database/QueryHelper';
import SortOrder from 'Common/Types/BaseDatabase/SortOrder'; import SortOrder from 'Common/Types/BaseDatabase/SortOrder';
import { MeteredPlanUtil } from '../Types/Billing/MeteredPlan/AllMeteredPlans'; import { MeteredPlanUtil } from '../Types/Billing/MeteredPlan/AllMeteredPlans';
import MeteredPlan from 'Common/Types/Billing/MeteredPlan';
import ServerMeteredPlan from '../Types/Billing/MeteredPlan/ServerMeteredPlan';
import Decimal from 'Common/Types/Decimal'; import Decimal from 'Common/Types/Decimal';
import TelemetryMeteredPlan from '../Types/Billing/MeteredPlan/TelemetryMeteredPlan'; import TelemetryMeteredPlan from '../Types/Billing/MeteredPlan/TelemetryMeteredPlan';
import BadDataException from 'Common/Types/Exception/BadDataException';
export class Service extends DatabaseService<Model> { export class Service extends DatabaseService<Model> {
public constructor(postgresDatabase?: PostgresDatabase) { public constructor(postgresDatabase?: PostgresDatabase) {
@ -53,8 +53,13 @@ export class Service extends DatabaseService<Model> {
dataIngestedInGB: number; dataIngestedInGB: number;
retentionInDays: number; retentionInDays: number;
}): Promise<void> { }): Promise<void> {
if(data.productType !== ProductType.Traces && data.productType !== ProductType.Metrics && data.productType !== ProductType.Logs) {
throw new BadDataException("This product type is not a telemetry product type.");
}
const serverMeteredPlan: TelemetryMeteredPlan = const serverMeteredPlan: TelemetryMeteredPlan =
MeteredPlanUtil.getTelemetryMeteredPlanByProductType(data.productType); MeteredPlanUtil.getMeteredPlanByProductType(data.productType) as TelemetryMeteredPlan;
const totalCostOfThisOperationInUSD: number = const totalCostOfThisOperationInUSD: number =
serverMeteredPlan.getTotalCostInUSD( serverMeteredPlan.getTotalCostInUSD(
@ -95,8 +100,8 @@ export class Service extends DatabaseService<Model> {
await this.updateOneById({ await this.updateOneById({
id: usageBilling.id, id: usageBilling.id,
data: { data: {
usageCount: new Decimal( dataIngestedInGB: new Decimal(
(usageBilling.usageCount?.value || 0) + data.usageCount (usageBilling.dataIngestedInGB?.value || 0) + data.dataIngestedInGB
), ),
totalCostInUSD: new Decimal( totalCostInUSD: new Decimal(
(usageBilling.totalCostInUSD?.value || 0) + (usageBilling.totalCostInUSD?.value || 0) +
@ -111,12 +116,16 @@ export class Service extends DatabaseService<Model> {
const usageBilling: Model = new Model(); const usageBilling: Model = new Model();
usageBilling.projectId = data.projectId; usageBilling.projectId = data.projectId;
usageBilling.productType = data.productType; usageBilling.productType = data.productType;
usageBilling.usageCount = new Decimal(data.usageCount); usageBilling.dataIngestedInGB = new Decimal(data.dataIngestedInGB);
usageBilling.telemetryServiceId = data.telemetryServiceId;
usageBilling.retainTelemetryDataForDays = data.retentionInDays;
usageBilling.isReportedToBillingProvider = false; usageBilling.isReportedToBillingProvider = false;
usageBilling.createdAt = OneUptimeDate.getCurrentDate(); usageBilling.createdAt = OneUptimeDate.getCurrentDate();
usageBilling.day = OneUptimeDate.getDateString( usageBilling.day = OneUptimeDate.getDateString(
OneUptimeDate.getCurrentDate() OneUptimeDate.getCurrentDate()
); );
usageBilling.totalCostInUSD = new Decimal( usageBilling.totalCostInUSD = new Decimal(
totalCostOfThisOperationInUSD totalCostOfThisOperationInUSD
); );

View File

@ -14,7 +14,7 @@ import {
ChangePlan, ChangePlan,
CouponData, CouponData,
} from '../../TestingUtils/Services/Types'; } from '../../TestingUtils/Services/Types';
import { ProductType } from 'Model/Models/UsageBilling'; import ProductType from 'Common/Types/MeteredPlan/ProductType';
/// @dev consider modifyfing the EnvirontmentConfig to use functions instead of constants so that we can mock them /// @dev consider modifyfing the EnvirontmentConfig to use functions instead of constants so that we can mock them

View File

@ -7,7 +7,7 @@ import PositiveNumber from 'Common/Types/PositiveNumber';
import ProjectService from '../../../Services/ProjectService'; import ProjectService from '../../../Services/ProjectService';
import BillingService from '../../../Services/BillingService'; import BillingService from '../../../Services/BillingService';
import Project from 'Model/Models/Project'; import Project from 'Model/Models/Project';
import { ProductType } from 'Model/Models/UsageBilling'; import ProductType from 'Common/Types/MeteredPlan/ProductType';
export default class ActiveMonitoringMeteredPlan extends ServerMeteredPlan { export default class ActiveMonitoringMeteredPlan extends ServerMeteredPlan {
public override getProductType(): ProductType { public override getProductType(): ProductType {

View File

@ -1,27 +1,27 @@
import ActiveMonitoringMeteredPlanType from './ActiveMonitoringMeteredPlan'; import ActiveMonitoringMeteredPlanType from './ActiveMonitoringMeteredPlan';
import ServerMeteredPlan from './ServerMeteredPlan'; import ServerMeteredPlan from './ServerMeteredPlan';
import TelemetryMeteredPlanType from './TelemetryMeteredPlan'; import TelemetryMeteredPlanType from './TelemetryMeteredPlan';
import { ProductType as TelemetryProductType } from 'Model/Models/TelemetryUsageBilling';
import BadDataException from 'Common/Types/Exception/BadDataException'; import BadDataException from 'Common/Types/Exception/BadDataException';
import ProductType from 'Common/Types/MeteredPlan/ProductType';
export const ActiveMonitoringMeteredPlan: ActiveMonitoringMeteredPlanType = export const ActiveMonitoringMeteredPlan: ActiveMonitoringMeteredPlanType =
new ActiveMonitoringMeteredPlanType(); new ActiveMonitoringMeteredPlanType();
export const LogDataIngestMeteredPlan: TelemetryMeteredPlanType = export const LogDataIngestMeteredPlan: TelemetryMeteredPlanType =
new TelemetryMeteredPlanType({ new TelemetryMeteredPlanType({
productType: TelemetryProductType.Logs, productType: ProductType.Logs,
unitCostInUSD: 0.10 / 15, // 0.10 per 15 days per GB unitCostInUSD: 0.10 / 15, // 0.10 per 15 days per GB
}); });
export const MetricsDataIngestMeteredPlan: TelemetryMeteredPlanType = export const MetricsDataIngestMeteredPlan: TelemetryMeteredPlanType =
new TelemetryMeteredPlanType({ new TelemetryMeteredPlanType({
productType: TelemetryProductType.Metrics, productType: ProductType.Metrics,
unitCostInUSD: 0.10 / 15, // 0.10 per 15 days per GB unitCostInUSD: 0.10 / 15, // 0.10 per 15 days per GB
}); });
export const TracesDataIngestMetredPlan: TelemetryMeteredPlanType = export const TracesDataIngestMetredPlan: TelemetryMeteredPlanType =
new TelemetryMeteredPlanType({ new TelemetryMeteredPlanType({
productType: TelemetryProductType.Traces, productType: ProductType.Traces,
unitCostInUSD: 0.10 / 15, // 0.10 per 15 days per GB unitCostInUSD: 0.10 / 15, // 0.10 per 15 days per GB
}); });
@ -33,16 +33,19 @@ const AllMeteredPlans: Array<ServerMeteredPlan> = [
]; ];
export class MeteredPlanUtil { export class MeteredPlanUtil {
public static getTelemetryMeteredPlanByProductType( public static getMeteredPlanByProductType(
productType: TelemetryProductType productType: ProductType
): TelemetryMeteredPlanType { ): ServerMeteredPlan {
if (productType === TelemetryProductType.Logs) { if (productType === ProductType.Logs) {
return LogDataIngestMeteredPlan; return LogDataIngestMeteredPlan;
} else if (productType === TelemetryProductType.Metrics) { } else if (productType === ProductType.Metrics) {
return MetricsDataIngestMeteredPlan; return MetricsDataIngestMeteredPlan;
} else if (productType === TelemetryProductType.Traces) { } else if (productType === ProductType.Traces) {
return TracesDataIngestMetredPlan; return TracesDataIngestMetredPlan;
} else if (productType === ProductType.ActiveMonitoring) {
return ActiveMonitoringMeteredPlan;
} }
throw new BadDataException(`Unknown product type ${productType}`); throw new BadDataException(`Unknown product type ${productType}`);
} }
} }

View File

@ -2,21 +2,13 @@ import NotImplementedException from 'Common/Types/Exception/NotImplementedExcept
import ObjectID from 'Common/Types/ObjectID'; import ObjectID from 'Common/Types/ObjectID';
import BillingService from '../../../Services/BillingService'; import BillingService from '../../../Services/BillingService';
import MeteredPlan from 'Common/Types/Billing/MeteredPlan'; import MeteredPlan from 'Common/Types/Billing/MeteredPlan';
import { ProductType } from 'Model/Models/TelemetryUsageBilling'; import ProductType from 'Common/Types/MeteredPlan/ProductType';
export default class ServerMeteredPlan { export default class ServerMeteredPlan {
public getProductType(): ProductType { public getProductType(): ProductType {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public async getCostByProjectId(
projectId: ObjectID,
quantity: number
): Promise<number> {
const meteredPlan: MeteredPlan = await this.getMeteredPlan(projectId);
return this.getCostByMeteredPlan(meteredPlan, quantity);
}
public getCostByMeteredPlan( public getCostByMeteredPlan(
meteredPlan: MeteredPlan, meteredPlan: MeteredPlan,
quantity: number quantity: number
@ -24,13 +16,6 @@ export default class ServerMeteredPlan {
return meteredPlan.getPricePerUnit() * quantity; return meteredPlan.getPricePerUnit() * quantity;
} }
public async getMeteredPlan(projectId: ObjectID): Promise<MeteredPlan> {
return await BillingService.getMeteredPlan({
projectId: projectId,
productType: this.getProductType(),
});
}
public async reportQuantityToBillingProvider( public async reportQuantityToBillingProvider(
_projectId: ObjectID, _projectId: ObjectID,
_options: { _options: {

View File

@ -3,9 +3,11 @@ import ObjectID from 'Common/Types/ObjectID';
import ProjectService from '../../../Services/ProjectService'; import ProjectService from '../../../Services/ProjectService';
import BillingService from '../../../Services/BillingService'; import BillingService from '../../../Services/BillingService';
import Project from 'Model/Models/Project'; import Project from 'Model/Models/Project';
import TelemetryUsageBilling, { ProductType } from 'Model/Models/TelemetryUsageBilling'; import TelemetryUsageBilling from 'Model/Models/TelemetryUsageBilling';
import TelemetryUsageBillingService from '../../../Services/TelemetryUsageBillingService'; import TelemetryUsageBillingService from '../../../Services/TelemetryUsageBillingService';
import OneUptimeDate from 'Common/Types/Date'; import OneUptimeDate from 'Common/Types/Date';
import ProductType from 'Common/Types/MeteredPlan/ProductType';
export default class TelemetryMeteredPlan extends ServerMeteredPlan { export default class TelemetryMeteredPlan extends ServerMeteredPlan {
private _productType!: ProductType; private _productType!: ProductType;

View File

@ -1,4 +1,4 @@
import { ProductType } from 'Model/Models/UsageBilling'; import ProductType from 'Common/Types/MeteredPlan/ProductType';
import Express, { import Express, {
ExpressRequest, ExpressRequest,
ExpressResponse, ExpressResponse,

View File

@ -8,15 +8,17 @@ import BadRequestException from 'Common/Types/Exception/BadRequestException';
import GlobalCache from 'CommonServer/Infrastructure/GlobalCache'; import GlobalCache from 'CommonServer/Infrastructure/GlobalCache';
import DiskSize from 'Common/Types/DiskSize'; import DiskSize from 'Common/Types/DiskSize';
import ObjectID from 'Common/Types/ObjectID'; import ObjectID from 'Common/Types/ObjectID';
import UsageBillingService from 'CommonServer/Services/UsageBillingService'; import TelemetryUsageBillingService from 'CommonServer/Services/TelemetryUsageBillingService';
import { ProductType } from 'Model/Models/UsageBilling'; import ProductType from 'Common/Types/MeteredPlan/ProductType';
import TelemetryServiceService from 'CommonServer/Services/TelemetryServiceService'; import TelemetryServiceService from 'CommonServer/Services/TelemetryServiceService';
import TelemetryService from 'Model/Models/TelemetryService'; import TelemetryService from 'Model/Models/TelemetryService';
import logger from 'CommonServer/Utils/Logger'; import logger from 'CommonServer/Utils/Logger';
import { DEFAULT_RETENTION_IN_DAYS } from 'Model/Models/TelemetryUsageBilling';
export interface TelemetryRequest extends ExpressRequest { export interface TelemetryRequest extends ExpressRequest {
serviceId: ObjectID; // Service ID serviceId: ObjectID; // Service ID
projectId: ObjectID; // Project ID projectId: ObjectID; // Project ID
dataRententionInDays: number; // how long the data should be retained.
productType: ProductType; // what is the product type of the request - logs, metrics or traces. productType: ProductType; // what is the product type of the request - logs, metrics or traces.
} }
@ -68,6 +70,7 @@ export default class TelemetryIngest {
select: { select: {
_id: true, _id: true,
projectId: true, projectId: true,
retainTelemetryDataForDays: true,
}, },
props: { props: {
isRoot: true, isRoot: true,
@ -92,6 +95,7 @@ export default class TelemetryIngest {
(req as TelemetryRequest).serviceId = service.id as ObjectID; (req as TelemetryRequest).serviceId = service.id as ObjectID;
(req as TelemetryRequest).projectId = (req as TelemetryRequest).projectId =
service.projectId as ObjectID; service.projectId as ObjectID;
(req as TelemetryRequest).dataRententionInDays = service.retainTelemetryDataForDays || DEFAULT_RETENTION_IN_DAYS;
} }
(req as TelemetryRequest).serviceId = ObjectID.fromString( (req as TelemetryRequest).serviceId = ObjectID.fromString(
@ -102,10 +106,12 @@ export default class TelemetryIngest {
); );
// report to Usage Service. // report to Usage Service.
UsageBillingService.updateUsageBilling({ TelemetryUsageBillingService.updateUsageBilling({
projectId: (req as TelemetryRequest).projectId, projectId: (req as TelemetryRequest).projectId,
productType: (req as TelemetryRequest).productType, productType: (req as TelemetryRequest).productType,
usageCount: sizeToGb, dataIngestedInGB: sizeToGb,
telemetryServiceId: (req as TelemetryRequest).serviceId,
retentionInDays: (req as TelemetryRequest).dataRententionInDays,
}).catch((err: Error) => { }).catch((err: Error) => {
logger.error('Failed to update usage billing for OTel'); logger.error('Failed to update usage billing for OTel');
logger.error(err); logger.error(err);

View File

@ -17,12 +17,11 @@ import IconProp from 'Common/Types/Icon/IconProp';
import Decimal from 'Common/Types/Decimal'; import Decimal from 'Common/Types/Decimal';
import BaseModel from 'Common/Models/BaseModel'; import BaseModel from 'Common/Models/BaseModel';
import TelemetryService from './TelemetryService'; import TelemetryService from './TelemetryService';
import ProductType from 'Common/Types/MeteredPlan/ProductType';
export const DEFAULT_RETENTION_IN_DAYS: number = 15;
export enum ProductType {
Logs = 'Logs',
Traces = 'Traces',
Metrics = 'Metrics',
}
@TenantColumn('projectId') @TenantColumn('projectId')
@TableAccessControl({ @TableAccessControl({
@ -169,7 +168,7 @@ export default class TelemetryUsageBilling extends BaseModel {
type: ColumnType.Number, type: ColumnType.Number,
nullable: true, nullable: true,
unique: false, unique: false,
default: 15, default: DEFAULT_RETENTION_IN_DAYS,
}) })
public retainTelemetryDataForDays?: number = undefined; public retainTelemetryDataForDays?: number = undefined;