mirror of
https://github.com/OneUptime/oneuptime
synced 2024-11-21 22:59:07 +00:00
Update usageCount and totalCostInUSD to use Decimal type
This commit is contained in:
parent
03a503b080
commit
018d3b7fcd
77
Common/Types/Decimal.ts
Normal file
77
Common/Types/Decimal.ts
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
@ -28,6 +28,7 @@ import StartAndEndTime from './Time/StartAndEndTime';
|
|||||||
|
|
||||||
export enum ObjectType {
|
export enum ObjectType {
|
||||||
ObjectID = 'ObjectID',
|
ObjectID = 'ObjectID',
|
||||||
|
Decimal = 'Decimal',
|
||||||
Name = 'Name',
|
Name = 'Name',
|
||||||
EqualToOrNull = 'EqualToOrNull',
|
EqualToOrNull = 'EqualToOrNull',
|
||||||
MonitorSteps = 'MonitorSteps',
|
MonitorSteps = 'MonitorSteps',
|
||||||
|
@ -9,6 +9,7 @@ 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 MeteredPlan from 'Common/Types/Billing/MeteredPlan';
|
||||||
import ServerMeteredPlan from '../Types/Billing/MeteredPlan/ServerMeteredPlan';
|
import ServerMeteredPlan from '../Types/Billing/MeteredPlan/ServerMeteredPlan';
|
||||||
|
import Decimal from 'Common/Types/Decimal';
|
||||||
|
|
||||||
export class Service extends DatabaseService<Model> {
|
export class Service extends DatabaseService<Model> {
|
||||||
public constructor(postgresDatabase?: PostgresDatabase) {
|
public constructor(postgresDatabase?: PostgresDatabase) {
|
||||||
@ -94,10 +95,10 @@ export class Service extends DatabaseService<Model> {
|
|||||||
id: usageBilling.id,
|
id: usageBilling.id,
|
||||||
data: {
|
data: {
|
||||||
usageCount:
|
usageCount:
|
||||||
(usageBilling.usageCount || 0) + data.usageCount,
|
new Decimal((usageBilling.usageCount?.value || 0) + data.usageCount),
|
||||||
totalCostInUSD:
|
totalCostInUSD:new Decimal(
|
||||||
(usageBilling.totalCostInUSD || 0) +
|
(usageBilling.totalCostInUSD?.value || 0) +
|
||||||
totalCostOfThisOperationInUSD,
|
totalCostOfThisOperationInUSD),
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
isRoot: true,
|
isRoot: true,
|
||||||
@ -107,13 +108,13 @@ 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 = data.usageCount;
|
usageBilling.usageCount = new Decimal(data.usageCount);
|
||||||
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 = totalCostOfThisOperationInUSD;
|
usageBilling.totalCostInUSD = new Decimal(totalCostOfThisOperationInUSD);
|
||||||
usageBilling.usageUnitName = meteredPlan.getUnitName(); // e.g. "GB"
|
usageBilling.usageUnitName = meteredPlan.getUnitName(); // e.g. "GB"
|
||||||
|
|
||||||
await this.create({
|
await this.create({
|
||||||
|
@ -12,6 +12,7 @@ import FieldType from 'CommonUI/src/Components/Types/FieldType';
|
|||||||
import DashboardNavigation from '../../Utils/Navigation';
|
import DashboardNavigation from '../../Utils/Navigation';
|
||||||
import Currency from 'Common/Types/Currency';
|
import Currency from 'Common/Types/Currency';
|
||||||
import DiskSize from 'Common/Types/DiskSize';
|
import DiskSize from 'Common/Types/DiskSize';
|
||||||
|
import Decimal from 'Common/Types/Decimal';
|
||||||
|
|
||||||
export interface ComponentProps extends PageComponentProps {}
|
export interface ComponentProps extends PageComponentProps {}
|
||||||
|
|
||||||
@ -93,7 +94,7 @@ const Settings: FunctionComponent<ComponentProps> = (
|
|||||||
getElement: (item: JSONObject) => {
|
getElement: (item: JSONObject) => {
|
||||||
return (
|
return (
|
||||||
<div>{`${DiskSize.convertToDecimalPlaces(
|
<div>{`${DiskSize.convertToDecimalPlaces(
|
||||||
item['usageCount'] as number
|
(item['usageCount'] as Decimal).value as number
|
||||||
)} ${item['usageUnitName'] as string}`}</div>
|
)} ${item['usageUnitName'] as string}`}</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -107,7 +108,7 @@ const Settings: FunctionComponent<ComponentProps> = (
|
|||||||
getElement: (item: JSONObject) => {
|
getElement: (item: JSONObject) => {
|
||||||
return (
|
return (
|
||||||
<div>{`${Currency.convertToDecimalPlaces(
|
<div>{`${Currency.convertToDecimalPlaces(
|
||||||
item['totalCostInUSD'] as number
|
(item['totalCostInUSD'] as Decimal).value as number
|
||||||
)} USD`}</div>
|
)} USD`}</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -7,6 +7,8 @@ using OpenTelemetry.Trace;
|
|||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
const string endpoint = "http://localhost:4317";
|
||||||
|
|
||||||
Console.WriteLine($"Env var: {Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_HEADERS")?.ToString()}");
|
Console.WriteLine($"Env var: {Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_HEADERS")?.ToString()}");
|
||||||
|
|
||||||
|
|
||||||
@ -28,6 +30,15 @@ builder.Logging.AddOpenTelemetry(logging =>
|
|||||||
.AddConsoleExporter()
|
.AddConsoleExporter()
|
||||||
.AddOtlpExporter(opt =>
|
.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}");
|
System.Console.WriteLine($"OTLP Exporter is using {opt.Protocol} protocol and endpoint {opt.Endpoint}");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -41,6 +52,16 @@ builder.Services.AddOpenTelemetry()
|
|||||||
.AddConsoleExporter()
|
.AddConsoleExporter()
|
||||||
.AddOtlpExporter(opt =>
|
.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}");
|
System.Console.WriteLine($"OTLP Exporter is using {opt.Protocol} protocol and endpoint {opt.Endpoint}");
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -61,6 +82,14 @@ builder.Services.AddOpenTelemetry()
|
|||||||
})
|
})
|
||||||
.AddOtlpExporter(opt =>
|
.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}");
|
System.Console.WriteLine($"OTLP Exporter is using {opt.Protocol} protocol and endpoint {opt.Endpoint}");
|
||||||
|
|
||||||
}));
|
}));
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -40,3 +40,4 @@
|
|||||||
2.0
|
2.0
|
||||||
2.0
|
2.0
|
||||||
2.0
|
2.0
|
||||||
|
2.0
|
||||||
|
@ -68,8 +68,10 @@
|
|||||||
value: {{ $.Values.port.dashboard | squote }}
|
value: {{ $.Values.port.dashboard | squote }}
|
||||||
- name: ADMIN_DASHBOARD_PORT
|
- name: ADMIN_DASHBOARD_PORT
|
||||||
value: {{ $.Values.port.adminDashboard | squote }}
|
value: {{ $.Values.port.adminDashboard | squote }}
|
||||||
- name: OTEL_COLLECTOR_PORT
|
- name: OTEL_COLLECTOR_GRPC_PORT
|
||||||
value: {{ $.Values.port.otelCollector | squote }}
|
value: {{ $.Values.port.otelCollectorGrpc | squote }}
|
||||||
|
- name: OTEL_COLLECTOR_HTTP_PORT
|
||||||
|
value: {{ $.Values.port.otelCollectorHttp | squote }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
|
||||||
|
@ -147,7 +147,8 @@ port:
|
|||||||
nginx: 80
|
nginx: 80
|
||||||
haraka: 2525
|
haraka: 2525
|
||||||
probe: 3500
|
probe: 3500
|
||||||
otelCollector: 4317
|
otelCollectorGrpc: 4317
|
||||||
|
otelCollectorHttp: 4318
|
||||||
|
|
||||||
|
|
||||||
testServer:
|
testServer:
|
||||||
|
@ -35,9 +35,11 @@ import { ProductType } from 'Model/Models/UsageBilling';
|
|||||||
const LogsProto: protobuf.Root = protobuf.loadSync(
|
const LogsProto: protobuf.Root = protobuf.loadSync(
|
||||||
'/usr/src/app/ProtoFiles/OTel/v1/logs.proto'
|
'/usr/src/app/ProtoFiles/OTel/v1/logs.proto'
|
||||||
);
|
);
|
||||||
|
|
||||||
const TracesProto: protobuf.Root = protobuf.loadSync(
|
const TracesProto: protobuf.Root = protobuf.loadSync(
|
||||||
'/usr/src/app/ProtoFiles/OTel/v1/traces.proto'
|
'/usr/src/app/ProtoFiles/OTel/v1/traces.proto'
|
||||||
);
|
);
|
||||||
|
|
||||||
const MetricsProto: protobuf.Root = protobuf.loadSync(
|
const MetricsProto: protobuf.Root = protobuf.loadSync(
|
||||||
'/usr/src/app/ProtoFiles/OTel/v1/metrics.proto'
|
'/usr/src/app/ProtoFiles/OTel/v1/metrics.proto'
|
||||||
);
|
);
|
||||||
@ -63,6 +65,19 @@ router.use(
|
|||||||
'/otel/*',
|
'/otel/*',
|
||||||
async (req: ExpressRequest, _res: ExpressResponse, next: NextFunction) => {
|
async (req: ExpressRequest, _res: ExpressResponse, next: NextFunction) => {
|
||||||
try {
|
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.
|
// size of req.body in bytes.
|
||||||
const sizeInBytes: number = Buffer.byteLength(
|
const sizeInBytes: number = Buffer.byteLength(
|
||||||
JSON.stringify(req.body)
|
JSON.stringify(req.body)
|
||||||
@ -85,17 +100,7 @@ router.use(
|
|||||||
throw new BadRequestException('Invalid URL: ' + req.baseUrl);
|
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(
|
const cachedServiceId: string | null = await GlobalCache.getString(
|
||||||
'service-token',
|
'service-token',
|
||||||
@ -276,7 +281,7 @@ router.post(
|
|||||||
(metric['sum'] as JSONObject)['dataPoints'] &&
|
(metric['sum'] as JSONObject)['dataPoints'] &&
|
||||||
(
|
(
|
||||||
(metric['sum'] as JSONObject)[
|
(metric['sum'] as JSONObject)[
|
||||||
'dataPoints'
|
'dataPoints'
|
||||||
] as JSONArray
|
] as JSONArray
|
||||||
).length > 0
|
).length > 0
|
||||||
) {
|
) {
|
||||||
@ -326,7 +331,7 @@ router.post(
|
|||||||
(metric['gauge'] as JSONObject)['dataPoints'] &&
|
(metric['gauge'] as JSONObject)['dataPoints'] &&
|
||||||
(
|
(
|
||||||
(metric['gauge'] as JSONObject)[
|
(metric['gauge'] as JSONObject)[
|
||||||
'dataPoints'
|
'dataPoints'
|
||||||
] as JSONArray
|
] as JSONArray
|
||||||
).length > 0
|
).length > 0
|
||||||
) {
|
) {
|
||||||
@ -377,7 +382,7 @@ router.post(
|
|||||||
(metric['histogram'] as JSONObject)['dataPoints'] &&
|
(metric['histogram'] as JSONObject)['dataPoints'] &&
|
||||||
(
|
(
|
||||||
(metric['histogram'] as JSONObject)[
|
(metric['histogram'] as JSONObject)[
|
||||||
'dataPoints'
|
'dataPoints'
|
||||||
] as JSONArray
|
] as JSONArray
|
||||||
).length > 0
|
).length > 0
|
||||||
) {
|
) {
|
||||||
|
@ -16,6 +16,7 @@ import ColumnAccessControl from 'Common/Types/Database/AccessControl/ColumnAcces
|
|||||||
import TenantColumn from 'Common/Types/Database/TenantColumn';
|
import TenantColumn from 'Common/Types/Database/TenantColumn';
|
||||||
import TableMetadata from 'Common/Types/Database/TableMetadata';
|
import TableMetadata from 'Common/Types/Database/TableMetadata';
|
||||||
import IconProp from 'Common/Types/Icon/IconProp';
|
import IconProp from 'Common/Types/Icon/IconProp';
|
||||||
|
import Decimal from 'Common/Types/Decimal';
|
||||||
|
|
||||||
export enum ProductType {
|
export enum ProductType {
|
||||||
Logs = 'Logs',
|
Logs = 'Logs',
|
||||||
@ -170,8 +171,9 @@ export default class UsageBilling extends AccessControlModel {
|
|||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
type: ColumnType.Decimal,
|
type: ColumnType.Decimal,
|
||||||
|
transformer: Decimal.getDatabaseTransformer()
|
||||||
})
|
})
|
||||||
public usageCount?: number = undefined;
|
public usageCount?: Decimal = undefined;
|
||||||
|
|
||||||
@ColumnAccessControl({
|
@ColumnAccessControl({
|
||||||
create: [],
|
create: [],
|
||||||
@ -216,8 +218,9 @@ export default class UsageBilling extends AccessControlModel {
|
|||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
type: ColumnType.Decimal,
|
type: ColumnType.Decimal,
|
||||||
|
transformer: Decimal.getDatabaseTransformer()
|
||||||
})
|
})
|
||||||
public totalCostInUSD?: number = undefined;
|
public totalCostInUSD?: Decimal = undefined;
|
||||||
|
|
||||||
@ColumnAccessControl({
|
@ColumnAccessControl({
|
||||||
create: [],
|
create: [],
|
||||||
|
@ -104,7 +104,8 @@ ACCOUNTS_PORT=3003
|
|||||||
STATUS_PAGE_PORT=3105
|
STATUS_PAGE_PORT=3105
|
||||||
DASHBOARD_PORT=3009
|
DASHBOARD_PORT=3009
|
||||||
ADMIN_DASHBOARD_PORT=3158
|
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.
|
# If USE_INTERNAL_SMTP is true then you need to fill these values.
|
||||||
|
@ -44,7 +44,8 @@ x-common-variables: &common-variables
|
|||||||
STATUS_PAGE_PORT: ${STATUS_PAGE_PORT}
|
STATUS_PAGE_PORT: ${STATUS_PAGE_PORT}
|
||||||
DASHBOARD_PORT: ${DASHBOARD_PORT}
|
DASHBOARD_PORT: ${DASHBOARD_PORT}
|
||||||
ADMIN_DASHBOARD_PORT: ${ADMIN_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
|
x-common-ui-variables: &common-ui-variables
|
||||||
<<: *common-variables
|
<<: *common-variables
|
||||||
|
Loading…
Reference in New Issue
Block a user