Update usageCount and totalCostInUSD to use Decimal type

This commit is contained in:
Simon Larsen 2023-12-30 13:22:57 +00:00
parent 03a503b080
commit 018d3b7fcd
No known key found for this signature in database
GPG Key ID: AB45983AA9C81CDE
16 changed files with 151 additions and 28 deletions

77
Common/Types/Decimal.ts Normal file
View File

@ -0,0 +1,77 @@
// This is for Object ID for all the things in our database.
import { FindOperator } from 'typeorm';
import DatabaseProperty from './Database/DatabaseProperty';
import { JSONObject, ObjectType } from './JSON';
import BadDataException from './Exception/BadDataException';
export default class Decimal extends DatabaseProperty {
private _value: number = 0;
public get value(): number {
return this._value;
}
public set value(v: number) {
this._value = v;
}
public constructor(value: number | Decimal | string) {
super();
if (typeof value === 'string') {
value = parseFloat(value);
}
if (value instanceof Decimal) {
value = value.value;
}
this.value = value;
}
public equals(other: Decimal): boolean {
return this.value.toString() === other.value.toString();
}
public override toString(): string {
return this.value.toString();
}
protected static override toDatabase(
value: Decimal | FindOperator<Decimal>
): string | null {
if (value) {
return value.toString();
}
return null;
}
public override toJSON(): JSONObject {
return {
_type: ObjectType.Decimal,
value: (this as Decimal).toString(),
};
}
public static override fromJSON(json: JSONObject): Decimal {
if (json['_type'] === ObjectType.Decimal) {
return new Decimal((json['value'] as number) || 0);
}
throw new BadDataException('Invalid JSON: ' + JSON.stringify(json));
}
protected static override fromDatabase(_value: number): Decimal | null {
if (_value) {
return new Decimal(_value);
}
return null;
}
public static fromString(value: string): Decimal {
return new Decimal(value);
}
}

View File

@ -28,6 +28,7 @@ import StartAndEndTime from './Time/StartAndEndTime';
export enum ObjectType {
ObjectID = 'ObjectID',
Decimal = 'Decimal',
Name = 'Name',
EqualToOrNull = 'EqualToOrNull',
MonitorSteps = 'MonitorSteps',

View File

@ -9,6 +9,7 @@ import SortOrder from 'Common/Types/BaseDatabase/SortOrder';
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';
export class Service extends DatabaseService<Model> {
public constructor(postgresDatabase?: PostgresDatabase) {
@ -94,10 +95,10 @@ export class Service extends DatabaseService<Model> {
id: usageBilling.id,
data: {
usageCount:
(usageBilling.usageCount || 0) + data.usageCount,
totalCostInUSD:
(usageBilling.totalCostInUSD || 0) +
totalCostOfThisOperationInUSD,
new Decimal((usageBilling.usageCount?.value || 0) + data.usageCount),
totalCostInUSD:new Decimal(
(usageBilling.totalCostInUSD?.value || 0) +
totalCostOfThisOperationInUSD),
},
props: {
isRoot: true,
@ -107,13 +108,13 @@ export class Service extends DatabaseService<Model> {
const usageBilling: Model = new Model();
usageBilling.projectId = data.projectId;
usageBilling.productType = data.productType;
usageBilling.usageCount = data.usageCount;
usageBilling.usageCount = new Decimal(data.usageCount);
usageBilling.isReportedToBillingProvider = false;
usageBilling.createdAt = OneUptimeDate.getCurrentDate();
usageBilling.day = OneUptimeDate.getDateString(
OneUptimeDate.getCurrentDate()
);
usageBilling.totalCostInUSD = totalCostOfThisOperationInUSD;
usageBilling.totalCostInUSD = new Decimal(totalCostOfThisOperationInUSD);
usageBilling.usageUnitName = meteredPlan.getUnitName(); // e.g. "GB"
await this.create({

View File

@ -12,6 +12,7 @@ import FieldType from 'CommonUI/src/Components/Types/FieldType';
import DashboardNavigation from '../../Utils/Navigation';
import Currency from 'Common/Types/Currency';
import DiskSize from 'Common/Types/DiskSize';
import Decimal from 'Common/Types/Decimal';
export interface ComponentProps extends PageComponentProps {}
@ -93,7 +94,7 @@ const Settings: FunctionComponent<ComponentProps> = (
getElement: (item: JSONObject) => {
return (
<div>{`${DiskSize.convertToDecimalPlaces(
item['usageCount'] as number
(item['usageCount'] as Decimal).value as number
)} ${item['usageUnitName'] as string}`}</div>
);
},
@ -107,7 +108,7 @@ const Settings: FunctionComponent<ComponentProps> = (
getElement: (item: JSONObject) => {
return (
<div>{`${Currency.convertToDecimalPlaces(
item['totalCostInUSD'] as number
(item['totalCostInUSD'] as Decimal).value as number
)} USD`}</div>
);
},

View File

@ -7,6 +7,8 @@ using OpenTelemetry.Trace;
var builder = WebApplication.CreateBuilder(args);
const string endpoint = "http://localhost:4317";
Console.WriteLine($"Env var: {Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_HEADERS")?.ToString()}");
@ -28,6 +30,15 @@ builder.Logging.AddOpenTelemetry(logging =>
.AddConsoleExporter()
.AddOtlpExporter(opt =>
{
// If endpoint was not specified, the proper one will be selected according to the protocol.
if (!string.IsNullOrEmpty(endpoint))
{
opt.Endpoint = new Uri(endpoint);
// Set headers in OTLP exporter
// opt.Headers = "oneuptime-service-token=0a00ebc0-7f39-11ee-ac8c-3fb43926b224";
}
System.Console.WriteLine($"OTLP Exporter is using {opt.Protocol} protocol and endpoint {opt.Endpoint}");
});
});
@ -41,6 +52,16 @@ builder.Services.AddOpenTelemetry()
.AddConsoleExporter()
.AddOtlpExporter(opt =>
{
// If endpoint was not specified, the proper one will be selected according to the protocol.
if (!string.IsNullOrEmpty(endpoint))
{
opt.Endpoint = new Uri(endpoint);
// Set headers in OTLP exporter
// opt.Headers = "oneuptime-service-token=0a00ebc0-7f39-11ee-ac8c-3fb43926b224";
}
System.Console.WriteLine($"OTLP Exporter is using {opt.Protocol} protocol and endpoint {opt.Endpoint}");
}));
@ -61,6 +82,14 @@ builder.Services.AddOpenTelemetry()
})
.AddOtlpExporter(opt =>
{
// If endpoint was not specified, the proper one will be selected according to the protocol.
if (!string.IsNullOrEmpty(endpoint))
{
opt.Endpoint = new Uri(endpoint);
// Set headers in OTLP exporter
// opt.Headers = "oneuptime-service-token=0a00ebc0-7f39-11ee-ac8c-3fb43926b224";
}
System.Console.WriteLine($"OTLP Exporter is using {opt.Protocol} protocol and endpoint {opt.Endpoint}");
}));

View File

@ -40,3 +40,4 @@
2.0
2.0
2.0
2.0

View File

@ -68,8 +68,10 @@
value: {{ $.Values.port.dashboard | squote }}
- name: ADMIN_DASHBOARD_PORT
value: {{ $.Values.port.adminDashboard | squote }}
- name: OTEL_COLLECTOR_PORT
value: {{ $.Values.port.otelCollector | squote }}
- name: OTEL_COLLECTOR_GRPC_PORT
value: {{ $.Values.port.otelCollectorGrpc | squote }}
- name: OTEL_COLLECTOR_HTTP_PORT
value: {{ $.Values.port.otelCollectorHttp | squote }}
{{- end }}

View File

@ -147,7 +147,8 @@ port:
nginx: 80
haraka: 2525
probe: 3500
otelCollector: 4317
otelCollectorGrpc: 4317
otelCollectorHttp: 4318
testServer:

View File

@ -35,9 +35,11 @@ import { ProductType } from 'Model/Models/UsageBilling';
const LogsProto: protobuf.Root = protobuf.loadSync(
'/usr/src/app/ProtoFiles/OTel/v1/logs.proto'
);
const TracesProto: protobuf.Root = protobuf.loadSync(
'/usr/src/app/ProtoFiles/OTel/v1/traces.proto'
);
const MetricsProto: protobuf.Root = protobuf.loadSync(
'/usr/src/app/ProtoFiles/OTel/v1/metrics.proto'
);
@ -63,6 +65,19 @@ router.use(
'/otel/*',
async (req: ExpressRequest, _res: ExpressResponse, next: NextFunction) => {
try {
// check header.
const serviceTokenInHeader: string | undefined = req.headers[
'x-oneuptime-service-token'
] as string | undefined;
if (!serviceTokenInHeader) {
throw new BadRequestException(
'Missing header: x-oneuptime-service-token'
);
}
// size of req.body in bytes.
const sizeInBytes: number = Buffer.byteLength(
JSON.stringify(req.body)
@ -85,17 +100,7 @@ router.use(
throw new BadRequestException('Invalid URL: ' + req.baseUrl);
}
// check header.
const serviceTokenInHeader: string | undefined = req.headers[
'x-oneuptime-service-token'
] as string | undefined;
if (!serviceTokenInHeader) {
throw new BadRequestException(
'Missing header: oneuptime-service-token'
);
}
const cachedServiceId: string | null = await GlobalCache.getString(
'service-token',

View File

@ -16,6 +16,7 @@ import ColumnAccessControl from 'Common/Types/Database/AccessControl/ColumnAcces
import TenantColumn from 'Common/Types/Database/TenantColumn';
import TableMetadata from 'Common/Types/Database/TableMetadata';
import IconProp from 'Common/Types/Icon/IconProp';
import Decimal from 'Common/Types/Decimal';
export enum ProductType {
Logs = 'Logs',
@ -170,8 +171,9 @@ export default class UsageBilling extends AccessControlModel {
@Column({
nullable: false,
type: ColumnType.Decimal,
transformer: Decimal.getDatabaseTransformer()
})
public usageCount?: number = undefined;
public usageCount?: Decimal = undefined;
@ColumnAccessControl({
create: [],
@ -216,8 +218,9 @@ export default class UsageBilling extends AccessControlModel {
@Column({
nullable: false,
type: ColumnType.Decimal,
transformer: Decimal.getDatabaseTransformer()
})
public totalCostInUSD?: number = undefined;
public totalCostInUSD?: Decimal = undefined;
@ColumnAccessControl({
create: [],

View File

@ -104,7 +104,8 @@ ACCOUNTS_PORT=3003
STATUS_PAGE_PORT=3105
DASHBOARD_PORT=3009
ADMIN_DASHBOARD_PORT=3158
OTEL_COLLECTOR_PORT=4317
OTEL_COLLECTOR_GRPC_PORT=4317
OTEL_COLLECTOR_HTTP_PORT=4318
# If USE_INTERNAL_SMTP is true then you need to fill these values.

View File

@ -44,7 +44,8 @@ x-common-variables: &common-variables
STATUS_PAGE_PORT: ${STATUS_PAGE_PORT}
DASHBOARD_PORT: ${DASHBOARD_PORT}
ADMIN_DASHBOARD_PORT: ${ADMIN_DASHBOARD_PORT}
OTEL_COLLECTOR_PORT: ${OTEL_COLLECTOR_PORT}
OTEL_COLLECTOR_GRPC_PORT: ${OTEL_COLLECTOR_GRPC_PORT}
OTEL_COLLECTOR_HTTP_PORT: ${OTEL_COLLECTOR_HTTP_PORT}
x-common-ui-variables: &common-ui-variables
<<: *common-variables