Compare commits

..

1 Commits

Author SHA1 Message Date
Abhi Kumar
0115a3d51a chore: updated drilldown popup ui to match tooltip 2026-04-27 14:17:37 +05:30
46 changed files with 152 additions and 4604 deletions

View File

@@ -167,7 +167,7 @@ func runServer(ctx context.Context, config signoz.Config, logger *slog.Logger) e
if err != nil {
return nil, err
}
azureCloudProviderModule := implcloudprovider.NewAzureCloudProvider(defStore)
azureCloudProviderModule := implcloudprovider.NewAzureCloudProvider()
cloudProvidersMap := map[cloudintegrationtypes.CloudProviderType]cloudintegration.CloudProviderModule{
cloudintegrationtypes.CloudProviderTypeAWS: awsCloudProviderModule,
cloudintegrationtypes.CloudProviderTypeAzure: azureCloudProviderModule,

File diff suppressed because it is too large Load Diff

View File

@@ -18,7 +18,6 @@ func NewAWSCloudProvider(defStore cloudintegrationtypes.ServiceDefinitionStore)
return &awscloudprovider{serviceDefinitions: defStore}, nil
}
// TODO: move URL construction logic to cloudintegrationtypes and add unit tests for it.
func (provider *awscloudprovider) GetConnectionArtifact(ctx context.Context, account *cloudintegrationtypes.Account, req *cloudintegrationtypes.GetConnectionArtifactRequest) (*cloudintegrationtypes.ConnectionArtifact, error) {
baseURL := fmt.Sprintf(cloudintegrationtypes.CloudFormationQuickCreateBaseURL.StringValue(), req.Config.AWS.DeploymentRegion)
u, _ := url.Parse(baseURL)

View File

@@ -2,48 +2,27 @@ package implcloudprovider
import (
"context"
"sort"
"github.com/SigNoz/signoz/pkg/modules/cloudintegration"
"github.com/SigNoz/signoz/pkg/types/cloudintegrationtypes"
)
type azurecloudprovider struct {
serviceDefinitions cloudintegrationtypes.ServiceDefinitionStore
}
type azurecloudprovider struct{}
func NewAzureCloudProvider(defStore cloudintegrationtypes.ServiceDefinitionStore) cloudintegration.CloudProviderModule {
return &azurecloudprovider{
serviceDefinitions: defStore,
}
func NewAzureCloudProvider() cloudintegration.CloudProviderModule {
return &azurecloudprovider{}
}
func (provider *azurecloudprovider) GetConnectionArtifact(ctx context.Context, account *cloudintegrationtypes.Account, req *cloudintegrationtypes.GetConnectionArtifactRequest) (*cloudintegrationtypes.ConnectionArtifact, error) {
connectionArtifact, err := cloudintegrationtypes.NewAzureConnectionArtifact(account.ID, req.Config.AgentVersion, req.Credentials, req.Config.Azure)
if err != nil {
return nil, err
}
return &cloudintegrationtypes.ConnectionArtifact{
Azure: connectionArtifact,
}, nil
panic("implement me")
}
func (provider *azurecloudprovider) ListServiceDefinitions(ctx context.Context) ([]*cloudintegrationtypes.ServiceDefinition, error) {
return provider.serviceDefinitions.List(ctx, cloudintegrationtypes.CloudProviderTypeAzure)
panic("implement me")
}
func (provider *azurecloudprovider) GetServiceDefinition(ctx context.Context, serviceID cloudintegrationtypes.ServiceID) (*cloudintegrationtypes.ServiceDefinition, error) {
serviceDef, err := provider.serviceDefinitions.Get(ctx, cloudintegrationtypes.CloudProviderTypeAzure, serviceID)
if err != nil {
return nil, err
}
// override cloud integration dashboard id.
for index, dashboard := range serviceDef.Assets.Dashboards {
serviceDef.Assets.Dashboards[index].ID = cloudintegrationtypes.GetCloudIntegrationDashboardID(cloudintegrationtypes.CloudProviderTypeAzure, serviceID.StringValue(), dashboard.ID)
}
return serviceDef, nil
panic("implement me")
}
func (provider *azurecloudprovider) BuildIntegrationConfig(
@@ -51,56 +30,5 @@ func (provider *azurecloudprovider) BuildIntegrationConfig(
account *cloudintegrationtypes.Account,
services []*cloudintegrationtypes.StorableCloudIntegrationService,
) (*cloudintegrationtypes.ProviderIntegrationConfig, error) {
sort.Slice(services, func(i, j int) bool {
return services[i].Type.StringValue() < services[j].Type.StringValue()
})
var strategies []*cloudintegrationtypes.AzureTelemetryCollectionStrategy
for _, storedSvc := range services {
svcCfg, err := cloudintegrationtypes.NewServiceConfigFromJSON(cloudintegrationtypes.CloudProviderTypeAzure, storedSvc.Config)
if err != nil {
return nil, err
}
svcDef, err := provider.GetServiceDefinition(ctx, storedSvc.Type)
if err != nil {
return nil, err
}
strategy := svcDef.TelemetryCollectionStrategy.Azure
if strategy == nil {
continue
}
logsEnabled := svcCfg.IsLogsEnabled(cloudintegrationtypes.CloudProviderTypeAzure)
metricsEnabled := svcCfg.IsMetricsEnabled(cloudintegrationtypes.CloudProviderTypeAzure)
if !logsEnabled && !metricsEnabled {
continue
}
entry := &cloudintegrationtypes.AzureTelemetryCollectionStrategy{
ResourceProvider: strategy.ResourceProvider,
ResourceType: strategy.ResourceType,
}
if metricsEnabled && strategy.Metrics != nil {
entry.Metrics = strategy.Metrics
}
if logsEnabled && strategy.Logs != nil {
entry.Logs = strategy.Logs
}
strategies = append(strategies, entry)
}
return &cloudintegrationtypes.ProviderIntegrationConfig{
Azure: cloudintegrationtypes.NewAzureIntegrationConfig(
account.Config.Azure.DeploymentRegion,
account.Config.Azure.ResourceGroups,
strategies,
),
}, nil
panic("implement me")
}

View File

@@ -429,14 +429,10 @@ func (module *module) Collect(ctx context.Context, orgID valuer.UUID) (map[strin
stats["cloudintegration.aws.connectedaccounts.count"] = awsAccountsCount
}
// get connected accounts for Azure
azureAccountsCount, err := module.store.CountConnectedAccounts(ctx, orgID, cloudintegrationtypes.CloudProviderTypeAzure)
if err == nil {
stats["cloudintegration.azure.connectedaccounts.count"] = azureAccountsCount
}
// NOTE: not adding stats for services for now.
// TODO: add more cloud providers when supported
return stats, nil
}

View File

@@ -1,399 +0,0 @@
/**
* ! Do not edit manually
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'yarn generate:api'
* SigNoz
*/
import { useMutation, useQuery } from 'react-query';
import type {
InvalidateOptions,
MutationFunction,
QueryClient,
QueryFunction,
QueryKey,
UseMutationOptions,
UseMutationResult,
UseQueryOptions,
UseQueryResult,
} from 'react-query';
import type {
DeleteLLMPricingRulePathParameters,
GetLLMPricingRule200,
GetLLMPricingRulePathParameters,
ListLLMPricingRules200,
ListLLMPricingRulesParams,
LlmpricingruletypesUpdatableLLMPricingRulesDTO,
RenderErrorResponseDTO,
} from '../sigNoz.schemas';
import { GeneratedAPIInstance } from '../../../generatedAPIInstance';
import type { ErrorType, BodyType } from '../../../generatedAPIInstance';
/**
* Returns all LLM pricing rules for the authenticated org, with pagination.
* @summary List pricing rules
*/
export const listLLMPricingRules = (
params?: ListLLMPricingRulesParams,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<ListLLMPricingRules200>({
url: `/api/v1/llm_pricing_rules`,
method: 'GET',
params,
signal,
});
};
export const getListLLMPricingRulesQueryKey = (
params?: ListLLMPricingRulesParams,
) => {
return [`/api/v1/llm_pricing_rules`, ...(params ? [params] : [])] as const;
};
export const getListLLMPricingRulesQueryOptions = <
TData = Awaited<ReturnType<typeof listLLMPricingRules>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
params?: ListLLMPricingRulesParams,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listLLMPricingRules>>,
TError,
TData
>;
},
) => {
const { query: queryOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getListLLMPricingRulesQueryKey(params);
const queryFn: QueryFunction<
Awaited<ReturnType<typeof listLLMPricingRules>>
> = ({ signal }) => listLLMPricingRules(params, signal);
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof listLLMPricingRules>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type ListLLMPricingRulesQueryResult = NonNullable<
Awaited<ReturnType<typeof listLLMPricingRules>>
>;
export type ListLLMPricingRulesQueryError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary List pricing rules
*/
export function useListLLMPricingRules<
TData = Awaited<ReturnType<typeof listLLMPricingRules>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
params?: ListLLMPricingRulesParams,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listLLMPricingRules>>,
TError,
TData
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getListLLMPricingRulesQueryOptions(params, options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
query.queryKey = queryOptions.queryKey;
return query;
}
/**
* @summary List pricing rules
*/
export const invalidateListLLMPricingRules = async (
queryClient: QueryClient,
params?: ListLLMPricingRulesParams,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getListLLMPricingRulesQueryKey(params) },
options,
);
return queryClient;
};
/**
* Single write endpoint used by both the user and the Zeus sync job. Per-rule match is by id, then sourceId, then insert. Override rows (is_override=true) are fully preserved when the request does not provide isOverride; only synced_at is stamped.
* @summary Create or update pricing rules
*/
export const createOrUpdateLLMPricingRules = (
llmpricingruletypesUpdatableLLMPricingRulesDTO: BodyType<LlmpricingruletypesUpdatableLLMPricingRulesDTO>,
) => {
return GeneratedAPIInstance<void>({
url: `/api/v1/llm_pricing_rules`,
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
data: llmpricingruletypesUpdatableLLMPricingRulesDTO,
});
};
export const getCreateOrUpdateLLMPricingRulesMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createOrUpdateLLMPricingRules>>,
TError,
{ data: BodyType<LlmpricingruletypesUpdatableLLMPricingRulesDTO> },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof createOrUpdateLLMPricingRules>>,
TError,
{ data: BodyType<LlmpricingruletypesUpdatableLLMPricingRulesDTO> },
TContext
> => {
const mutationKey = ['createOrUpdateLLMPricingRules'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof createOrUpdateLLMPricingRules>>,
{ data: BodyType<LlmpricingruletypesUpdatableLLMPricingRulesDTO> }
> = (props) => {
const { data } = props ?? {};
return createOrUpdateLLMPricingRules(data);
};
return { mutationFn, ...mutationOptions };
};
export type CreateOrUpdateLLMPricingRulesMutationResult = NonNullable<
Awaited<ReturnType<typeof createOrUpdateLLMPricingRules>>
>;
export type CreateOrUpdateLLMPricingRulesMutationBody =
BodyType<LlmpricingruletypesUpdatableLLMPricingRulesDTO>;
export type CreateOrUpdateLLMPricingRulesMutationError =
ErrorType<RenderErrorResponseDTO>;
/**
* @summary Create or update pricing rules
*/
export const useCreateOrUpdateLLMPricingRules = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createOrUpdateLLMPricingRules>>,
TError,
{ data: BodyType<LlmpricingruletypesUpdatableLLMPricingRulesDTO> },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof createOrUpdateLLMPricingRules>>,
TError,
{ data: BodyType<LlmpricingruletypesUpdatableLLMPricingRulesDTO> },
TContext
> => {
const mutationOptions =
getCreateOrUpdateLLMPricingRulesMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* Hard-deletes a pricing rule. If auto-synced, it will be recreated on the next sync cycle.
* @summary Delete a pricing rule
*/
export const deleteLLMPricingRule = ({
id,
}: DeleteLLMPricingRulePathParameters) => {
return GeneratedAPIInstance<void>({
url: `/api/v1/llm_pricing_rules/${id}`,
method: 'DELETE',
});
};
export const getDeleteLLMPricingRuleMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteLLMPricingRule>>,
TError,
{ pathParams: DeleteLLMPricingRulePathParameters },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof deleteLLMPricingRule>>,
TError,
{ pathParams: DeleteLLMPricingRulePathParameters },
TContext
> => {
const mutationKey = ['deleteLLMPricingRule'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof deleteLLMPricingRule>>,
{ pathParams: DeleteLLMPricingRulePathParameters }
> = (props) => {
const { pathParams } = props ?? {};
return deleteLLMPricingRule(pathParams);
};
return { mutationFn, ...mutationOptions };
};
export type DeleteLLMPricingRuleMutationResult = NonNullable<
Awaited<ReturnType<typeof deleteLLMPricingRule>>
>;
export type DeleteLLMPricingRuleMutationError =
ErrorType<RenderErrorResponseDTO>;
/**
* @summary Delete a pricing rule
*/
export const useDeleteLLMPricingRule = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteLLMPricingRule>>,
TError,
{ pathParams: DeleteLLMPricingRulePathParameters },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof deleteLLMPricingRule>>,
TError,
{ pathParams: DeleteLLMPricingRulePathParameters },
TContext
> => {
const mutationOptions = getDeleteLLMPricingRuleMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* Returns a single LLM pricing rule by ID.
* @summary Get a pricing rule
*/
export const getLLMPricingRule = (
{ id }: GetLLMPricingRulePathParameters,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<GetLLMPricingRule200>({
url: `/api/v1/llm_pricing_rules/${id}`,
method: 'GET',
signal,
});
};
export const getGetLLMPricingRuleQueryKey = ({
id,
}: GetLLMPricingRulePathParameters) => {
return [`/api/v1/llm_pricing_rules/${id}`] as const;
};
export const getGetLLMPricingRuleQueryOptions = <
TData = Awaited<ReturnType<typeof getLLMPricingRule>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
{ id }: GetLLMPricingRulePathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getLLMPricingRule>>,
TError,
TData
>;
},
) => {
const { query: queryOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getGetLLMPricingRuleQueryKey({ id });
const queryFn: QueryFunction<
Awaited<ReturnType<typeof getLLMPricingRule>>
> = ({ signal }) => getLLMPricingRule({ id }, signal);
return {
queryKey,
queryFn,
enabled: !!id,
...queryOptions,
} as UseQueryOptions<
Awaited<ReturnType<typeof getLLMPricingRule>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type GetLLMPricingRuleQueryResult = NonNullable<
Awaited<ReturnType<typeof getLLMPricingRule>>
>;
export type GetLLMPricingRuleQueryError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Get a pricing rule
*/
export function useGetLLMPricingRule<
TData = Awaited<ReturnType<typeof getLLMPricingRule>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
{ id }: GetLLMPricingRulePathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getLLMPricingRule>>,
TError,
TData
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getGetLLMPricingRuleQueryOptions({ id }, options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
query.queryKey = queryOptions.queryKey;
return query;
}
/**
* @summary Get a pricing rule
*/
export const invalidateGetLLMPricingRule = async (
queryClient: QueryClient,
{ id }: GetLLMPricingRulePathParameters,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getGetLLMPricingRuleQueryKey({ id }) },
options,
);
return queryClient;
};

View File

@@ -3283,170 +3283,6 @@ export enum InframonitoringtypesResponseTypeDTO {
list = 'list',
grouped_list = 'grouped_list',
}
export interface LlmpricingruletypesGettablePricingRulesDTO {
/**
* @type array
* @nullable true
*/
items: LlmpricingruletypesLLMPricingRuleDTO[] | null;
/**
* @type integer
*/
limit: number;
/**
* @type integer
*/
offset: number;
/**
* @type integer
*/
total: number;
}
export interface LlmpricingruletypesLLMPricingCacheCostsDTO {
mode: LlmpricingruletypesLLMPricingRuleCacheModeDTO;
/**
* @type number
* @format double
*/
read?: number;
/**
* @type number
* @format double
*/
write?: number;
}
export interface LlmpricingruletypesLLMPricingRuleDTO {
/**
* @type string
* @format date-time
*/
createdAt?: Date;
/**
* @type string
*/
createdBy?: string;
/**
* @type boolean
*/
enabled: boolean;
/**
* @type string
*/
id: string;
/**
* @type boolean
*/
isOverride: boolean;
/**
* @type string
*/
modelName: string;
modelPattern: LlmpricingruletypesStringSliceDTO;
/**
* @type string
*/
orgId: string;
pricing: LlmpricingruletypesLLMRulePricingDTO;
/**
* @type string
*/
provider: string;
/**
* @type string
*/
sourceId?: string;
/**
* @type string
* @format date-time
* @nullable true
*/
syncedAt?: Date | null;
unit: LlmpricingruletypesLLMPricingRuleUnitDTO;
/**
* @type string
* @format date-time
*/
updatedAt?: Date;
/**
* @type string
*/
updatedBy?: string;
}
export enum LlmpricingruletypesLLMPricingRuleCacheModeDTO {
subtract = 'subtract',
additive = 'additive',
unknown = 'unknown',
}
export enum LlmpricingruletypesLLMPricingRuleUnitDTO {
per_million_tokens = 'per_million_tokens',
}
export interface LlmpricingruletypesLLMRulePricingDTO {
cache?: LlmpricingruletypesLLMPricingCacheCostsDTO;
/**
* @type number
* @format double
*/
input: number;
/**
* @type number
* @format double
*/
output: number;
}
/**
* @nullable
*/
export type LlmpricingruletypesStringSliceDTO = string[] | null;
export interface LlmpricingruletypesUpdatableLLMPricingRuleDTO {
/**
* @type boolean
*/
enabled: boolean;
/**
* @type string
* @nullable true
*/
id?: string | null;
/**
* @type boolean
* @nullable true
*/
isOverride?: boolean | null;
/**
* @type string
*/
modelName: string;
/**
* @type array
* @nullable true
*/
modelPattern: string[] | null;
pricing: LlmpricingruletypesLLMRulePricingDTO;
/**
* @type string
*/
provider: string;
/**
* @type string
* @nullable true
*/
sourceId?: string | null;
unit: LlmpricingruletypesLLMPricingRuleUnitDTO;
}
export interface LlmpricingruletypesUpdatableLLMPricingRulesDTO {
/**
* @type array
* @nullable true
*/
rules: LlmpricingruletypesUpdatableLLMPricingRuleDTO[] | null;
}
export interface MetricsexplorertypesInspectMetricsRequestDTO {
/**
* @type integer
@@ -3865,7 +3701,10 @@ export interface PromotetypesPromotePathDTO {
}
export interface PromotetypesWrappedIndexDTO {
fieldDataType?: TelemetrytypesFieldDataTypeDTO;
/**
* @type string
*/
column_type?: string;
/**
* @type integer
*/
@@ -5636,187 +5475,6 @@ export interface Sigv4SigV4ConfigDTO {
[key: string]: unknown;
}
export enum SpantypesFieldContextDTO {
attribute = 'attribute',
resource = 'resource',
}
export interface SpantypesGettableSpanMapperGroupsDTO {
/**
* @type array
*/
items: SpantypesSpanMapperGroupDTO[];
}
export interface SpantypesPostableSpanMapperDTO {
config: SpantypesSpanMapperConfigDTO;
/**
* @type boolean
*/
enabled?: boolean;
field_context: SpantypesFieldContextDTO;
/**
* @type string
*/
name: string;
}
export interface SpantypesPostableSpanMapperGroupDTO {
category: SpantypesSpanMapperGroupCategoryDTO;
condition: SpantypesSpanMapperGroupConditionDTO;
/**
* @type boolean
*/
enabled?: boolean;
/**
* @type string
*/
name: string;
}
export interface SpantypesSpanMapperDTO {
config: SpantypesSpanMapperConfigDTO;
/**
* @type string
* @format date-time
*/
createdAt?: Date;
/**
* @type string
*/
createdBy?: string;
/**
* @type boolean
*/
enabled: boolean;
field_context: SpantypesFieldContextDTO;
/**
* @type string
*/
group_id: string;
/**
* @type string
*/
id: string;
/**
* @type string
*/
name: string;
/**
* @type string
* @format date-time
*/
updatedAt?: Date;
/**
* @type string
*/
updatedBy?: string;
}
export interface SpantypesSpanMapperConfigDTO {
/**
* @type array
* @nullable true
*/
sources: SpantypesSpanMapperSourceDTO[] | null;
}
export interface SpantypesSpanMapperGroupDTO {
category: SpantypesSpanMapperGroupCategoryDTO;
condition: SpantypesSpanMapperGroupConditionDTO;
/**
* @type string
* @format date-time
*/
createdAt?: Date;
/**
* @type string
*/
createdBy?: string;
/**
* @type boolean
*/
enabled: boolean;
/**
* @type string
*/
id: string;
/**
* @type string
*/
name: string;
/**
* @type string
*/
orgId: string;
/**
* @type string
* @format date-time
*/
updatedAt?: Date;
/**
* @type string
*/
updatedBy?: string;
}
export interface SpantypesSpanMapperGroupCategoryDTO {
[key: string]: unknown;
}
export interface SpantypesSpanMapperGroupConditionDTO {
/**
* @type array
* @nullable true
*/
attributes: string[] | null;
/**
* @type array
* @nullable true
*/
resource: string[] | null;
}
export enum SpantypesSpanMapperOperationDTO {
move = 'move',
copy = 'copy',
}
export interface SpantypesSpanMapperSourceDTO {
context: SpantypesFieldContextDTO;
/**
* @type string
*/
key: string;
operation: SpantypesSpanMapperOperationDTO;
/**
* @type integer
*/
priority: number;
}
export interface SpantypesUpdatableSpanMapperDTO {
config?: SpantypesSpanMapperConfigDTO;
/**
* @type boolean
* @nullable true
*/
enabled?: boolean | null;
field_context?: SpantypesFieldContextDTO;
}
export interface SpantypesUpdatableSpanMapperGroupDTO {
condition?: SpantypesSpanMapperGroupConditionDTO;
/**
* @type boolean
* @nullable true
*/
enabled?: boolean | null;
/**
* @type string
* @nullable true
*/
name?: string | null;
}
export enum TelemetrytypesFieldContextDTO {
metric = 'metric',
log = 'log',
@@ -7001,41 +6659,6 @@ export type CreateInvite201 = {
status: string;
};
export type ListLLMPricingRulesParams = {
/**
* @type integer
* @description undefined
*/
offset?: number;
/**
* @type integer
* @description undefined
*/
limit?: number;
};
export type ListLLMPricingRules200 = {
data: LlmpricingruletypesGettablePricingRulesDTO;
/**
* @type string
*/
status: string;
};
export type DeleteLLMPricingRulePathParameters = {
id: string;
};
export type GetLLMPricingRulePathParameters = {
id: string;
};
export type GetLLMPricingRule200 = {
data: LlmpricingruletypesLLMPricingRuleDTO;
/**
* @type string
*/
status: string;
};
export type ListPromotedAndIndexedPaths200 = {
/**
* @type array
@@ -7302,71 +6925,6 @@ export type GetMyServiceAccount200 = {
status: string;
};
export type ListSpanMapperGroupsParams = {
/**
* @description undefined
*/
category?: SpantypesSpanMapperGroupCategoryDTO;
/**
* @type boolean
* @nullable true
* @description undefined
*/
enabled?: boolean | null;
};
export type ListSpanMapperGroups200 = {
data: SpantypesGettableSpanMapperGroupsDTO;
/**
* @type string
*/
status: string;
};
export type CreateSpanMapperGroup201 = {
data: SpantypesSpanMapperGroupDTO;
/**
* @type string
*/
status: string;
};
export type DeleteSpanMapperGroupPathParameters = {
groupId: string;
};
export type UpdateSpanMapperGroupPathParameters = {
groupId: string;
};
export type ListSpanMappersPathParameters = {
groupId: string;
};
export type ListSpanMappers200 = {
data: SpantypesGettableSpanMapperGroupsDTO;
/**
* @type string
*/
status: string;
};
export type CreateSpanMapperPathParameters = {
groupId: string;
};
export type CreateSpanMapper201 = {
data: SpantypesSpanMapperDTO;
/**
* @type string
*/
status: string;
};
export type DeleteSpanMapperPathParameters = {
groupId: string;
mapperId: string;
};
export type UpdateSpanMapperPathParameters = {
groupId: string;
mapperId: string;
};
export type ListUsersDeprecated200 = {
/**
* @type array

View File

@@ -1,787 +0,0 @@
/**
* ! Do not edit manually
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'yarn generate:api'
* SigNoz
*/
import { useMutation, useQuery } from 'react-query';
import type {
InvalidateOptions,
MutationFunction,
QueryClient,
QueryFunction,
QueryKey,
UseMutationOptions,
UseMutationResult,
UseQueryOptions,
UseQueryResult,
} from 'react-query';
import type {
CreateSpanMapper201,
CreateSpanMapperGroup201,
CreateSpanMapperPathParameters,
DeleteSpanMapperGroupPathParameters,
DeleteSpanMapperPathParameters,
ListSpanMapperGroups200,
ListSpanMapperGroupsParams,
ListSpanMappers200,
ListSpanMappersPathParameters,
RenderErrorResponseDTO,
SpantypesPostableSpanMapperDTO,
SpantypesPostableSpanMapperGroupDTO,
SpantypesUpdatableSpanMapperDTO,
SpantypesUpdatableSpanMapperGroupDTO,
UpdateSpanMapperGroupPathParameters,
UpdateSpanMapperPathParameters,
} from '../sigNoz.schemas';
import { GeneratedAPIInstance } from '../../../generatedAPIInstance';
import type { ErrorType, BodyType } from '../../../generatedAPIInstance';
/**
* Returns all span attribute mapping groups for the authenticated org.
* @summary List span attribute mapping groups
*/
export const listSpanMapperGroups = (
params?: ListSpanMapperGroupsParams,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<ListSpanMapperGroups200>({
url: `/api/v1/span_mapper_groups`,
method: 'GET',
params,
signal,
});
};
export const getListSpanMapperGroupsQueryKey = (
params?: ListSpanMapperGroupsParams,
) => {
return [`/api/v1/span_mapper_groups`, ...(params ? [params] : [])] as const;
};
export const getListSpanMapperGroupsQueryOptions = <
TData = Awaited<ReturnType<typeof listSpanMapperGroups>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
params?: ListSpanMapperGroupsParams,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listSpanMapperGroups>>,
TError,
TData
>;
},
) => {
const { query: queryOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getListSpanMapperGroupsQueryKey(params);
const queryFn: QueryFunction<
Awaited<ReturnType<typeof listSpanMapperGroups>>
> = ({ signal }) => listSpanMapperGroups(params, signal);
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof listSpanMapperGroups>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type ListSpanMapperGroupsQueryResult = NonNullable<
Awaited<ReturnType<typeof listSpanMapperGroups>>
>;
export type ListSpanMapperGroupsQueryError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary List span attribute mapping groups
*/
export function useListSpanMapperGroups<
TData = Awaited<ReturnType<typeof listSpanMapperGroups>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
params?: ListSpanMapperGroupsParams,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listSpanMapperGroups>>,
TError,
TData
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getListSpanMapperGroupsQueryOptions(params, options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
query.queryKey = queryOptions.queryKey;
return query;
}
/**
* @summary List span attribute mapping groups
*/
export const invalidateListSpanMapperGroups = async (
queryClient: QueryClient,
params?: ListSpanMapperGroupsParams,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getListSpanMapperGroupsQueryKey(params) },
options,
);
return queryClient;
};
/**
* Creates a new span attribute mapping group for the org.
* @summary Create a span attribute mapping group
*/
export const createSpanMapperGroup = (
spantypesPostableSpanMapperGroupDTO: BodyType<SpantypesPostableSpanMapperGroupDTO>,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<CreateSpanMapperGroup201>({
url: `/api/v1/span_mapper_groups`,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
data: spantypesPostableSpanMapperGroupDTO,
signal,
});
};
export const getCreateSpanMapperGroupMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createSpanMapperGroup>>,
TError,
{ data: BodyType<SpantypesPostableSpanMapperGroupDTO> },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof createSpanMapperGroup>>,
TError,
{ data: BodyType<SpantypesPostableSpanMapperGroupDTO> },
TContext
> => {
const mutationKey = ['createSpanMapperGroup'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof createSpanMapperGroup>>,
{ data: BodyType<SpantypesPostableSpanMapperGroupDTO> }
> = (props) => {
const { data } = props ?? {};
return createSpanMapperGroup(data);
};
return { mutationFn, ...mutationOptions };
};
export type CreateSpanMapperGroupMutationResult = NonNullable<
Awaited<ReturnType<typeof createSpanMapperGroup>>
>;
export type CreateSpanMapperGroupMutationBody =
BodyType<SpantypesPostableSpanMapperGroupDTO>;
export type CreateSpanMapperGroupMutationError =
ErrorType<RenderErrorResponseDTO>;
/**
* @summary Create a span attribute mapping group
*/
export const useCreateSpanMapperGroup = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createSpanMapperGroup>>,
TError,
{ data: BodyType<SpantypesPostableSpanMapperGroupDTO> },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof createSpanMapperGroup>>,
TError,
{ data: BodyType<SpantypesPostableSpanMapperGroupDTO> },
TContext
> => {
const mutationOptions = getCreateSpanMapperGroupMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* Hard-deletes a mapping group and cascades to all its mappers.
* @summary Delete a span attribute mapping group
*/
export const deleteSpanMapperGroup = ({
groupId,
}: DeleteSpanMapperGroupPathParameters) => {
return GeneratedAPIInstance<void>({
url: `/api/v1/span_mapper_groups/${groupId}`,
method: 'DELETE',
});
};
export const getDeleteSpanMapperGroupMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteSpanMapperGroup>>,
TError,
{ pathParams: DeleteSpanMapperGroupPathParameters },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof deleteSpanMapperGroup>>,
TError,
{ pathParams: DeleteSpanMapperGroupPathParameters },
TContext
> => {
const mutationKey = ['deleteSpanMapperGroup'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof deleteSpanMapperGroup>>,
{ pathParams: DeleteSpanMapperGroupPathParameters }
> = (props) => {
const { pathParams } = props ?? {};
return deleteSpanMapperGroup(pathParams);
};
return { mutationFn, ...mutationOptions };
};
export type DeleteSpanMapperGroupMutationResult = NonNullable<
Awaited<ReturnType<typeof deleteSpanMapperGroup>>
>;
export type DeleteSpanMapperGroupMutationError =
ErrorType<RenderErrorResponseDTO>;
/**
* @summary Delete a span attribute mapping group
*/
export const useDeleteSpanMapperGroup = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteSpanMapperGroup>>,
TError,
{ pathParams: DeleteSpanMapperGroupPathParameters },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof deleteSpanMapperGroup>>,
TError,
{ pathParams: DeleteSpanMapperGroupPathParameters },
TContext
> => {
const mutationOptions = getDeleteSpanMapperGroupMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* Partially updates an existing mapping group's name, condition, or enabled state.
* @summary Update a span attribute mapping group
*/
export const updateSpanMapperGroup = (
{ groupId }: UpdateSpanMapperGroupPathParameters,
spantypesUpdatableSpanMapperGroupDTO: BodyType<SpantypesUpdatableSpanMapperGroupDTO>,
) => {
return GeneratedAPIInstance<void>({
url: `/api/v1/span_mapper_groups/${groupId}`,
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
data: spantypesUpdatableSpanMapperGroupDTO,
});
};
export const getUpdateSpanMapperGroupMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateSpanMapperGroup>>,
TError,
{
pathParams: UpdateSpanMapperGroupPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperGroupDTO>;
},
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof updateSpanMapperGroup>>,
TError,
{
pathParams: UpdateSpanMapperGroupPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperGroupDTO>;
},
TContext
> => {
const mutationKey = ['updateSpanMapperGroup'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof updateSpanMapperGroup>>,
{
pathParams: UpdateSpanMapperGroupPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperGroupDTO>;
}
> = (props) => {
const { pathParams, data } = props ?? {};
return updateSpanMapperGroup(pathParams, data);
};
return { mutationFn, ...mutationOptions };
};
export type UpdateSpanMapperGroupMutationResult = NonNullable<
Awaited<ReturnType<typeof updateSpanMapperGroup>>
>;
export type UpdateSpanMapperGroupMutationBody =
BodyType<SpantypesUpdatableSpanMapperGroupDTO>;
export type UpdateSpanMapperGroupMutationError =
ErrorType<RenderErrorResponseDTO>;
/**
* @summary Update a span attribute mapping group
*/
export const useUpdateSpanMapperGroup = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateSpanMapperGroup>>,
TError,
{
pathParams: UpdateSpanMapperGroupPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperGroupDTO>;
},
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof updateSpanMapperGroup>>,
TError,
{
pathParams: UpdateSpanMapperGroupPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperGroupDTO>;
},
TContext
> => {
const mutationOptions = getUpdateSpanMapperGroupMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* Returns all mappers belonging to a mapping group.
* @summary List span mappers for a group
*/
export const listSpanMappers = (
{ groupId }: ListSpanMappersPathParameters,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<ListSpanMappers200>({
url: `/api/v1/span_mapper_groups/${groupId}/span_mappers`,
method: 'GET',
signal,
});
};
export const getListSpanMappersQueryKey = ({
groupId,
}: ListSpanMappersPathParameters) => {
return [`/api/v1/span_mapper_groups/${groupId}/span_mappers`] as const;
};
export const getListSpanMappersQueryOptions = <
TData = Awaited<ReturnType<typeof listSpanMappers>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
{ groupId }: ListSpanMappersPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listSpanMappers>>,
TError,
TData
>;
},
) => {
const { query: queryOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getListSpanMappersQueryKey({ groupId });
const queryFn: QueryFunction<Awaited<ReturnType<typeof listSpanMappers>>> = ({
signal,
}) => listSpanMappers({ groupId }, signal);
return {
queryKey,
queryFn,
enabled: !!groupId,
...queryOptions,
} as UseQueryOptions<
Awaited<ReturnType<typeof listSpanMappers>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type ListSpanMappersQueryResult = NonNullable<
Awaited<ReturnType<typeof listSpanMappers>>
>;
export type ListSpanMappersQueryError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary List span mappers for a group
*/
export function useListSpanMappers<
TData = Awaited<ReturnType<typeof listSpanMappers>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
{ groupId }: ListSpanMappersPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listSpanMappers>>,
TError,
TData
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getListSpanMappersQueryOptions({ groupId }, options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
query.queryKey = queryOptions.queryKey;
return query;
}
/**
* @summary List span mappers for a group
*/
export const invalidateListSpanMappers = async (
queryClient: QueryClient,
{ groupId }: ListSpanMappersPathParameters,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getListSpanMappersQueryKey({ groupId }) },
options,
);
return queryClient;
};
/**
* Adds a new mapper to the specified mapping group.
* @summary Create a span mapper
*/
export const createSpanMapper = (
{ groupId }: CreateSpanMapperPathParameters,
spantypesPostableSpanMapperDTO: BodyType<SpantypesPostableSpanMapperDTO>,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<CreateSpanMapper201>({
url: `/api/v1/span_mapper_groups/${groupId}/span_mappers`,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
data: spantypesPostableSpanMapperDTO,
signal,
});
};
export const getCreateSpanMapperMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createSpanMapper>>,
TError,
{
pathParams: CreateSpanMapperPathParameters;
data: BodyType<SpantypesPostableSpanMapperDTO>;
},
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof createSpanMapper>>,
TError,
{
pathParams: CreateSpanMapperPathParameters;
data: BodyType<SpantypesPostableSpanMapperDTO>;
},
TContext
> => {
const mutationKey = ['createSpanMapper'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof createSpanMapper>>,
{
pathParams: CreateSpanMapperPathParameters;
data: BodyType<SpantypesPostableSpanMapperDTO>;
}
> = (props) => {
const { pathParams, data } = props ?? {};
return createSpanMapper(pathParams, data);
};
return { mutationFn, ...mutationOptions };
};
export type CreateSpanMapperMutationResult = NonNullable<
Awaited<ReturnType<typeof createSpanMapper>>
>;
export type CreateSpanMapperMutationBody =
BodyType<SpantypesPostableSpanMapperDTO>;
export type CreateSpanMapperMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Create a span mapper
*/
export const useCreateSpanMapper = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createSpanMapper>>,
TError,
{
pathParams: CreateSpanMapperPathParameters;
data: BodyType<SpantypesPostableSpanMapperDTO>;
},
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof createSpanMapper>>,
TError,
{
pathParams: CreateSpanMapperPathParameters;
data: BodyType<SpantypesPostableSpanMapperDTO>;
},
TContext
> => {
const mutationOptions = getCreateSpanMapperMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* Hard-deletes a mapper from a mapping group.
* @summary Delete a span mapper
*/
export const deleteSpanMapper = ({
groupId,
mapperId,
}: DeleteSpanMapperPathParameters) => {
return GeneratedAPIInstance<void>({
url: `/api/v1/span_mapper_groups/${groupId}/span_mappers/${mapperId}`,
method: 'DELETE',
});
};
export const getDeleteSpanMapperMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteSpanMapper>>,
TError,
{ pathParams: DeleteSpanMapperPathParameters },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof deleteSpanMapper>>,
TError,
{ pathParams: DeleteSpanMapperPathParameters },
TContext
> => {
const mutationKey = ['deleteSpanMapper'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof deleteSpanMapper>>,
{ pathParams: DeleteSpanMapperPathParameters }
> = (props) => {
const { pathParams } = props ?? {};
return deleteSpanMapper(pathParams);
};
return { mutationFn, ...mutationOptions };
};
export type DeleteSpanMapperMutationResult = NonNullable<
Awaited<ReturnType<typeof deleteSpanMapper>>
>;
export type DeleteSpanMapperMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Delete a span mapper
*/
export const useDeleteSpanMapper = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteSpanMapper>>,
TError,
{ pathParams: DeleteSpanMapperPathParameters },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof deleteSpanMapper>>,
TError,
{ pathParams: DeleteSpanMapperPathParameters },
TContext
> => {
const mutationOptions = getDeleteSpanMapperMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* Partially updates an existing mapper's field context, config, or enabled state.
* @summary Update a span mapper
*/
export const updateSpanMapper = (
{ groupId, mapperId }: UpdateSpanMapperPathParameters,
spantypesUpdatableSpanMapperDTO: BodyType<SpantypesUpdatableSpanMapperDTO>,
) => {
return GeneratedAPIInstance<void>({
url: `/api/v1/span_mapper_groups/${groupId}/span_mappers/${mapperId}`,
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
data: spantypesUpdatableSpanMapperDTO,
});
};
export const getUpdateSpanMapperMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateSpanMapper>>,
TError,
{
pathParams: UpdateSpanMapperPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperDTO>;
},
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof updateSpanMapper>>,
TError,
{
pathParams: UpdateSpanMapperPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperDTO>;
},
TContext
> => {
const mutationKey = ['updateSpanMapper'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof updateSpanMapper>>,
{
pathParams: UpdateSpanMapperPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperDTO>;
}
> = (props) => {
const { pathParams, data } = props ?? {};
return updateSpanMapper(pathParams, data);
};
return { mutationFn, ...mutationOptions };
};
export type UpdateSpanMapperMutationResult = NonNullable<
Awaited<ReturnType<typeof updateSpanMapper>>
>;
export type UpdateSpanMapperMutationBody =
BodyType<SpantypesUpdatableSpanMapperDTO>;
export type UpdateSpanMapperMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Update a span mapper
*/
export const useUpdateSpanMapper = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateSpanMapper>>,
TError,
{
pathParams: UpdateSpanMapperPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperDTO>;
},
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof updateSpanMapper>>,
TError,
{
pathParams: UpdateSpanMapperPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperDTO>;
},
TContext
> => {
const mutationOptions = getUpdateSpanMapperMutationOptions(options);
return useMutation(mutationOptions);
};

View File

@@ -104,7 +104,12 @@ export const usePanelContextMenu = ({
}
if (data && data?.record?.queryName) {
onClick(data.coord, { ...data.record, label: data.label, timeRange });
onClick(data.coord, {
...data.record,
label: data.label,
seriesColor: data.seriesColor,
timeRange,
});
}
},
[onClick, queryResponse],

View File

@@ -196,6 +196,7 @@ export const getUplotClickData = ({
coord: { x: number; y: number };
record: { queryName: string; filters: FilterData[] };
label: string | React.ReactNode;
seriesColor?: string;
} | null => {
if (!queryData?.queryName || !metric) {
return null;
@@ -208,6 +209,8 @@ export const getUplotClickData = ({
// Generate label from focusedSeries data
let label: string | React.ReactNode = '';
const seriesColor = focusedSeries?.color;
if (focusedSeries && focusedSeries.seriesName) {
label = (
<span style={{ color: focusedSeries.color }}>
@@ -223,6 +226,7 @@ export const getUplotClickData = ({
},
record,
label,
seriesColor,
};
};
@@ -237,6 +241,7 @@ export const getPieChartClickData = (
queryName: string;
filters: FilterData[];
label: string | React.ReactNode;
seriesColor?: string;
} | null => {
const { metric, queryName } = arc.data.record;
if (!queryName || !metric) {
@@ -248,6 +253,7 @@ export const getPieChartClickData = (
queryName,
filters: getFiltersFromMetric(metric), // TODO: add where clause query as well.
label,
seriesColor: arc.data.color,
};
};

View File

@@ -22,6 +22,7 @@ export interface AggregateData {
endTime: number;
};
label?: string | React.ReactNode;
seriesColor?: string;
}
const useAggregateDrilldown = ({

View File

@@ -228,7 +228,13 @@ const useBaseAggregateOptions = ({
return (
<ContextMenu.Item
key={key}
icon={isLoading ? <LoadingOutlined spin /> : icon}
icon={
isLoading ? (
<LoadingOutlined spin />
) : (
<span style={{ color: aggregateData?.seriesColor }}>{icon}</span>
)
}
onClick={(): void => onClick()}
disabled={isLoading}
>

View File

@@ -4,7 +4,7 @@
gap: 8px;
padding: 8px;
cursor: pointer;
color: var(--foreground);
color: var(--muted-foreground);
font-family: Inter;
font-size: var(--font-size-sm);
font-weight: 600;
@@ -20,13 +20,10 @@
overflow: hidden;
text-overflow: ellipsis;
&:hover {
background-color: var(--l1-background);
}
&:hover,
&:focus {
outline: none;
background-color: var(--l1-background);
background-color: var(--l2-background-hover);
}
&.disabled {
@@ -47,7 +44,8 @@
}
&:hover {
background-color: var(--bg-cherry-100);
background-color: var(--danger-background);
color: var(--l1-foreground);
}
}
@@ -74,73 +72,24 @@
}
.context-menu-header {
padding-bottom: 4px;
border-bottom: 1px solid var(--l1-border);
padding: 8px 12px;
border-bottom: 1px solid var(--l2-border);
color: var(--muted-foreground);
}
// Target the popover inner specifically for context menu
.context-menu .ant-popover-inner {
padding: 12px 8px !important;
// max-height: 254px !important;
max-width: 300px !important;
padding: 0;
border-radius: 6px;
max-width: 300px;
background: var(--l2-background) !important;
border: 1px solid var(--l2-border) !important;
}
// Dark mode support
.darkMode {
.context-menu-item {
color: var(--muted-foreground);
&:hover,
&:focus {
background-color: var(--l2-background);
}
&.danger {
color: var(--bg-cherry-400);
.icon {
color: var(--bg-cherry-400);
}
&:hover {
background-color: var(--danger-background);
color: var(--l1-foreground);
}
}
.icon {
color: var(--bg-robin-400);
}
}
.context-menu-header {
border-bottom: 1px solid var(--l1-border);
color: var(--muted-foreground);
}
// Set the menu popover background
.context-menu .ant-popover-inner {
background: var(--l1-background) !important;
border: 1px solid var(--border) !important;
}
}
// Context menu backdrop overlay
.context-menu-backdrop {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
inset: 0;
z-index: 9999;
background: transparent;
cursor: default;
// Prevent any pointer events from reaching elements behind
pointer-events: auto;
// Ensure it covers the entire viewport including any scrollable areas
position: fixed !important;
inset: 0;
}

2
go.mod
View File

@@ -8,7 +8,7 @@ require (
github.com/ClickHouse/clickhouse-go/v2 v2.40.1
github.com/DATA-DOG/go-sqlmock v1.5.2
github.com/SigNoz/govaluate v0.0.0-20240203125216-988004ccc7fd
github.com/SigNoz/signoz-otel-collector v0.144.3
github.com/SigNoz/signoz-otel-collector v0.144.3-rc.4
github.com/antlr4-go/antlr/v4 v4.13.1
github.com/antonmedv/expr v1.15.3
github.com/cespare/xxhash/v2 v2.3.0

4
go.sum
View File

@@ -108,8 +108,8 @@ github.com/SigNoz/expr v1.17.7-beta h1:FyZkleM5dTQ0O6muQfwGpoH5A2ohmN/XTasRCO72g
github.com/SigNoz/expr v1.17.7-beta/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4=
github.com/SigNoz/govaluate v0.0.0-20240203125216-988004ccc7fd h1:Bk43AsDYe0fhkbj57eGXx8H3ZJ4zhmQXBnrW523ktj8=
github.com/SigNoz/govaluate v0.0.0-20240203125216-988004ccc7fd/go.mod h1:nxRcH/OEdM8QxzH37xkGzomr1O0JpYBRS6pwjsWW6Pc=
github.com/SigNoz/signoz-otel-collector v0.144.3 h1:/7PPIqIpPsaWtrgnfHam2XVYP41ZlgEKLHzQO8oVxcA=
github.com/SigNoz/signoz-otel-collector v0.144.3/go.mod h1:9pLVpcIQvUT88ZiNnZN/MI+XLruvwC+Xm2UzPmGjNfA=
github.com/SigNoz/signoz-otel-collector v0.144.3-rc.4 h1:EskJkEMfuuIyArWhV8SleDV/fuKxiaEGTXrCZIFqDT4=
github.com/SigNoz/signoz-otel-collector v0.144.3-rc.4/go.mod h1:9pLVpcIQvUT88ZiNnZN/MI+XLruvwC+Xm2UzPmGjNfA=
github.com/Yiling-J/theine-go v0.6.2 h1:1GeoXeQ0O0AUkiwj2S9Jc0Mzx+hpqzmqsJ4kIC4M9AY=
github.com/Yiling-J/theine-go v0.6.2/go.mod h1:08QpMa5JZ2pKN+UJCRrCasWYO1IKCdl54Xa836rpmDU=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=

View File

@@ -1,93 +0,0 @@
package signozapiserver
import (
"net/http"
"github.com/SigNoz/signoz/pkg/http/handler"
"github.com/SigNoz/signoz/pkg/types"
"github.com/SigNoz/signoz/pkg/types/llmpricingruletypes"
"github.com/gorilla/mux"
)
func (provider *provider) addLLMPricingRuleRoutes(router *mux.Router) error {
if err := router.Handle("/api/v1/llm_pricing_rules", handler.New(
provider.authZ.ViewAccess(provider.llmPricingRuleHandler.List),
handler.OpenAPIDef{
ID: "ListLLMPricingRules",
Tags: []string{"llmpricingrules"},
Summary: "List pricing rules",
Description: "Returns all LLM pricing rules for the authenticated org, with pagination.",
Request: nil,
RequestContentType: "",
RequestQuery: new(llmpricingruletypes.ListPricingRulesQuery),
Response: new(llmpricingruletypes.GettablePricingRules),
ResponseContentType: "application/json",
SuccessStatusCode: http.StatusOK,
ErrorStatusCodes: []int{http.StatusBadRequest},
Deprecated: false,
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
},
)).Methods(http.MethodGet).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v1/llm_pricing_rules", handler.New(
provider.authZ.AdminAccess(provider.llmPricingRuleHandler.CreateOrUpdate),
handler.OpenAPIDef{
ID: "CreateOrUpdateLLMPricingRules",
Tags: []string{"llmpricingrules"},
Summary: "Create or update pricing rules",
Description: "Single write endpoint used by both the user and the Zeus sync job. Per-rule match is by id, then sourceId, then insert. Override rows (is_override=true) are fully preserved when the request does not provide isOverride; only synced_at is stamped.",
Request: new(llmpricingruletypes.UpdatableLLMPricingRules),
RequestContentType: "application/json",
SuccessStatusCode: http.StatusNoContent,
ErrorStatusCodes: []int{http.StatusBadRequest},
Deprecated: false,
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
},
)).Methods(http.MethodPut).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v1/llm_pricing_rules/{id}", handler.New(
provider.authZ.ViewAccess(provider.llmPricingRuleHandler.Get),
handler.OpenAPIDef{
ID: "GetLLMPricingRule",
Tags: []string{"llmpricingrules"},
Summary: "Get a pricing rule",
Description: "Returns a single LLM pricing rule by ID.",
Request: nil,
RequestContentType: "",
Response: new(llmpricingruletypes.GettableLLMPricingRule),
ResponseContentType: "application/json",
SuccessStatusCode: http.StatusOK,
ErrorStatusCodes: []int{http.StatusNotFound},
Deprecated: false,
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
},
)).Methods(http.MethodGet).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v1/llm_pricing_rules/{id}", handler.New(
provider.authZ.AdminAccess(provider.llmPricingRuleHandler.Delete),
handler.OpenAPIDef{
ID: "DeleteLLMPricingRule",
Tags: []string{"llmpricingrules"},
Summary: "Delete a pricing rule",
Description: "Hard-deletes a pricing rule. If auto-synced, it will be recreated on the next sync cycle.",
Request: nil,
RequestContentType: "",
Response: nil,
ResponseContentType: "",
SuccessStatusCode: http.StatusNoContent,
ErrorStatusCodes: []int{http.StatusNotFound},
Deprecated: false,
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
},
)).Methods(http.MethodDelete).GetError(); err != nil {
return err
}
return nil
}

View File

@@ -16,9 +16,8 @@ import (
"github.com/SigNoz/signoz/pkg/modules/cloudintegration"
"github.com/SigNoz/signoz/pkg/modules/dashboard"
"github.com/SigNoz/signoz/pkg/modules/fields"
"github.com/SigNoz/signoz/pkg/modules/inframonitoring"
"github.com/SigNoz/signoz/pkg/modules/llmpricingrule"
"github.com/SigNoz/signoz/pkg/modules/metricsexplorer"
"github.com/SigNoz/signoz/pkg/modules/inframonitoring"
"github.com/SigNoz/signoz/pkg/modules/organization"
"github.com/SigNoz/signoz/pkg/modules/preference"
"github.com/SigNoz/signoz/pkg/modules/promote"
@@ -26,7 +25,6 @@ import (
"github.com/SigNoz/signoz/pkg/modules/rulestatehistory"
"github.com/SigNoz/signoz/pkg/modules/serviceaccount"
"github.com/SigNoz/signoz/pkg/modules/session"
"github.com/SigNoz/signoz/pkg/modules/spanmapper"
"github.com/SigNoz/signoz/pkg/modules/tracedetail"
"github.com/SigNoz/signoz/pkg/modules/user"
"github.com/SigNoz/signoz/pkg/querier"
@@ -64,11 +62,9 @@ type provider struct {
factoryHandler factory.Handler
cloudIntegrationHandler cloudintegration.Handler
ruleStateHistoryHandler rulestatehistory.Handler
spanMapperHandler spanmapper.Handler
alertmanagerHandler alertmanager.Handler
traceDetailHandler tracedetail.Handler
rulerHandler ruler.Handler
llmPricingRuleHandler llmpricingrule.Handler
}
func NewFactory(
@@ -96,9 +92,7 @@ func NewFactory(
factoryHandler factory.Handler,
cloudIntegrationHandler cloudintegration.Handler,
ruleStateHistoryHandler rulestatehistory.Handler,
spanMapperHandler spanmapper.Handler,
alertmanagerHandler alertmanager.Handler,
llmPricingRuleHandler llmpricingrule.Handler,
traceDetailHandler tracedetail.Handler,
rulerHandler ruler.Handler,
) factory.ProviderFactory[apiserver.APIServer, apiserver.Config] {
@@ -131,9 +125,7 @@ func NewFactory(
factoryHandler,
cloudIntegrationHandler,
ruleStateHistoryHandler,
spanMapperHandler,
alertmanagerHandler,
llmPricingRuleHandler,
traceDetailHandler,
rulerHandler,
)
@@ -168,9 +160,7 @@ func newProvider(
factoryHandler factory.Handler,
cloudIntegrationHandler cloudintegration.Handler,
ruleStateHistoryHandler rulestatehistory.Handler,
spanMapperHandler spanmapper.Handler,
alertmanagerHandler alertmanager.Handler,
llmPricingRuleHandler llmpricingrule.Handler,
traceDetailHandler tracedetail.Handler,
rulerHandler ruler.Handler,
) (apiserver.APIServer, error) {
@@ -203,11 +193,9 @@ func newProvider(
factoryHandler: factoryHandler,
cloudIntegrationHandler: cloudIntegrationHandler,
ruleStateHistoryHandler: ruleStateHistoryHandler,
spanMapperHandler: spanMapperHandler,
alertmanagerHandler: alertmanagerHandler,
traceDetailHandler: traceDetailHandler,
rulerHandler: rulerHandler,
llmPricingRuleHandler: llmPricingRuleHandler,
}
provider.authZ = middleware.NewAuthZ(settings.Logger(), orgGetter, authz)
@@ -312,18 +300,10 @@ func (provider *provider) AddToRouter(router *mux.Router) error {
return err
}
if err := provider.addSpanMapperRoutes(router); err != nil {
return err
}
if err := provider.addAlertmanagerRoutes(router); err != nil {
return err
}
if err := provider.addLLMPricingRuleRoutes(router); err != nil {
return err
}
if err := provider.addTraceDetailRoutes(router); err != nil {
return err
}

View File

@@ -1,171 +0,0 @@
package signozapiserver
import (
"net/http"
"github.com/SigNoz/signoz/pkg/http/handler"
"github.com/SigNoz/signoz/pkg/types"
"github.com/SigNoz/signoz/pkg/types/spantypes"
"github.com/gorilla/mux"
)
func (provider *provider) addSpanMapperRoutes(router *mux.Router) error {
if err := router.Handle("/api/v1/span_mapper_groups", handler.New(
provider.authZ.ViewAccess(provider.spanMapperHandler.ListGroups),
handler.OpenAPIDef{
ID: "ListSpanMapperGroups",
Tags: []string{"spanmapper"},
Summary: "List span attribute mapping groups",
Description: "Returns all span attribute mapping groups for the authenticated org.",
Request: nil,
RequestContentType: "",
RequestQuery: new(spantypes.ListSpanMapperGroupsQuery),
Response: new(spantypes.GettableSpanMapperGroups),
ResponseContentType: "application/json",
SuccessStatusCode: http.StatusOK,
ErrorStatusCodes: []int{http.StatusBadRequest},
Deprecated: false,
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
},
)).Methods(http.MethodGet).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v1/span_mapper_groups", handler.New(
provider.authZ.AdminAccess(provider.spanMapperHandler.CreateGroup),
handler.OpenAPIDef{
ID: "CreateSpanMapperGroup",
Tags: []string{"spanmapper"},
Summary: "Create a span attribute mapping group",
Description: "Creates a new span attribute mapping group for the org.",
Request: new(spantypes.PostableSpanMapperGroup),
RequestContentType: "application/json",
Response: new(spantypes.GettableSpanMapperGroup),
ResponseContentType: "application/json",
SuccessStatusCode: http.StatusCreated,
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusConflict},
Deprecated: false,
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
},
)).Methods(http.MethodPost).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v1/span_mapper_groups/{groupId}", handler.New(
provider.authZ.AdminAccess(provider.spanMapperHandler.UpdateGroup),
handler.OpenAPIDef{
ID: "UpdateSpanMapperGroup",
Tags: []string{"spanmapper"},
Summary: "Update a span attribute mapping group",
Description: "Partially updates an existing mapping group's name, condition, or enabled state.",
Request: new(spantypes.UpdatableSpanMapperGroup),
RequestContentType: "application/json",
SuccessStatusCode: http.StatusNoContent,
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
Deprecated: false,
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
},
)).Methods(http.MethodPatch).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v1/span_mapper_groups/{groupId}", handler.New(
provider.authZ.AdminAccess(provider.spanMapperHandler.DeleteGroup),
handler.OpenAPIDef{
ID: "DeleteSpanMapperGroup",
Tags: []string{"spanmapper"},
Summary: "Delete a span attribute mapping group",
Description: "Hard-deletes a mapping group and cascades to all its mappers.",
Request: nil,
RequestContentType: "",
Response: nil,
ResponseContentType: "",
SuccessStatusCode: http.StatusNoContent,
ErrorStatusCodes: []int{http.StatusNotFound},
Deprecated: false,
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
},
)).Methods(http.MethodDelete).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v1/span_mapper_groups/{groupId}/span_mappers", handler.New(
provider.authZ.ViewAccess(provider.spanMapperHandler.ListMappers),
handler.OpenAPIDef{
ID: "ListSpanMappers",
Tags: []string{"spanmapper"},
Summary: "List span mappers for a group",
Description: "Returns all mappers belonging to a mapping group.",
Request: nil,
RequestContentType: "",
Response: new(spantypes.GettableSpanMapperGroups),
ResponseContentType: "application/json",
SuccessStatusCode: http.StatusOK,
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
Deprecated: false,
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
},
)).Methods(http.MethodGet).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v1/span_mapper_groups/{groupId}/span_mappers", handler.New(
provider.authZ.AdminAccess(provider.spanMapperHandler.CreateMapper),
handler.OpenAPIDef{
ID: "CreateSpanMapper",
Tags: []string{"spanmapper"},
Summary: "Create a span mapper",
Description: "Adds a new mapper to the specified mapping group.",
Request: new(spantypes.PostableSpanMapper),
RequestContentType: "application/json",
Response: new(spantypes.GettableSpanMapper),
ResponseContentType: "application/json",
SuccessStatusCode: http.StatusCreated,
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound, http.StatusConflict},
Deprecated: false,
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
},
)).Methods(http.MethodPost).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v1/span_mapper_groups/{groupId}/span_mappers/{mapperId}", handler.New(
provider.authZ.AdminAccess(provider.spanMapperHandler.UpdateMapper),
handler.OpenAPIDef{
ID: "UpdateSpanMapper",
Tags: []string{"spanmapper"},
Summary: "Update a span mapper",
Description: "Partially updates an existing mapper's field context, config, or enabled state.",
Request: new(spantypes.UpdatableSpanMapper),
RequestContentType: "application/json",
SuccessStatusCode: http.StatusNoContent,
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
Deprecated: false,
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
},
)).Methods(http.MethodPatch).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v1/span_mapper_groups/{groupId}/span_mappers/{mapperId}", handler.New(
provider.authZ.AdminAccess(provider.spanMapperHandler.DeleteMapper),
handler.OpenAPIDef{
ID: "DeleteSpanMapper",
Tags: []string{"spanmapper"},
Summary: "Delete a span mapper",
Description: "Hard-deletes a mapper from a mapping group.",
Request: nil,
RequestContentType: "",
Response: nil,
ResponseContentType: "",
SuccessStatusCode: http.StatusNoContent,
ErrorStatusCodes: []int{http.StatusNotFound},
Deprecated: false,
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
},
)).Methods(http.MethodDelete).GetError(); err != nil {
return err
}
return nil
}

View File

@@ -440,4 +440,3 @@ func (handler *handler) AgentCheckIn(rw http.ResponseWriter, r *http.Request) {
render.Success(rw, http.StatusOK, cloudintegrationtypes.NewGettableAgentCheckIn(provider, resp))
}

View File

@@ -1,158 +0,0 @@
package impllmpricingrule
import (
"context"
"net/http"
"time"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/http/binding"
"github.com/SigNoz/signoz/pkg/http/render"
"github.com/SigNoz/signoz/pkg/modules/llmpricingrule"
"github.com/SigNoz/signoz/pkg/types/authtypes"
"github.com/SigNoz/signoz/pkg/types/llmpricingruletypes"
"github.com/SigNoz/signoz/pkg/valuer"
"github.com/gorilla/mux"
)
const maxLimit = 100
type handler struct {
module llmpricingrule.Module
providerSettings factory.ProviderSettings
}
func NewHandler(module llmpricingrule.Module, providerSettings factory.ProviderSettings) llmpricingrule.Handler {
return &handler{module: module, providerSettings: providerSettings}
}
// List handles GET /api/v1/llm_pricing_rules.
func (h *handler) List(rw http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
claims, err := authtypes.ClaimsFromContext(ctx)
if err != nil {
render.Error(rw, err)
return
}
orgID := valuer.MustNewUUID(claims.OrgID)
var q llmpricingruletypes.ListPricingRulesQuery
if err := binding.Query.BindQuery(r.URL.Query(), &q); err != nil {
render.Error(rw, err)
return
}
if q.Limit <= 0 {
q.Limit = 20
} else if q.Limit > maxLimit {
q.Limit = maxLimit
}
if q.Offset < 0 {
render.Error(rw, errors.Newf(errors.TypeInvalidInput, llmpricingruletypes.ErrCodePricingRuleInvalidInput, "offset must be a non-negative integer"))
return
}
rules, total, err := h.module.List(ctx, orgID, q.Offset, q.Limit)
if err != nil {
render.Error(rw, err)
return
}
render.Success(rw, http.StatusOK, llmpricingruletypes.NewGettableLLMPricingRulesFromLLMPricingRules(rules, total, q.Offset, q.Limit))
}
// Get handles GET /api/v1/llm_pricing_rules/{id}.
func (h *handler) Get(rw http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
claims, err := authtypes.ClaimsFromContext(ctx)
if err != nil {
render.Error(rw, err)
return
}
orgID := valuer.MustNewUUID(claims.OrgID)
id, err := ruleIDFromPath(r)
if err != nil {
render.Error(rw, err)
return
}
rule, err := h.module.Get(ctx, orgID, id)
if err != nil {
render.Error(rw, err)
return
}
render.Success(rw, http.StatusOK, rule)
}
func (h *handler) CreateOrUpdate(rw http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 30*time.Second)
defer cancel()
claims, err := authtypes.ClaimsFromContext(ctx)
if err != nil {
render.Error(rw, err)
return
}
orgID := valuer.MustNewUUID(claims.OrgID)
req := new(llmpricingruletypes.UpdatableLLMPricingRules)
if err := binding.JSON.BindBody(r.Body, req); err != nil {
render.Error(rw, err)
return
}
err = h.module.CreateOrUpdate(ctx, orgID, claims.Email, req.Rules)
if err != nil {
render.Error(rw, err)
return
}
render.Success(rw, http.StatusNoContent, nil)
}
// Delete handles DELETE /api/v1/llm_pricing_rules/{id}.
func (h *handler) Delete(rw http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
claims, err := authtypes.ClaimsFromContext(ctx)
if err != nil {
render.Error(rw, err)
return
}
orgID := valuer.MustNewUUID(claims.OrgID)
id, err := ruleIDFromPath(r)
if err != nil {
render.Error(rw, err)
return
}
if err := h.module.Delete(ctx, orgID, id); err != nil {
render.Error(rw, err)
return
}
render.Success(rw, http.StatusNoContent, nil)
}
// ruleIDFromPath extracts and validates the {id} path variable.
func ruleIDFromPath(r *http.Request) (valuer.UUID, error) {
raw := mux.Vars(r)["id"]
id, err := valuer.NewUUID(raw)
if err != nil {
return valuer.UUID{}, errors.Wrapf(err, errors.TypeInvalidInput, llmpricingruletypes.ErrCodePricingRuleInvalidInput, "id is not a valid uuid")
}
return id, nil
}

View File

@@ -1,24 +0,0 @@
package llmpricingrule
import (
"context"
"net/http"
"github.com/SigNoz/signoz/pkg/types/llmpricingruletypes"
"github.com/SigNoz/signoz/pkg/valuer"
)
type Module interface {
List(ctx context.Context, orgID valuer.UUID, offset, limit int) ([]*llmpricingruletypes.LLMPricingRule, int, error)
Get(ctx context.Context, orgID valuer.UUID, id valuer.UUID) (*llmpricingruletypes.LLMPricingRule, error)
CreateOrUpdate(ctx context.Context, orgID valuer.UUID, userEmail string, rules []llmpricingruletypes.UpdatableLLMPricingRule) (err error)
Delete(ctx context.Context, orgID, id valuer.UUID) error
}
// Handler defines the HTTP handler interface for pricing rule endpoints.
type Handler interface {
List(rw http.ResponseWriter, r *http.Request)
Get(rw http.ResponseWriter, r *http.Request)
CreateOrUpdate(rw http.ResponseWriter, r *http.Request)
Delete(rw http.ResponseWriter, r *http.Request)
}

View File

@@ -32,17 +32,27 @@ func NewModule(metadataStore telemetrytypes.MetadataStore, telemetrystore teleme
}
func (m *module) ListPromotedAndIndexedPaths(ctx context.Context) ([]promotetypes.PromotePath, error) {
indexes, err := m.metadataStore.ListLogsJSONIndexes(ctx)
logsIndexes, err := m.metadataStore.ListLogsJSONIndexes(ctx)
if err != nil {
return nil, err
}
// Flatten the map values (which are slices) into a single slice
indexes := slices.Concat(slices.Collect(maps.Values(logsIndexes))...)
aggr := map[string][]promotetypes.WrappedIndex{}
for _, index := range indexes {
aggr[index.Name] = append(aggr[index.Name], promotetypes.WrappedIndex{
FieldDataType: index.FieldDataType,
Type: index.IndexType,
Granularity: index.Granularity,
path, columnType, err := schemamigrator.UnfoldJSONSubColumnIndexExpr(index.Expression)
if err != nil {
return nil, err
}
// clean backticks from the path
path = strings.ReplaceAll(path, "`", "")
aggr[path] = append(aggr[path], promotetypes.WrappedIndex{
ColumnType: columnType,
Type: index.Type,
Granularity: index.Granularity,
})
}
promotedPaths, err := m.listPromotedPaths(ctx)

View File

@@ -1,301 +0,0 @@
package implspanmapper
import (
"context"
"net/http"
"time"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/http/binding"
"github.com/SigNoz/signoz/pkg/http/render"
"github.com/SigNoz/signoz/pkg/modules/spanmapper"
"github.com/SigNoz/signoz/pkg/types/authtypes"
"github.com/SigNoz/signoz/pkg/types/spantypes"
"github.com/SigNoz/signoz/pkg/valuer"
"github.com/gorilla/mux"
)
type handler struct {
module spanmapper.Module
providerSettings factory.ProviderSettings
}
func NewHandler(module spanmapper.Module, providerSettings factory.ProviderSettings) spanmapper.Handler {
return &handler{module: module, providerSettings: providerSettings}
}
// ListGroups handles GET /api/v1/span_mapper_groups.
func (h *handler) ListGroups(rw http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
claims, err := authtypes.ClaimsFromContext(ctx)
if err != nil {
render.Error(rw, err)
return
}
orgID := valuer.MustNewUUID(claims.OrgID)
var q spantypes.ListSpanMapperGroupsQuery
if err := binding.Query.BindQuery(r.URL.Query(), &q); err != nil {
render.Error(rw, err)
return
}
groups, err := h.module.ListGroups(ctx, orgID, &q)
if err != nil {
render.Error(rw, err)
return
}
render.Success(rw, http.StatusOK, spantypes.NewGettableSpanMapperGroups(groups))
}
// CreateGroup handles POST /api/v1/span_mapper_groups.
func (h *handler) CreateGroup(rw http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
claims, err := authtypes.ClaimsFromContext(ctx)
if err != nil {
render.Error(rw, err)
return
}
orgID := valuer.MustNewUUID(claims.OrgID)
req := new(spantypes.PostableSpanMapperGroup)
if err := binding.JSON.BindBody(r.Body, req); err != nil {
render.Error(rw, err)
return
}
group := spantypes.NewSpanMapperGroupFromPostable(req)
err = h.module.CreateGroup(ctx, orgID, claims.Email, group)
if err != nil {
render.Error(rw, err)
return
}
render.Success(rw, http.StatusCreated, group)
}
// UpdateGroup handles PUT /api/v1/span_mapper_groups/{id}.
func (h *handler) UpdateGroup(rw http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
claims, err := authtypes.ClaimsFromContext(ctx)
if err != nil {
render.Error(rw, err)
return
}
orgID := valuer.MustNewUUID(claims.OrgID)
id, err := groupIDFromPath(r)
if err != nil {
render.Error(rw, err)
return
}
req := new(spantypes.UpdatableSpanMapperGroup)
if err := binding.JSON.BindBody(r.Body, req); err != nil {
render.Error(rw, err)
return
}
err = h.module.UpdateGroup(ctx, orgID, id, claims.Email, spantypes.NewSpanMapperGroupFromUpdatable(req))
if err != nil {
render.Error(rw, err)
return
}
render.Success(rw, http.StatusNoContent, nil)
}
// DeleteGroup handles DELETE /api/v1/span_mapper_groups/{id}.
func (h *handler) DeleteGroup(rw http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
claims, err := authtypes.ClaimsFromContext(ctx)
if err != nil {
render.Error(rw, err)
return
}
orgID := valuer.MustNewUUID(claims.OrgID)
id, err := groupIDFromPath(r)
if err != nil {
render.Error(rw, err)
return
}
if err := h.module.DeleteGroup(ctx, orgID, id); err != nil {
render.Error(rw, err)
return
}
render.Success(rw, http.StatusNoContent, nil)
}
// ListMappers handles GET /api/v1/span_mapper_groups/{id}/span_mappers.
func (h *handler) ListMappers(rw http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
claims, err := authtypes.ClaimsFromContext(ctx)
if err != nil {
render.Error(rw, err)
return
}
orgID := valuer.MustNewUUID(claims.OrgID)
groupID, err := groupIDFromPath(r)
if err != nil {
render.Error(rw, err)
return
}
mappers, err := h.module.ListMappers(ctx, orgID, groupID)
if err != nil {
render.Error(rw, err)
return
}
render.Success(rw, http.StatusOK, spantypes.NewGettableSpanMappers(mappers))
}
// CreateMapper handles POST /api/v1/span_mapper_groups/{id}/span_mappers.
func (h *handler) CreateMapper(rw http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
claims, err := authtypes.ClaimsFromContext(ctx)
if err != nil {
render.Error(rw, err)
return
}
orgID := valuer.MustNewUUID(claims.OrgID)
groupID, err := groupIDFromPath(r)
if err != nil {
render.Error(rw, err)
return
}
req := new(spantypes.PostableSpanMapper)
if err := binding.JSON.BindBody(r.Body, req); err != nil {
render.Error(rw, err)
return
}
mapper := spantypes.NewSpanMapperFromPostable(req)
err = h.module.CreateMapper(ctx, orgID, groupID, claims.Email, mapper)
if err != nil {
render.Error(rw, err)
return
}
render.Success(rw, http.StatusCreated, mapper)
}
// UpdateMapper handles PUT /api/v1/span_mapper_groups/{groupId}/span_mappers/{mapperId}.
func (h *handler) UpdateMapper(rw http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
claims, err := authtypes.ClaimsFromContext(ctx)
if err != nil {
render.Error(rw, err)
return
}
orgID := valuer.MustNewUUID(claims.OrgID)
groupID, err := groupIDFromPath(r)
if err != nil {
render.Error(rw, err)
return
}
mapperID, err := mapperIDFromPath(r)
if err != nil {
render.Error(rw, err)
return
}
req := new(spantypes.UpdatableSpanMapper)
if err := binding.JSON.BindBody(r.Body, req); err != nil {
render.Error(rw, err)
return
}
err = h.module.UpdateMapper(ctx, orgID, groupID, mapperID, claims.Email, spantypes.NewSpanMapperFromUpdatable(req))
if err != nil {
render.Error(rw, err)
return
}
render.Success(rw, http.StatusNoContent, nil)
}
// DeleteMapper handles DELETE /api/v1/span_mapper_groups/{groupId}/span_mappers/{mapperId}.
func (h *handler) DeleteMapper(rw http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
claims, err := authtypes.ClaimsFromContext(ctx)
if err != nil {
render.Error(rw, err)
return
}
orgID := valuer.MustNewUUID(claims.OrgID)
groupID, err := groupIDFromPath(r)
if err != nil {
render.Error(rw, err)
return
}
mapperID, err := mapperIDFromPath(r)
if err != nil {
render.Error(rw, err)
return
}
if err := h.module.DeleteMapper(ctx, orgID, groupID, mapperID); err != nil {
render.Error(rw, err)
return
}
render.Success(rw, http.StatusNoContent, nil)
}
// groupIDFromPath extracts and validates the {id} or {groupId} path variable.
func groupIDFromPath(r *http.Request) (valuer.UUID, error) {
vars := mux.Vars(r)
raw := vars["groupId"]
id, err := valuer.NewUUID(raw)
if err != nil {
return valuer.UUID{}, errors.Wrapf(err, errors.TypeInvalidInput, spantypes.ErrCodeMappingInvalidInput, "group id is not a valid uuid")
}
return id, nil
}
// mapperIDFromPath extracts and validates the {mapperId} path variable.
func mapperIDFromPath(r *http.Request) (valuer.UUID, error) {
raw := mux.Vars(r)["mapperId"]
id, err := valuer.NewUUID(raw)
if err != nil {
return valuer.UUID{}, errors.Wrapf(err, errors.TypeInvalidInput, spantypes.ErrCodeMappingInvalidInput, "mapper id is not a valid uuid")
}
return id, nil
}

View File

@@ -1,41 +0,0 @@
package spanmapper
import (
"context"
"net/http"
"github.com/SigNoz/signoz/pkg/types/spantypes"
"github.com/SigNoz/signoz/pkg/valuer"
)
// Module defines the business logic for span attribute mapping groups and mappers.
type Module interface {
// Group operations
ListGroups(ctx context.Context, orgID valuer.UUID, q *spantypes.ListSpanMapperGroupsQuery) ([]*spantypes.SpanMapperGroup, error)
GetGroup(ctx context.Context, orgID valuer.UUID, id valuer.UUID) (*spantypes.SpanMapperGroup, error)
CreateGroup(ctx context.Context, orgID valuer.UUID, createdBy string, group *spantypes.SpanMapperGroup) error
UpdateGroup(ctx context.Context, orgID valuer.UUID, id valuer.UUID, updatedBy string, group *spantypes.SpanMapperGroup) error
DeleteGroup(ctx context.Context, orgID valuer.UUID, id valuer.UUID) error
// Mapper operations
ListMappers(ctx context.Context, orgID valuer.UUID, groupID valuer.UUID) ([]*spantypes.SpanMapper, error)
GetMapper(ctx context.Context, orgID valuer.UUID, groupID valuer.UUID, id valuer.UUID) (*spantypes.SpanMapper, error)
CreateMapper(ctx context.Context, orgID valuer.UUID, groupID valuer.UUID, createdBy string, mapper *spantypes.SpanMapper) error
UpdateMapper(ctx context.Context, orgID valuer.UUID, groupID valuer.UUID, id valuer.UUID, updatedBy string, mapper *spantypes.SpanMapper) error
DeleteMapper(ctx context.Context, orgID valuer.UUID, groupID valuer.UUID, id valuer.UUID) error
}
// Handler defines the HTTP handler interface for mapping group and mapper endpoints.
type Handler interface {
// Group handlers
ListGroups(rw http.ResponseWriter, r *http.Request)
CreateGroup(rw http.ResponseWriter, r *http.Request)
UpdateGroup(rw http.ResponseWriter, r *http.Request)
DeleteGroup(rw http.ResponseWriter, r *http.Request)
// Mapper handlers
ListMappers(rw http.ResponseWriter, r *http.Request)
CreateMapper(rw http.ResponseWriter, r *http.Request)
UpdateMapper(rw http.ResponseWriter, r *http.Request)
DeleteMapper(rw http.ResponseWriter, r *http.Request)
}

View File

@@ -204,7 +204,7 @@ func AdjustKey(key *telemetrytypes.TelemetryFieldKey, keys map[string][]*telemet
// Downstream query builder should handle multiple matching keys with their own metadata
// and not rely on this function to do so.
materialized := true
indexes := []telemetrytypes.TelemetryFieldKeySkipIndex{}
indexes := []telemetrytypes.JSONDataTypeIndex{}
fieldContextsSeen := map[telemetrytypes.FieldContext]bool{}
dataTypesSeen := map[telemetrytypes.FieldDataType]bool{}
for _, matchingKey := range matchingKeys {

View File

@@ -22,8 +22,6 @@ import (
"github.com/SigNoz/signoz/pkg/modules/fields/implfields"
"github.com/SigNoz/signoz/pkg/modules/inframonitoring"
"github.com/SigNoz/signoz/pkg/modules/inframonitoring/implinframonitoring"
"github.com/SigNoz/signoz/pkg/modules/llmpricingrule"
"github.com/SigNoz/signoz/pkg/modules/llmpricingrule/impllmpricingrule"
"github.com/SigNoz/signoz/pkg/modules/metricsexplorer"
"github.com/SigNoz/signoz/pkg/modules/metricsexplorer/implmetricsexplorer"
"github.com/SigNoz/signoz/pkg/modules/quickfilter"
@@ -38,8 +36,6 @@ import (
"github.com/SigNoz/signoz/pkg/modules/serviceaccount/implserviceaccount"
"github.com/SigNoz/signoz/pkg/modules/services"
"github.com/SigNoz/signoz/pkg/modules/services/implservices"
"github.com/SigNoz/signoz/pkg/modules/spanmapper"
"github.com/SigNoz/signoz/pkg/modules/spanmapper/implspanmapper"
"github.com/SigNoz/signoz/pkg/modules/spanpercentile"
"github.com/SigNoz/signoz/pkg/modules/spanpercentile/implspanpercentile"
"github.com/SigNoz/signoz/pkg/modules/tracedetail"
@@ -75,11 +71,9 @@ type Handlers struct {
RegistryHandler factory.Handler
CloudIntegrationHandler cloudintegration.Handler
RuleStateHistory rulestatehistory.Handler
SpanMapperHandler spanmapper.Handler
AlertmanagerHandler alertmanager.Handler
TraceDetail tracedetail.Handler
RulerHandler ruler.Handler
LLMPricingRuleHandler llmpricingrule.Handler
}
func NewHandlers(
@@ -120,10 +114,8 @@ func NewHandlers(
RegistryHandler: registryHandler,
RuleStateHistory: implrulestatehistory.NewHandler(modules.RuleStateHistory),
CloudIntegrationHandler: implcloudintegration.NewHandler(modules.CloudIntegration),
SpanMapperHandler: implspanmapper.NewHandler(nil, providerSettings), // todo(nitya): will update this in future PR
AlertmanagerHandler: signozalertmanager.NewHandler(alertmanagerService),
TraceDetail: impltracedetail.NewHandler(modules.TraceDetail),
RulerHandler: signozruler.NewHandler(rulerService),
LLMPricingRuleHandler: impllmpricingrule.NewHandler(nil, providerSettings),
}
}

View File

@@ -21,9 +21,8 @@ import (
"github.com/SigNoz/signoz/pkg/modules/cloudintegration"
"github.com/SigNoz/signoz/pkg/modules/dashboard"
"github.com/SigNoz/signoz/pkg/modules/fields"
"github.com/SigNoz/signoz/pkg/modules/inframonitoring"
"github.com/SigNoz/signoz/pkg/modules/llmpricingrule"
"github.com/SigNoz/signoz/pkg/modules/metricsexplorer"
"github.com/SigNoz/signoz/pkg/modules/inframonitoring"
"github.com/SigNoz/signoz/pkg/modules/organization"
"github.com/SigNoz/signoz/pkg/modules/preference"
"github.com/SigNoz/signoz/pkg/modules/promote"
@@ -31,7 +30,6 @@ import (
"github.com/SigNoz/signoz/pkg/modules/rulestatehistory"
"github.com/SigNoz/signoz/pkg/modules/serviceaccount"
"github.com/SigNoz/signoz/pkg/modules/session"
"github.com/SigNoz/signoz/pkg/modules/spanmapper"
"github.com/SigNoz/signoz/pkg/modules/tracedetail"
"github.com/SigNoz/signoz/pkg/modules/user"
"github.com/SigNoz/signoz/pkg/querier"
@@ -76,9 +74,7 @@ func NewOpenAPI(ctx context.Context, instrumentation instrumentation.Instrumenta
struct{ factory.Handler }{},
struct{ cloudintegration.Handler }{},
struct{ rulestatehistory.Handler }{},
struct{ spanmapper.Handler }{},
struct{ alertmanager.Handler }{},
struct{ llmpricingrule.Handler }{},
struct{ tracedetail.Handler }{},
struct{ ruler.Handler }{},
).New(ctx, instrumentation.ToProviderSettings(), apiserver.Config{})

View File

@@ -281,9 +281,7 @@ func NewAPIServerProviderFactories(orgGetter organization.Getter, authz authz.Au
handlers.RegistryHandler,
handlers.CloudIntegrationHandler,
handlers.RuleStateHistory,
handlers.SpanMapperHandler,
handlers.AlertmanagerHandler,
handlers.LLMPricingRuleHandler,
handlers.TraceDetail,
handlers.RulerHandler,
),

View File

@@ -195,8 +195,8 @@ func (c *jsonConditionBuilder) buildPrimitiveTerminalCondition(node *telemetryty
// the field genuinely holds the empty/zero value.
//
// Note: indexing is also skipped for Array Nested fields because they cannot be indexed.
indexed := slices.ContainsFunc(node.TerminalConfig.Key.Indexes, func(index telemetrytypes.TelemetryFieldKeySkipIndex) bool {
return telemetrytypes.MappingFieldDataTypeToJSONDataType[index.FieldDataType] == node.TerminalConfig.ElemType
indexed := slices.ContainsFunc(node.TerminalConfig.Key.Indexes, func(index telemetrytypes.JSONDataTypeIndex) bool {
return index.Type == node.TerminalConfig.ElemType
})
isExistsCheck := operator == qbtypes.FilterOperatorExists || operator == qbtypes.FilterOperatorNotExists
if node.TerminalConfig.ElemType.IndexSupported && indexed && !isExistsCheck {

View File

@@ -1127,12 +1127,9 @@ func buildTestTelemetryMetadataStore(t *testing.T, addIndexes bool) *telemetryty
return entry.Path == path && entry.Type == jsonType
})
if idx >= 0 {
key.Indexes = append(key.Indexes, telemetrytypes.TelemetryFieldKeySkipIndex{
Name: path,
FieldContext: telemetrytypes.FieldContextBody,
FieldDataType: fdt,
BaseColumn: LogsV2BodyV2Column,
IndexExpression: schemamigrator.JSONSubColumnIndexExpr(LogsV2BodyV2Column, path, jsonType.StringValue()),
key.Indexes = append(key.Indexes, telemetrytypes.JSONDataTypeIndex{
Type: jsonType,
ColumnExpression: schemamigrator.JSONSubColumnIndexExpr(LogsV2BodyV2Column, path, jsonType.StringValue()),
})
}
}

View File

@@ -106,7 +106,7 @@ func (t *telemetryMetaStore) buildJSONPlans(keys []*telemetrytypes.TelemetryFiel
return nil
}
func (t *telemetryMetaStore) getJSONPathIndexes(ctx context.Context, paths ...string) (map[string][]telemetrytypes.TelemetryFieldKeySkipIndex, error) {
func (t *telemetryMetaStore) getJSONPathIndexes(ctx context.Context, paths ...string) (map[string][]telemetrytypes.JSONDataTypeIndex, error) {
filteredPaths := []string{}
for _, path := range paths {
// skip array paths; since they don't have any indexes
@@ -116,22 +116,47 @@ func (t *telemetryMetaStore) getJSONPathIndexes(ctx context.Context, paths ...st
filteredPaths = append(filteredPaths, path)
}
if len(filteredPaths) == 0 {
return make(map[string][]telemetrytypes.TelemetryFieldKeySkipIndex), nil
return make(map[string][]telemetrytypes.JSONDataTypeIndex), nil
}
// list indexes for the paths
indexes, err := t.ListLogsJSONIndexes(ctx, filteredPaths...)
indexesMap, err := t.ListLogsJSONIndexes(ctx, filteredPaths...)
if err != nil {
return nil, errors.WrapInternalf(err, CodeFailLoadLogsJSONIndexes, "failed to list JSON path indexes")
}
// build a set of indexes
fieldPathToIndexes := make(map[string][]telemetrytypes.TelemetryFieldKeySkipIndex)
for _, index := range indexes {
fieldPathToIndexes[index.Name] = append(fieldPathToIndexes[index.Name], index)
cleanIndexes := make(map[string][]telemetrytypes.JSONDataTypeIndex)
for path, indexes := range indexesMap {
for _, index := range indexes {
columnExpr, columnType, err := schemamigrator.UnfoldJSONSubColumnIndexExpr(index.Expression)
if err != nil {
return nil, errors.WrapInternalf(err, CodeFailLoadLogsJSONIndexes, "failed to unfold JSON sub column index expression: %s", index.Expression)
}
jsonDataType, found := telemetrytypes.MappingStringToJSONDataType[columnType]
if !found {
t.logger.ErrorContext(ctx, "failed to map column type to JSON data type", slog.String("column_type", columnType), slog.String("column_expr", columnExpr))
continue
}
if jsonDataType == telemetrytypes.String {
cleanIndexes[path] = append(cleanIndexes[path], telemetrytypes.JSONDataTypeIndex{
Type: telemetrytypes.String,
ColumnExpression: columnExpr,
IndexExpression: index.Expression,
})
} else if strings.HasPrefix(index.Type, "minmax") {
cleanIndexes[path] = append(cleanIndexes[path], telemetrytypes.JSONDataTypeIndex{
Type: jsonDataType,
ColumnExpression: columnExpr,
IndexExpression: index.Expression,
})
}
}
}
return fieldPathToIndexes, nil
return cleanIndexes, nil
}
func buildListLogsJSONIndexesQuery(cluster string, filters ...string) (string, []any) {
@@ -148,15 +173,14 @@ func buildListLogsJSONIndexesQuery(cluster string, filters ...string) (string, [
filterExprs := []string{}
for _, filter := range filters {
// Remove backticks from actual expr cuz paths from metadata doesn't have backticks
filterExprs = append(filterExprs, sb.ILike("replaceAll(expr, '`', '')", fmt.Sprintf("%%%s%%", querybuilder.FormatValueForContains(filter))))
filterExprs = append(filterExprs, sb.ILike("expr", fmt.Sprintf("%%%s%%", querybuilder.FormatValueForContains(filter))))
}
sb.Where(sb.Or(filterExprs...))
return sb.BuildWithFlavor(sqlbuilder.ClickHouse)
}
func (t *telemetryMetaStore) ListLogsJSONIndexes(ctx context.Context, filters ...string) ([]telemetrytypes.TelemetryFieldKeySkipIndex, error) {
func (t *telemetryMetaStore) ListLogsJSONIndexes(ctx context.Context, filters ...string) (map[string][]schemamigrator.Index, error) {
ctx = withTelemetryContext(ctx, "ListLogsJSONIndexes")
query, args := buildListLogsJSONIndexesQuery(t.telemetrystore.Cluster(), filters...)
rows, err := t.telemetrystore.ClickhouseDB().Query(ctx, query, args...)
@@ -165,7 +189,7 @@ func (t *telemetryMetaStore) ListLogsJSONIndexes(ctx context.Context, filters ..
}
defer rows.Close()
indexes := []telemetrytypes.TelemetryFieldKeySkipIndex{}
indexes := make(map[string][]schemamigrator.Index)
for rows.Next() {
var name string
var typeFull string
@@ -174,39 +198,11 @@ func (t *telemetryMetaStore) ListLogsJSONIndexes(ctx context.Context, filters ..
if err := rows.Scan(&name, &typeFull, &expr, &granularity); err != nil {
return nil, errors.WrapInternalf(err, CodeFailLoadLogsJSONIndexes, "failed to scan string indexed column")
}
columnExpr, columnType, err := schemamigrator.UnfoldJSONSubColumnIndexExpr(expr)
if err != nil {
return nil, errors.WrapInternalf(err, CodeFailLoadLogsJSONIndexes, "failed to unfold JSON sub column index expression: %s", expr)
}
fdt, found := telemetrytypes.MappingJSONDataTypeToFieldDataType[columnType]
if !found {
t.logger.ErrorContext(ctx, "failed to map JSON data type to field data type", slog.String("column_type", columnType), slog.String("column_expr", columnExpr))
continue
}
baseColumn := ""
fieldName := ""
switch {
case strings.HasPrefix(columnExpr, telemetrylogs.BodyV2ColumnPrefix):
baseColumn = telemetrylogs.BodyV2ColumnPrefix
fieldName = strings.TrimPrefix(columnExpr, telemetrylogs.BodyV2ColumnPrefix)
case strings.HasPrefix(columnExpr, telemetrylogs.BodyPromotedColumnPrefix):
baseColumn = telemetrylogs.BodyPromotedColumnPrefix
fieldName = strings.TrimPrefix(columnExpr, telemetrylogs.BodyPromotedColumnPrefix)
}
fieldName = strings.ReplaceAll(fieldName, "`", "")
indexes = append(indexes, telemetrytypes.TelemetryFieldKeySkipIndex{
Name: fieldName,
FieldContext: telemetrytypes.FieldContextBody,
FieldDataType: fdt,
BaseColumn: baseColumn,
IndexName: name,
IndexType: typeFull,
IndexExpression: expr,
Granularity: int(granularity),
indexes[name] = append(indexes[name], schemamigrator.Index{
Name: name,
Type: typeFull,
Expression: expr,
Granularity: int(granularity),
})
}

View File

@@ -36,7 +36,7 @@ func TestBuildListLogsJSONIndexesQuery(t *testing.T) {
cluster: "test-cluster",
filters: []string{"foo", "bar"},
expectedSQL: "SELECT name, type_full, expr, granularity FROM clusterAllReplicas('test-cluster', system.data_skipping_indices) " +
"WHERE database = ? AND table = ? AND (LOWER(expr) LIKE LOWER(?) OR LOWER(expr) LIKE LOWER(?)) AND (LOWER(replaceAll(expr, '`', '')) LIKE LOWER(?) OR LOWER(replaceAll(expr, '`', '')) LIKE LOWER(?))",
"WHERE database = ? AND table = ? AND (LOWER(expr) LIKE LOWER(?) OR LOWER(expr) LIKE LOWER(?)) AND (LOWER(expr) LIKE LOWER(?) OR LOWER(expr) LIKE LOWER(?))",
expectedArgs: []any{
telemetrylogs.DBName,
telemetrylogs.LogsV2LocalTableName,

View File

@@ -1,39 +1,5 @@
package cloudintegrationtypes
import (
"bytes"
"fmt"
"text/template"
"github.com/SigNoz/signoz/pkg/valuer"
)
var (
AgentArmTemplateStorePath = "https://signoz-integrations.s3.us-east-1.amazonaws.com/azure-arm-template-%s.json"
AgentDeploymentStackName = "signoz-integration"
// Default values for fixed ARM template parameters.
armDefaultRgName = "signoz-integration-rg"
armDefaultContainerEnvName = "signoz-integration-agent-env"
armDefaultDeploymentEnv = "production"
// ARM template parameter key names used in both CLI and PowerShell deployment commands.
armParamLocation = "location"
armParamSignozAPIKey = "signozApiKey"
armParamSignozAPIUrl = "signozApiUrl"
armParamSignozIngestionURL = "signozIngestionUrl"
armParamSignozIngestionKey = "signozIngestionKey"
armParamAccountID = "signozIntegrationAccountId"
armParamAgentVersion = "signozIntegrationAgentVersion"
armParamRgName = "rgName"
armParamContainerEnvName = "containerEnvName"
armParamDeploymentEnv = "deploymentEnv"
// command templates.
azureCLITemplate = template.Must(template.New("azureCLI").Parse(azureCLITemplateStr()))
azurePowerShellTemplate = template.Must(template.New("azurePS").Parse(azurePowerShellTemplateStr()))
)
type AzureAccountConfig struct {
DeploymentRegion string `json:"deploymentRegion" required:"true"`
ResourceGroups []string `json:"resourceGroups" required:"true" nullable:"false"`
@@ -85,36 +51,6 @@ type AzureIntegrationConfig struct {
TelemetryCollectionStrategy []*AzureTelemetryCollectionStrategy `json:"telemetryCollectionStrategy" required:"true" nullable:"false"`
}
// azureTemplateData is the data struct passed to both command templates.
// All fields are exported so text/template can access them.
type azureTemplateData struct {
// Deploy parameter values.
TemplateURL string
Location string
SignozAPIKey string
SignozAPIUrl string
SignozIngestionURL string
SignozIngestionKey string
AccountID string
AgentVersion string
// ARM parameter key names (from package-level vars).
StackName string
ParamLocation string
ParamSignozAPIKey string
ParamSignozAPIUrl string
ParamSignozIngestionURL string
ParamSignozIngestionKey string
ParamAccountID string
ParamAgentVersion string
ParamRgName string
ParamContainerEnvName string
ParamDeploymentEnv string
// Fixed default values.
DefaultRgName string
DefaultContainerEnvName string
DefaultDeploymentEnv string
}
func NewAzureIntegrationConfig(
deploymentRegion string,
resourceGroups []string,
@@ -126,105 +62,3 @@ func NewAzureIntegrationConfig(
TelemetryCollectionStrategy: strategies,
}
}
func NewAzureConnectionArtifact(
accountID valuer.UUID,
agentVersion string,
creds *Credentials,
cfg *AzurePostableAccountConfig,
) (*AzureConnectionArtifact, error) {
data := azureTemplateData{
TemplateURL: fmt.Sprintf(AgentArmTemplateStorePath, agentVersion),
Location: cfg.DeploymentRegion,
SignozAPIKey: creds.SigNozAPIKey,
SignozAPIUrl: creds.SigNozAPIURL,
SignozIngestionURL: creds.IngestionURL,
SignozIngestionKey: creds.IngestionKey,
AccountID: accountID.StringValue(),
AgentVersion: agentVersion,
StackName: AgentDeploymentStackName,
ParamLocation: armParamLocation,
ParamSignozAPIKey: armParamSignozAPIKey,
ParamSignozAPIUrl: armParamSignozAPIUrl,
ParamSignozIngestionURL: armParamSignozIngestionURL,
ParamSignozIngestionKey: armParamSignozIngestionKey,
ParamAccountID: armParamAccountID,
ParamAgentVersion: armParamAgentVersion,
ParamRgName: armParamRgName,
ParamContainerEnvName: armParamContainerEnvName,
ParamDeploymentEnv: armParamDeploymentEnv,
DefaultRgName: armDefaultRgName,
DefaultContainerEnvName: armDefaultContainerEnvName,
DefaultDeploymentEnv: armDefaultDeploymentEnv,
}
cliCommand, err := newAzureConnectionCLICommand(data)
if err != nil {
return nil, err
}
psCommand, err := newAzureConnectionPowerShellCommand(data)
if err != nil {
return nil, err
}
return &AzureConnectionArtifact{
CLICommand: cliCommand,
CloudPowerShellCommand: psCommand,
}, nil
}
func newAzureConnectionCLICommand(data azureTemplateData) (string, error) {
var buf bytes.Buffer
err := azureCLITemplate.Execute(&buf, data)
if err != nil {
return "", err
}
return buf.String(), nil
}
func newAzureConnectionPowerShellCommand(data azureTemplateData) (string, error) {
var buf bytes.Buffer
err := azurePowerShellTemplate.Execute(&buf, data)
if err != nil {
return "", err
}
return buf.String(), nil
}
func azureCLITemplateStr() string {
return `az stack sub create \
--name {{.StackName}} \
--location {{.Location}} \
--template-uri {{.TemplateURL}} \
--parameters \
{{.ParamLocation}}='{{.Location}}' \
{{.ParamSignozAPIKey}}='{{.SignozAPIKey}}' \
{{.ParamSignozAPIUrl}}='{{.SignozAPIUrl}}' \
{{.ParamSignozIngestionURL}}='{{.SignozIngestionURL}}' \
{{.ParamSignozIngestionKey}}='{{.SignozIngestionKey}}' \
{{.ParamAccountID}}='{{.AccountID}}' \
{{.ParamAgentVersion}}='{{.AgentVersion}}' \
--action-on-unmanage deleteAll \
--deny-settings-mode denyDelete`
}
func azurePowerShellTemplateStr() string {
return "New-AzSubscriptionDeploymentStack `\n" +
" -Name \"{{.StackName}}\" `\n" +
" -Location \"{{.Location}}\" `\n" +
" -TemplateUri \"{{.TemplateURL}}\" `\n" +
" -TemplateParameterObject @{\n" +
" {{.ParamLocation}} = \"{{.Location}}\"\n" +
" {{.ParamSignozAPIKey}} = \"{{.SignozAPIKey}}\"\n" +
" {{.ParamSignozAPIUrl}} = \"{{.SignozAPIUrl}}\"\n" +
" {{.ParamSignozIngestionURL}} = \"{{.SignozIngestionURL}}\"\n" +
" {{.ParamSignozIngestionKey}} = \"{{.SignozIngestionKey}}\"\n" +
" {{.ParamAccountID}} = \"{{.AccountID}}\"\n" +
" {{.ParamAgentVersion}} = \"{{.AgentVersion}}\"\n" +
" {{.ParamRgName}} = \"{{.DefaultRgName}}\"\n" +
" {{.ParamContainerEnvName}} = \"{{.DefaultContainerEnvName}}\"\n" +
" {{.ParamDeploymentEnv}} = \"{{.DefaultDeploymentEnv}}\"\n" +
" } `\n" +
" -ActionOnUnmanage \"deleteAll\" `\n" +
" -DenySettingsMode \"denyDelete\""
}

View File

@@ -1,142 +0,0 @@
// file is generated by AI
package cloudintegrationtypes
import (
"fmt"
"strings"
"testing"
"github.com/SigNoz/signoz/pkg/valuer"
)
var testTemplateData = azureTemplateData{
TemplateURL: fmt.Sprintf(AgentArmTemplateStorePath, "v0.1.0"),
Location: "eastus",
SignozAPIKey: "test-api-key",
SignozAPIUrl: "https://signoz.example.com",
SignozIngestionURL: "https://ingest.example.com",
SignozIngestionKey: "test-ingest-key",
AccountID: "acct-123",
AgentVersion: "v0.1.0",
StackName: AgentDeploymentStackName,
ParamLocation: armParamLocation,
ParamSignozAPIKey: armParamSignozAPIKey,
ParamSignozAPIUrl: armParamSignozAPIUrl,
ParamSignozIngestionURL: armParamSignozIngestionURL,
ParamSignozIngestionKey: armParamSignozIngestionKey,
ParamAccountID: armParamAccountID,
ParamAgentVersion: armParamAgentVersion,
ParamRgName: armParamRgName,
ParamContainerEnvName: armParamContainerEnvName,
ParamDeploymentEnv: armParamDeploymentEnv,
DefaultRgName: armDefaultRgName,
DefaultContainerEnvName: armDefaultContainerEnvName,
DefaultDeploymentEnv: armDefaultDeploymentEnv,
}
func TestNewAzureConnectionCLICommand(t *testing.T) {
cmd, err := newAzureConnectionCLICommand(testTemplateData)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
mustContain := []string{
"az stack sub create",
fmt.Sprintf("--name %s", AgentDeploymentStackName),
fmt.Sprintf("--location %s", testTemplateData.Location),
fmt.Sprintf("--template-uri %s", testTemplateData.TemplateURL),
fmt.Sprintf("%s='%s'", armParamLocation, testTemplateData.Location),
fmt.Sprintf("%s='%s'", armParamSignozAPIKey, testTemplateData.SignozAPIKey),
fmt.Sprintf("%s='%s'", armParamSignozAPIUrl, testTemplateData.SignozAPIUrl),
fmt.Sprintf("%s='%s'", armParamSignozIngestionURL, testTemplateData.SignozIngestionURL),
fmt.Sprintf("%s='%s'", armParamSignozIngestionKey, testTemplateData.SignozIngestionKey),
fmt.Sprintf("%s='%s'", armParamAccountID, testTemplateData.AccountID),
fmt.Sprintf("%s='%s'", armParamAgentVersion, testTemplateData.AgentVersion),
"--action-on-unmanage deleteAll",
"--deny-settings-mode denyDelete",
}
for _, fragment := range mustContain {
if !strings.Contains(cmd, fragment) {
t.Errorf("CLI command missing %q\ngot:\n%s", fragment, cmd)
}
}
// Lines must be joined with the bash line-continuation separator.
if !strings.Contains(cmd, " \\\n") {
t.Errorf("CLI command missing line-continuation separator ' \\\\\\n'\ngot:\n%s", cmd)
}
}
func TestNewAzureConnectionPowerShellCommand(t *testing.T) {
cmd, err := newAzureConnectionPowerShellCommand(testTemplateData)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
mustContain := []string{
"New-AzSubscriptionDeploymentStack",
fmt.Sprintf("-Name \"%s\"", AgentDeploymentStackName),
fmt.Sprintf("-Location \"%s\"", testTemplateData.Location),
fmt.Sprintf("-TemplateUri \"%s\"", testTemplateData.TemplateURL),
armParamLocation,
armParamSignozAPIKey,
armParamSignozAPIUrl,
armParamSignozIngestionURL,
armParamSignozIngestionKey,
armParamAccountID,
armParamAgentVersion,
armParamRgName,
armParamContainerEnvName,
armParamDeploymentEnv,
armDefaultRgName,
armDefaultContainerEnvName,
armDefaultDeploymentEnv,
"-ActionOnUnmanage \"deleteAll\"",
"-DenySettingsMode \"denyDelete\"",
}
for _, fragment := range mustContain {
if !strings.Contains(cmd, fragment) {
t.Errorf("PowerShell command missing %q\ngot:\n%s", fragment, cmd)
}
}
// Final command must not end with a line-continuation backtick.
if strings.HasSuffix(strings.TrimSpace(cmd), "`") {
t.Errorf("PowerShell command must not end with a backtick\ngot:\n%s", cmd)
}
}
func TestNewAzureConnectionArtifact(t *testing.T) {
accountID := valuer.GenerateUUID()
agentVersion := "v0.1.0"
creds := &Credentials{
SigNozAPIURL: "https://signoz.example.com",
SigNozAPIKey: "test-api-key",
IngestionURL: "https://ingest.example.com",
IngestionKey: "test-ingest-key",
}
cfg := &AzurePostableAccountConfig{
DeploymentRegion: "eastus",
ResourceGroups: []string{"rg1"},
}
artifact, err := NewAzureConnectionArtifact(accountID, agentVersion, creds, cfg)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if artifact.CLICommand == "" {
t.Error("CLICommand must not be empty")
}
if artifact.CloudPowerShellCommand == "" {
t.Error("CloudPowerShellCommand must not be empty")
}
if !strings.Contains(artifact.CLICommand, accountID.StringValue()) {
t.Errorf("CLICommand must contain accountID %q", accountID.StringValue())
}
if !strings.Contains(artifact.CloudPowerShellCommand, accountID.StringValue()) {
t.Errorf("CloudPowerShellCommand must contain accountID %q", accountID.StringValue())
}
}

View File

@@ -239,10 +239,6 @@ func (service *CloudIntegrationService) Update(provider CloudProviderType, servi
}
// other validations happen in newStorableServiceConfig
case CloudProviderTypeAzure:
if config.Azure == nil {
return errors.NewInvalidInputf(ErrCodeCloudProviderInvalidInput, "Azure config is required for Azure service")
}
default:
return errors.NewInvalidInputf(ErrCodeCloudProviderInvalidInput, "invalid cloud provider: %s", provider.StringValue())
}

View File

@@ -1,185 +0,0 @@
package llmpricingruletypes
import (
"database/sql/driver"
"encoding/json"
"time"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/types"
"github.com/SigNoz/signoz/pkg/valuer"
"github.com/uptrace/bun"
)
var (
ErrCodePricingRuleNotFound = errors.MustNewCode("pricing_rule_not_found")
ErrCodePricingRuleInvalidInput = errors.MustNewCode("pricing_rule_invalid_input")
)
type LLMPricingRuleUnit struct {
valuer.String
}
var (
UnitPerMillionTokens = LLMPricingRuleUnit{valuer.NewString("per_million_tokens")}
)
type LLMPricingRuleCacheMode struct {
valuer.String
}
var (
// LLMPricingRuleCacheModeSubtract: cached tokens are inside input_tokens (OpenAI-style).
LLMPricingRuleCacheModeSubtract = LLMPricingRuleCacheMode{valuer.NewString("subtract")}
// LLMPricingRuleCacheModeAdditive: cached tokens are reported separately (Anthropic-style).
LLMPricingRuleCacheModeAdditive = LLMPricingRuleCacheMode{valuer.NewString("additive")}
// LLMPricingRuleCacheModeUnknown: provider behaviour is unknown; falls back to subtract.
LLMPricingRuleCacheModeUnknown = LLMPricingRuleCacheMode{valuer.NewString("unknown")}
)
// StringSlice is a []string that is stored as a JSON text column.
// It is compatible with both SQLite and PostgreSQL.
type StringSlice []string
// LLMRulePricing is the per-rule pricing shape, persisted as a single JSON
type LLMRulePricing struct {
Input float64 `json:"input" required:"true"`
Output float64 `json:"output" required:"true"`
Cache *LLMPricingCacheCosts `json:"cache,omitempty"`
}
type LLMPricingCacheCosts struct {
Mode LLMPricingRuleCacheMode `json:"mode" required:"true"`
Read float64 `json:"read"`
Write float64 `json:"write"`
}
type LLMPricingRule struct {
bun.BaseModel `bun:"table:llm_pricing_rule,alias:llm_pricing_rule" json:"-"`
types.Identifiable
types.TimeAuditable
types.UserAuditable
OrgID valuer.UUID `bun:"org_id,type:text,notnull" json:"orgId" required:"true"`
SourceID *valuer.UUID `bun:"source_id,type:text" json:"sourceId,omitempty"`
Model string `bun:"model,type:text,notnull" json:"modelName" required:"true"`
Provider string `bun:"provider,type:text,notnull" json:"provider" required:"true"`
ModelPattern StringSlice `bun:"model_pattern,type:text,notnull" json:"modelPattern" required:"true"`
Unit LLMPricingRuleUnit `bun:"unit,type:text,notnull" json:"unit" required:"true"`
Pricing LLMRulePricing `bun:"pricing,type:text,notnull,default:'{}'" json:"pricing" required:"true"`
// IsOverride marks the row as user-pinned. When true, Zeus skips it entirely.
IsOverride bool `bun:"is_override,notnull,default:false" json:"isOverride" required:"true"`
SyncedAt *time.Time `bun:"synced_at" json:"syncedAt,omitempty"`
Enabled bool `bun:"enabled,notnull,default:true" json:"enabled" required:"true"`
}
type GettableLLMPricingRule = LLMPricingRule
type StorableLLMPricingRule = LLMPricingRule
// UpdatableLLMPricingRule is one entry in the bulk upsert batch.
//
// Identification:
// - ID set → match by id (user editing a known row).
// - SourceID set → match by source_id (Zeus sync, or user editing a Zeus-synced row).
// - neither set → insert a new row with source_id = NULL (user-created custom rule).
//
// IsOverride is a pointer so the caller can distinguish "not sent" from "set to false".
// When IsOverride is nil AND the matched row has is_override = true, the row is fully
// preserved — only synced_at is stamped.
type UpdatableLLMPricingRule struct {
ID *valuer.UUID `json:"id,omitempty"`
SourceID *valuer.UUID `json:"sourceId,omitempty"`
Model string `json:"modelName" required:"true"`
Provider string `json:"provider" required:"true"`
ModelPattern []string `json:"modelPattern" required:"true"`
Unit LLMPricingRuleUnit `json:"unit" required:"true"`
Pricing LLMRulePricing `json:"pricing" required:"true"`
IsOverride *bool `json:"isOverride,omitempty"`
Enabled bool `json:"enabled" required:"true"`
}
type UpdatableLLMPricingRules struct {
Rules []UpdatableLLMPricingRule `json:"rules" required:"true"`
}
type ListPricingRulesQuery struct {
Offset int `query:"offset" json:"offset"`
Limit int `query:"limit" json:"limit"`
}
type GettablePricingRules struct {
Items []*GettableLLMPricingRule `json:"items" required:"true"`
Total int `json:"total" required:"true"`
Offset int `json:"offset" required:"true"`
Limit int `json:"limit" required:"true"`
}
func (LLMPricingRuleUnit) Enum() []any {
return []any{UnitPerMillionTokens}
}
func (LLMPricingRuleCacheMode) Enum() []any {
return []any{LLMPricingRuleCacheModeSubtract, LLMPricingRuleCacheModeAdditive, LLMPricingRuleCacheModeUnknown}
}
func (s StringSlice) Value() (driver.Value, error) {
if s == nil {
return "[]", nil
}
b, err := json.Marshal(s)
if err != nil {
return nil, err
}
return string(b), nil
}
func (s *StringSlice) Scan(src any) error {
var raw []byte
switch v := src.(type) {
case string:
raw = []byte(v)
case []byte:
raw = v
case nil:
*s = nil
return nil
default:
return errors.NewInternalf(errors.CodeInternal, "llmpricingruletypes: cannot scan %T into StringSlice", src)
}
return json.Unmarshal(raw, s)
}
func (p LLMRulePricing) Value() (driver.Value, error) {
b, err := json.Marshal(p)
if err != nil {
return nil, err
}
return string(b), nil
}
func (p *LLMRulePricing) Scan(src any) error {
var raw []byte
switch v := src.(type) {
case string:
raw = []byte(v)
case []byte:
raw = v
case nil:
*p = LLMRulePricing{}
return nil
default:
return errors.NewInternalf(errors.CodeInternal, "llmpricingruletypes: cannot scan %T into LLMRulePricing", src)
}
return json.Unmarshal(raw, p)
}
func NewGettableLLMPricingRulesFromLLMPricingRules(items []*LLMPricingRule, total, offset, limit int) *GettablePricingRules {
return &GettablePricingRules{
Items: items,
Total: total,
Offset: offset,
Limit: limit,
}
}

View File

@@ -1,16 +0,0 @@
package llmpricingruletypes
import (
"context"
"github.com/SigNoz/signoz/pkg/valuer"
)
type Store interface {
List(ctx context.Context, orgID valuer.UUID, offset, limit int) ([]*StorableLLMPricingRule, int, error)
Get(ctx context.Context, orgID, id valuer.UUID) (*StorableLLMPricingRule, error)
GetBySourceID(ctx context.Context, orgID, sourceID valuer.UUID) (*StorableLLMPricingRule, error)
Create(ctx context.Context, rule *StorableLLMPricingRule) error
Update(ctx context.Context, rule *StorableLLMPricingRule) error
Delete(ctx context.Context, orgID, id valuer.UUID) error
}

View File

@@ -10,10 +10,10 @@ import (
)
type WrappedIndex struct {
JSONDataType telemetrytypes.JSONDataType `json:"-"`
FieldDataType telemetrytypes.FieldDataType `json:"fieldDataType"`
Type string `json:"type"`
Granularity int `json:"granularity"`
JSONDataType telemetrytypes.JSONDataType `json:"-"`
ColumnType string `json:"column_type"`
Type string `json:"type"`
Granularity int `json:"granularity"`
}
type PromotePath struct {
@@ -60,12 +60,12 @@ func (i *PromotePath) ValidateAndSetDefaults() error {
return errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "index granularity must be greater than 0")
}
jsonDataType, ok := telemetrytypes.MappingFieldDataTypeToJSONDataType[index.FieldDataType]
jsonDataType, ok := telemetrytypes.MappingStringToJSONDataType[index.ColumnType]
if !ok {
return errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "invalid column type: %s", index.FieldDataType)
return errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "invalid column type: %s", index.ColumnType)
}
if !jsonDataType.IndexSupported {
return errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "index is not supported for column type: %s", index.FieldDataType)
return errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "index is not supported for column type: %s", index.ColumnType)
}
i.Indexes[idx].JSONDataType = jsonDataType

View File

@@ -1,137 +0,0 @@
package spantypes
import (
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/types"
"github.com/SigNoz/signoz/pkg/valuer"
)
var (
ErrCodeMapperNotFound = errors.MustNewCode("span_attribute_mapper_not_found")
ErrCodeMapperAlreadyExists = errors.MustNewCode("span_attribute_mapper_already_exists")
ErrCodeMappingInvalidInput = errors.MustNewCode("span_attribute_mapping_invalid_input")
)
// FieldContext is where the target attribute is written.
type FieldContext struct {
valuer.String
}
var (
FieldContextSpanAttribute = FieldContext{valuer.NewString("attribute")}
FieldContextResource = FieldContext{valuer.NewString("resource")}
)
// MapperOperation determines whether the source attribute is moved (deleted) or copied.
type SpanMapperOperation struct {
valuer.String
}
var (
SpanMapperOperationMove = SpanMapperOperation{valuer.NewString("move")}
SpanMapperOperationCopy = SpanMapperOperation{valuer.NewString("copy")}
)
// MapperSource describes one candidate source for a target attribute.
type SpanMapperSource struct {
Key string `json:"key" required:"true"`
Context FieldContext `json:"context" required:"true"`
Operation SpanMapperOperation `json:"operation" required:"true"`
Priority int `json:"priority" required:"true"`
}
// MapperConfig holds the mapping logic for a single target attribute.
// It implements driver.Valuer and sql.Scanner for JSON text column storage.
type SpanMapperConfig struct {
Sources []SpanMapperSource `json:"sources" required:"true" nullable:"true"`
}
// SpanMapper is the domain model for a span attribute mapper.
type SpanMapper struct {
types.TimeAuditable
types.UserAuditable
ID valuer.UUID `json:"id" required:"true"`
GroupID valuer.UUID `json:"group_id" required:"true"`
Name string `json:"name" required:"true"`
FieldContext FieldContext `json:"field_context" required:"true"`
Config SpanMapperConfig `json:"config" required:"true"`
Enabled bool `json:"enabled" required:"true"`
}
type PostableSpanMapper struct {
Name string `json:"name" required:"true"`
FieldContext FieldContext `json:"field_context" required:"true"`
Config SpanMapperConfig `json:"config" required:"true"`
Enabled bool `json:"enabled"`
}
// UpdatableSpanMapper is the HTTP request body for updating a span mapper.
// All fields are optional; only non-nil fields are applied.
type UpdatableSpanMapper struct {
FieldContext FieldContext `json:"field_context,omitempty"`
Config *SpanMapperConfig `json:"config,omitempty"`
Enabled *bool `json:"enabled,omitempty"`
}
type GettableSpanMapper = SpanMapper
type GettableSpanMappers struct {
Items []*GettableSpanMapper `json:"items" required:"true" nullable:"false"`
}
func (FieldContext) Enum() []any {
return []any{FieldContextSpanAttribute, FieldContextResource}
}
func (SpanMapperOperation) Enum() []any {
return []any{SpanMapperOperationMove, SpanMapperOperationCopy}
}
func NewSpanMapperFromStorable(s *StorableSpanMapper) *SpanMapper {
return &SpanMapper{
TimeAuditable: s.TimeAuditable,
UserAuditable: s.UserAuditable,
ID: s.ID,
GroupID: s.GroupID,
Name: s.Name,
FieldContext: s.FieldContext,
Config: s.Config,
Enabled: s.Enabled,
}
}
func NewSpanMapperFromPostable(req *PostableSpanMapper) *SpanMapper {
return &SpanMapper{
Name: req.Name,
FieldContext: req.FieldContext,
Config: req.Config,
Enabled: req.Enabled,
}
}
func NewSpanMapperFromUpdatable(req *UpdatableSpanMapper) *SpanMapper {
m := &SpanMapper{}
if req.FieldContext != (FieldContext{}) {
m.FieldContext = req.FieldContext
}
if req.Config != nil {
m.Config = *req.Config
}
if req.Enabled != nil {
m.Enabled = *req.Enabled
}
return m
}
func NewSpanMappersFromStorableSpanMappers(ss []*StorableSpanMapper) []*SpanMapper {
mappers := make([]*SpanMapper, len(ss))
for i, s := range ss {
mappers[i] = NewSpanMapperFromStorable(s)
}
return mappers
}
func NewGettableSpanMappers(m []*SpanMapper) *GettableSpanMappers {
return &GettableSpanMappers{Items: m}
}

View File

@@ -1,109 +0,0 @@
package spantypes
import (
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/types"
"github.com/SigNoz/signoz/pkg/valuer"
)
var (
ErrCodeMappingGroupNotFound = errors.MustNewCode("span_attribute_mapping_group_not_found")
ErrCodeMappingGroupAlreadyExists = errors.MustNewCode("span_attribute_mapping_group_already_exists")
)
// SpanMapperGroupCategory defaults will be llm, tool, agent but user can configure more as they want.
type SpanMapperGroupCategory valuer.String
// A group runs when any of the listed attribute/resource key patterns match.
type SpanMapperGroupCondition struct {
Attributes []string `json:"attributes" required:"true" nullable:"true"`
Resource []string `json:"resource" required:"true" nullable:"true"`
}
// SpanMapperGroup is the domain model for a span attribute mapping group.
type SpanMapperGroup struct {
types.TimeAuditable
types.UserAuditable
ID valuer.UUID `json:"id" required:"true"`
OrgID valuer.UUID `json:"orgId" required:"true"`
Name string `json:"name" required:"true"`
Category SpanMapperGroupCategory `json:"category" required:"true"`
Condition SpanMapperGroupCondition `json:"condition" required:"true"`
Enabled bool `json:"enabled" required:"true"`
}
// GettableSpanMapperGroup is the HTTP response representation of a mapping group.
type GettableSpanMapperGroup = SpanMapperGroup
type PostableSpanMapperGroup struct {
Name string `json:"name" required:"true"`
Category SpanMapperGroupCategory `json:"category" required:"true"`
Condition SpanMapperGroupCondition `json:"condition" required:"true"`
Enabled bool `json:"enabled"`
}
// UpdatableSpanMapperGroup is the HTTP request body for updating a mapping group.
// All fields are optional; only non-nil fields are applied.
type UpdatableSpanMapperGroup struct {
Name *string `json:"name,omitempty"`
Condition *SpanMapperGroupCondition `json:"condition,omitempty"`
Enabled *bool `json:"enabled,omitempty"`
}
type ListSpanMapperGroupsQuery struct {
Category *SpanMapperGroupCategory `query:"category"`
Enabled *bool `query:"enabled"`
}
type GettableSpanMapperGroups struct {
Items []*GettableSpanMapperGroup `json:"items" required:"true" nullable:"false"`
}
func NewSpanMapperGroupFromStorable(s *StorableSpanMapperGroup) *SpanMapperGroup {
return &SpanMapperGroup{
TimeAuditable: s.TimeAuditable,
UserAuditable: s.UserAuditable,
ID: s.ID,
OrgID: s.OrgID,
Name: s.Name,
Category: s.Category,
Condition: s.Condition,
Enabled: s.Enabled,
}
}
func NewSpanMapperGroupFromPostable(p *PostableSpanMapperGroup) *SpanMapperGroup {
return &SpanMapperGroup{
Name: p.Name,
Category: p.Category,
Condition: p.Condition,
Enabled: p.Enabled,
}
}
func NewSpanMapperGroupFromUpdatable(u *UpdatableSpanMapperGroup) *SpanMapperGroup {
g := &SpanMapperGroup{}
if u.Name != nil {
g.Name = *u.Name
}
if u.Condition != nil {
g.Condition = *u.Condition
}
if u.Enabled != nil {
g.Enabled = *u.Enabled
}
return g
}
func NewSpanMapperGroupsFromStorableGroups(ss []*StorableSpanMapperGroup) []*SpanMapperGroup {
groups := make([]*SpanMapperGroup, len(ss))
for i, s := range ss {
groups[i] = NewSpanMapperGroupFromStorable(s)
}
return groups
}
func NewGettableSpanMapperGroups(g []*SpanMapperGroup) *GettableSpanMapperGroups {
return &GettableSpanMapperGroups{Items: g}
}

View File

@@ -1,87 +0,0 @@
package spantypes
import (
"database/sql/driver"
"encoding/json"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/types"
"github.com/SigNoz/signoz/pkg/valuer"
"github.com/uptrace/bun"
)
type StorableSpanMapperGroup struct {
bun.BaseModel `bun:"table:span_mapper_group,alias:span_attribute_mapping_group"`
types.Identifiable
types.TimeAuditable
types.UserAuditable
OrgID valuer.UUID `bun:"org_id,type:text,notnull"`
Name string `bun:"name,type:text,notnull"`
Category SpanMapperGroupCategory `bun:"category,type:text,notnull"`
Condition SpanMapperGroupCondition `bun:"condition,type:jsonb,notnull"`
Enabled bool `bun:"enabled,notnull,default:true"`
}
type StorableSpanMapper struct {
bun.BaseModel `bun:"table:span_mapper,alias:span_attribute_mapping"`
types.Identifiable
types.TimeAuditable
types.UserAuditable
GroupID valuer.UUID `bun:"group_id,type:text,notnull"`
Name string `bun:"name,type:text,notnull"`
FieldContext FieldContext `bun:"field_context,type:text,notnull"`
Config SpanMapperConfig `bun:"config,type:jsonb,notnull"`
Enabled bool `bun:"enabled,notnull,default:true"`
}
func (c SpanMapperGroupCondition) Value() (driver.Value, error) {
b, err := json.Marshal(c)
if err != nil {
return nil, err
}
return string(b), nil
}
func (c *SpanMapperGroupCondition) Scan(src any) error {
var raw []byte
switch v := src.(type) {
case string:
raw = []byte(v)
case []byte:
raw = v
case nil:
*c = SpanMapperGroupCondition{}
return nil
default:
return errors.NewInternalf(errors.CodeInternal, "spanmapper: cannot scan %T into Condition", src)
}
return json.Unmarshal(raw, c)
}
func (m SpanMapperConfig) Value() (driver.Value, error) {
b, err := json.Marshal(m)
if err != nil {
return nil, err
}
return string(b), nil
}
func (m *SpanMapperConfig) Scan(src any) error {
var raw []byte
switch v := src.(type) {
case string:
raw = []byte(v)
case []byte:
raw = v
case nil:
*m = SpanMapperConfig{}
return nil
default:
return errors.NewInternalf(errors.CodeInternal, "spanmapper: cannot scan %T into MapperConfig", src)
}
return json.Unmarshal(raw, m)
}

View File

@@ -1,23 +0,0 @@
package spantypes
import (
"context"
"github.com/SigNoz/signoz/pkg/valuer"
)
type Store interface {
// Group operations
ListSpanMapperGroups(ctx context.Context, orgID valuer.UUID, q *ListSpanMapperGroupsQuery) ([]*StorableSpanMapperGroup, error)
GetSpanMapperGroup(ctx context.Context, orgID, id valuer.UUID) (*StorableSpanMapperGroup, error)
CreateSpanMapperGroup(ctx context.Context, group *StorableSpanMapperGroup) error
UpdateSpanMapperGroup(ctx context.Context, group *StorableSpanMapperGroup) error
DeleteSpanMapperGroup(ctx context.Context, orgID, id valuer.UUID) error
// Mapper operations
ListSpanMappers(ctx context.Context, orgID, groupID valuer.UUID) ([]*StorableSpanMapper, error)
GetSpanMapper(ctx context.Context, orgID, groupID, id valuer.UUID) (*StorableSpanMapper, error)
CreateSpanMapper(ctx context.Context, mapper *StorableSpanMapper) error
UpdateSpanMapper(ctx context.Context, mapper *StorableSpanMapper) error
DeleteSpanMapper(ctx context.Context, orgID, groupID, id valuer.UUID) error
}

View File

@@ -37,9 +37,9 @@ type TelemetryFieldKey struct {
FieldContext FieldContext `json:"fieldContext,omitzero"`
FieldDataType FieldDataType `json:"fieldDataType,omitzero"`
JSONPlan JSONAccessPlan `json:"-"`
Indexes []TelemetryFieldKeySkipIndex `json:"-"`
Materialized bool `json:"-"` // refers to promoted in case of body.... fields
JSONPlan JSONAccessPlan `json:"-"`
Indexes []JSONDataTypeIndex `json:"-"`
Materialized bool `json:"-"` // refers to promoted in case of body.... fields
Evolutions []*EvolutionEntry `json:"-"`
}
@@ -102,7 +102,7 @@ func (f TelemetryFieldKey) String() string {
if i > 0 {
sb.WriteString("; ")
}
fmt.Fprintf(&sb, "{type=%s, indexExpr=%s}", MappingFieldDataTypeToJSONDataType[index.FieldDataType].StringValue(), index.IndexExpression)
fmt.Fprintf(&sb, "{type=%s, columnExpr=%s, indexExpr=%s}", index.Type.StringValue(), index.ColumnExpression, index.IndexExpression)
}
sb.WriteString("]")
}
@@ -400,14 +400,3 @@ func NewFieldValueSelectorFromPostableFieldValueParams(params PostableFieldValue
return fieldValueSelector
}
type TelemetryFieldKeySkipIndex struct {
Name string `json:"name"` // Name is TelemetryFieldKey.Name not IndexName from ClickHouse
FieldContext FieldContext `json:"fieldContext,omitzero"`
FieldDataType FieldDataType `json:"fieldDataType,omitzero"`
BaseColumn string `json:"baseColumn"`
IndexName string `json:"indexName"`
IndexType string `json:"indexType"`
IndexExpression string `json:"indexExpression"`
Granularity int `json:"granularity"`
}

View File

@@ -1,5 +1,11 @@
package telemetrytypes
type JSONDataTypeIndex struct {
Type JSONDataType
ColumnExpression string
IndexExpression string
}
type JSONDataType struct {
str string // Store the correct case for ClickHouse
IsArray bool
@@ -26,17 +32,18 @@ var (
ArrayJSON = JSONDataType{"Array(JSON)", true, "JSON", false}
)
var MappingJSONDataTypeToFieldDataType = map[string]FieldDataType{
"String": FieldDataTypeString,
"Int64": FieldDataTypeInt64,
"Float64": FieldDataTypeFloat64,
"Bool": FieldDataTypeBool,
"Array(Nullable(String))": FieldDataTypeArrayString,
"Array(Nullable(Int64))": FieldDataTypeArrayInt64,
"Array(Nullable(Float64))": FieldDataTypeArrayFloat64,
"Array(Nullable(Bool))": FieldDataTypeArrayBool,
"Array(Dynamic)": FieldDataTypeArrayDynamic,
"Array(JSON)": FieldDataTypeArrayJSON,
var MappingStringToJSONDataType = map[string]JSONDataType{
"String": String,
"Int64": Int64,
"Float64": Float64,
"Bool": Bool,
"Dynamic": Dynamic,
"Array(Nullable(String))": ArrayString,
"Array(Nullable(Int64))": ArrayInt64,
"Array(Nullable(Float64))": ArrayFloat64,
"Array(Nullable(Bool))": ArrayBool,
"Array(Dynamic)": ArrayDynamic,
"Array(JSON)": ArrayJSON,
}
var MappingFieldDataTypeToJSONDataType = map[FieldDataType]JSONDataType{

View File

@@ -3,6 +3,7 @@ package telemetrytypes
import (
"context"
schemamigrator "github.com/SigNoz/signoz-otel-collector/cmd/signozschemamigrator/schema_migrator"
"github.com/SigNoz/signoz/pkg/types/metrictypes"
)
@@ -34,7 +35,7 @@ type MetadataStore interface {
FetchTemporalityAndTypeMulti(ctx context.Context, queryTimeRangeStartTs, queryTimeRangeEndTs uint64, metricNames ...string) (map[string]metrictypes.Temporality, map[string]metrictypes.Type, error)
// ListLogsJSONIndexes lists the JSON indexes for the logs table.
ListLogsJSONIndexes(ctx context.Context, filters ...string) ([]TelemetryFieldKeySkipIndex, error)
ListLogsJSONIndexes(ctx context.Context, filters ...string) (map[string][]schemamigrator.Index, error)
// ListPromotedPaths lists the promoted paths.
GetPromotedPaths(ctx context.Context, paths ...string) (map[string]bool, error)

View File

@@ -4,6 +4,7 @@ import (
"context"
"strings"
schemamigrator "github.com/SigNoz/signoz-otel-collector/cmd/signozschemamigrator/schema_migrator"
"github.com/SigNoz/signoz/pkg/types/metrictypes"
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
)
@@ -17,7 +18,7 @@ type MockMetadataStore struct {
TemporalityMap map[string]metrictypes.Temporality
TypeMap map[string]metrictypes.Type
PromotedPathsMap map[string]bool
LogsJSONIndexes []telemetrytypes.TelemetryFieldKeySkipIndex
LogsJSONIndexesMap map[string][]schemamigrator.Index
ColumnEvolutionMetadataMap map[string][]*telemetrytypes.EvolutionEntry
LookupKeysMap map[telemetrytypes.MetricMetadataLookupKey]int64
// StaticFields holds signal-specific intrinsic field definitions (e.g. telemetrylogs.IntrinsicFields).
@@ -33,7 +34,7 @@ func NewMockMetadataStore() *MockMetadataStore {
TemporalityMap: make(map[string]metrictypes.Temporality),
TypeMap: make(map[string]metrictypes.Type),
PromotedPathsMap: make(map[string]bool),
LogsJSONIndexes: []telemetrytypes.TelemetryFieldKeySkipIndex{},
LogsJSONIndexesMap: make(map[string][]schemamigrator.Index),
ColumnEvolutionMetadataMap: make(map[string][]*telemetrytypes.EvolutionEntry),
LookupKeysMap: make(map[telemetrytypes.MetricMetadataLookupKey]int64),
StaticFields: make(map[string]telemetrytypes.TelemetryFieldKey),
@@ -368,8 +369,8 @@ func (m *MockMetadataStore) GetPromotedPaths(ctx context.Context, paths ...strin
}
// ListLogsJSONIndexes lists the JSON indexes for the logs table.
func (m *MockMetadataStore) ListLogsJSONIndexes(ctx context.Context, filters ...string) ([]telemetrytypes.TelemetryFieldKeySkipIndex, error) {
return m.LogsJSONIndexes, nil
func (m *MockMetadataStore) ListLogsJSONIndexes(ctx context.Context, filters ...string) (map[string][]schemamigrator.Index, error) {
return m.LogsJSONIndexesMap, nil
}
func (m *MockMetadataStore) updateColumnEvolutionMetadataForKeys(_ context.Context, keysToUpdate []*telemetrytypes.TelemetryFieldKey) map[string][]*telemetrytypes.EvolutionEntry {