Skip to content

Commit 06ae1e1

Browse files
authored
Merge branch 'main' into add-tooltips
2 parents b3cf538 + 1dfebed commit 06ae1e1

File tree

84 files changed

+4131
-715
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+4131
-715
lines changed

ee/http/middleware/pat.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ func (p *Pat) Wrap(next http.Handler) http.Handler {
2525
var values []string
2626
var patToken string
2727
var pat types.StorablePersonalAccessToken
28-
var updateLastUsed bool
2928

3029
for _, header := range p.headers {
3130
values = append(values, r.Header.Get(header))
@@ -74,13 +73,10 @@ func (p *Pat) Wrap(next http.Handler) http.Handler {
7473

7574
next.ServeHTTP(w, r)
7675

77-
// update last used only if SIGNOZ-API-KEY was present and successful
78-
if updateLastUsed {
79-
pat.LastUsed = time.Now().Unix()
80-
_, err = p.db.NewUpdate().Model(&pat).Column("last_used").Where("token = ?", patToken).Where("revoked = false").Exec(r.Context())
81-
if err != nil {
82-
zap.L().Error("Failed to update PAT last used in db, err: %v", zap.Error(err))
83-
}
76+
pat.LastUsed = time.Now().Unix()
77+
_, err = p.db.NewUpdate().Model(&pat).Column("last_used").Where("token = ?", patToken).Where("revoked = false").Exec(r.Context())
78+
if err != nil {
79+
zap.L().Error("Failed to update PAT last used in db, err: %v", zap.Error(err))
8480
}
8581

8682
})

ee/query-service/app/server.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
217217

218218
// ingestion pipelines manager
219219
logParsingPipelineController, err := logparsingpipeline.NewLogParsingPipelinesController(
220-
serverOptions.SigNoz.SQLStore.SQLxDB(), integrationsController.GetPipelinesForInstalledIntegrations,
220+
serverOptions.SigNoz.SQLStore, integrationsController.GetPipelinesForInstalledIntegrations,
221221
)
222222
if err != nil {
223223
return nil, err
@@ -385,6 +385,7 @@ func (s *Server) createPublicServer(apiHandler *api.APIHandler, web web.Web) (*h
385385
apiHandler.RegisterMessagingQueuesRoutes(r, am)
386386
apiHandler.RegisterThirdPartyApiRoutes(r, am)
387387
apiHandler.MetricExplorerRoutes(r, am)
388+
apiHandler.RegisterTraceFunnelsRoutes(r, am)
388389

389390
c := cors.New(cors.Options{
390391
AllowedOrigins: []string{"*"},

ee/query-service/main.go

Lines changed: 4 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ package main
33
import (
44
"context"
55
"flag"
6-
"log"
76
"os"
8-
"os/signal"
9-
"strconv"
107
"time"
118

129
"github.com/SigNoz/signoz/ee/query-service/app"
@@ -18,67 +15,19 @@ import (
1815
"github.com/SigNoz/signoz/pkg/query-service/version"
1916
"github.com/SigNoz/signoz/pkg/signoz"
2017
"github.com/SigNoz/signoz/pkg/types/authtypes"
21-
"go.opentelemetry.io/otel/sdk/resource"
22-
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
23-
"google.golang.org/grpc"
24-
"google.golang.org/grpc/credentials/insecure"
2518

2619
prommodel "github.com/prometheus/common/model"
2720

28-
zapotlpencoder "github.com/SigNoz/zap_otlp/zap_otlp_encoder"
29-
zapotlpsync "github.com/SigNoz/zap_otlp/zap_otlp_sync"
30-
3121
"go.uber.org/zap"
3222
"go.uber.org/zap/zapcore"
3323
)
3424

35-
func initZapLog(enableQueryServiceLogOTLPExport bool) *zap.Logger {
25+
func initZapLog() *zap.Logger {
3626
config := zap.NewProductionConfig()
37-
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
38-
defer stop()
39-
40-
config.EncoderConfig.EncodeDuration = zapcore.MillisDurationEncoder
41-
config.EncoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
27+
config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
4228
config.EncoderConfig.TimeKey = "timestamp"
4329
config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
44-
45-
otlpEncoder := zapotlpencoder.NewOTLPEncoder(config.EncoderConfig)
46-
consoleEncoder := zapcore.NewJSONEncoder(config.EncoderConfig)
47-
defaultLogLevel := zapcore.InfoLevel
48-
49-
res := resource.NewWithAttributes(
50-
semconv.SchemaURL,
51-
semconv.ServiceNameKey.String("query-service"),
52-
)
53-
54-
core := zapcore.NewTee(
55-
zapcore.NewCore(consoleEncoder, os.Stdout, defaultLogLevel),
56-
)
57-
58-
if enableQueryServiceLogOTLPExport {
59-
ctx, cancel := context.WithTimeout(ctx, time.Second*30)
60-
defer cancel()
61-
conn, err := grpc.DialContext(ctx, baseconst.OTLPTarget, grpc.WithBlock(), grpc.WithTransportCredentials(insecure.NewCredentials()))
62-
if err != nil {
63-
log.Fatalf("failed to establish connection: %v", err)
64-
} else {
65-
logExportBatchSizeInt, err := strconv.Atoi(baseconst.LogExportBatchSize)
66-
if err != nil {
67-
logExportBatchSizeInt = 512
68-
}
69-
ws := zapcore.AddSync(zapotlpsync.NewOtlpSyncer(conn, zapotlpsync.Options{
70-
BatchSize: logExportBatchSizeInt,
71-
ResourceSchema: semconv.SchemaURL,
72-
Resource: res,
73-
}))
74-
core = zapcore.NewTee(
75-
zapcore.NewCore(consoleEncoder, os.Stdout, defaultLogLevel),
76-
zapcore.NewCore(otlpEncoder, zapcore.NewMultiWriteSyncer(ws), defaultLogLevel),
77-
)
78-
}
79-
}
80-
logger := zap.New(core, zap.AddCaller(), zap.AddStacktrace(zapcore.ErrorLevel))
81-
30+
logger, _ := config.Build()
8231
return logger
8332
}
8433

@@ -99,7 +48,6 @@ func main() {
9948
var useLogsNewSchema bool
10049
var useTraceNewSchema bool
10150
var cacheConfigPath, fluxInterval, fluxIntervalForTraceDetail string
102-
var enableQueryServiceLogOTLPExport bool
10351
var preferSpanMetrics bool
10452

10553
var maxIdleConns int
@@ -121,14 +69,12 @@ func main() {
12169
flag.StringVar(&cacheConfigPath, "experimental.cache-config", "", "(cache config to use)")
12270
flag.StringVar(&fluxInterval, "flux-interval", "5m", "(the interval to exclude data from being cached to avoid incorrect cache for data in motion)")
12371
flag.StringVar(&fluxIntervalForTraceDetail, "flux-interval-trace-detail", "2m", "(the interval to exclude data from being cached to avoid incorrect cache for trace data in motion)")
124-
flag.BoolVar(&enableQueryServiceLogOTLPExport, "enable.query.service.log.otlp.export", false, "(enable query service log otlp export)")
12572
flag.StringVar(&cluster, "cluster", "cluster", "(cluster name - defaults to 'cluster')")
12673
flag.StringVar(&gatewayUrl, "gateway-url", "", "(url to the gateway)")
12774
flag.BoolVar(&useLicensesV3, "use-licenses-v3", false, "use licenses_v3 schema for licenses")
12875
flag.Parse()
12976

130-
loggerMgr := initZapLog(enableQueryServiceLogOTLPExport)
131-
77+
loggerMgr := initZapLog()
13278
zap.ReplaceGlobals(loggerMgr)
13379
defer loggerMgr.Sync() // flushes buffer, if any
13480

frontend/public/locales/en/titles.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
"SUPPORT": "SigNoz | Support",
5555
"LOGS_SAVE_VIEWS": "SigNoz | Logs Saved Views",
5656
"TRACES_SAVE_VIEWS": "SigNoz | Traces Saved Views",
57+
"TRACES_FUNNELS": "SigNoz | Traces Funnels",
5758
"DEFAULT": "Open source Observability Platform | SigNoz",
5859
"SHORTCUTS": "SigNoz | Shortcuts",
5960
"INTEGRATIONS": "SigNoz | Integrations",

frontend/src/AppRoutes/pageComponents.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,17 @@ export const TracesSaveViews = Loadable(
4242
import(/* webpackChunkName: "Traces Save Views" */ 'pages/TracesModulePage'),
4343
);
4444

45+
export const TracesFunnels = Loadable(
46+
() =>
47+
import(/* webpackChunkName: "Traces Funnels" */ 'pages/TracesModulePage'),
48+
);
49+
export const TracesFunnelDetails = Loadable(
50+
() =>
51+
import(
52+
/* webpackChunkName: "Traces Funnel Details" */ 'pages/TracesFunnelDetails'
53+
),
54+
);
55+
4556
export const TraceFilter = Loadable(
4657
() => import(/* webpackChunkName: "Trace Filter Page" */ 'pages/Trace'),
4758
);

frontend/src/AppRoutes/routes.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ import {
5252
TraceDetail,
5353
TraceFilter,
5454
TracesExplorer,
55+
TracesFunnelDetails,
56+
TracesFunnels,
5557
TracesSaveViews,
5658
UnAuthorized,
5759
UsageExplorerPage,
@@ -236,6 +238,20 @@ const routes: AppRoutes[] = [
236238
isPrivate: true,
237239
key: 'TRACES_SAVE_VIEWS',
238240
},
241+
{
242+
path: ROUTES.TRACES_FUNNELS,
243+
exact: true,
244+
component: TracesFunnels,
245+
isPrivate: true,
246+
key: 'TRACES_FUNNELS',
247+
},
248+
{
249+
path: ROUTES.TRACES_FUNNELS_DETAIL,
250+
exact: true,
251+
component: TracesFunnelDetails,
252+
isPrivate: true,
253+
key: 'TRACES_FUNNELS_DETAIL',
254+
},
239255
{
240256
path: ROUTES.CHANNELS_NEW,
241257
exact: true,
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import axios from 'api';
2+
import { AxiosResponse } from 'axios';
3+
import { ErrorResponse, SuccessResponse } from 'types/api';
4+
import {
5+
CreateFunnelPayload,
6+
CreateFunnelResponse,
7+
FunnelData,
8+
} from 'types/api/traceFunnels';
9+
10+
const FUNNELS_BASE_PATH = '/trace-funnels';
11+
12+
export const createFunnel = async (
13+
payload: CreateFunnelPayload,
14+
): Promise<SuccessResponse<CreateFunnelResponse> | ErrorResponse> => {
15+
const response: AxiosResponse = await axios.post(
16+
`${FUNNELS_BASE_PATH}/new-funnel`,
17+
payload,
18+
);
19+
20+
return {
21+
statusCode: 200,
22+
error: null,
23+
message: 'Funnel created successfully',
24+
payload: response.data,
25+
};
26+
};
27+
28+
interface GetFunnelsListParams {
29+
search?: string;
30+
}
31+
32+
export const getFunnelsList = async ({
33+
search = '',
34+
}: GetFunnelsListParams = {}): Promise<
35+
SuccessResponse<FunnelData[]> | ErrorResponse
36+
> => {
37+
const params = new URLSearchParams();
38+
if (search.length) {
39+
params.set('search', search);
40+
}
41+
42+
const response: AxiosResponse = await axios.get(
43+
`${FUNNELS_BASE_PATH}/list${
44+
params.toString() ? `?${params.toString()}` : ''
45+
}`,
46+
);
47+
48+
return {
49+
statusCode: 200,
50+
error: null,
51+
message: '',
52+
payload: response.data,
53+
};
54+
};
55+
56+
export const getFunnelById = async (
57+
funnelId: string,
58+
): Promise<SuccessResponse<FunnelData> | ErrorResponse> => {
59+
const response: AxiosResponse = await axios.get(
60+
`${FUNNELS_BASE_PATH}/get/${funnelId}`,
61+
);
62+
63+
return {
64+
statusCode: 200,
65+
error: null,
66+
message: '',
67+
payload: response.data,
68+
};
69+
};
70+
71+
interface RenameFunnelPayload {
72+
id: string;
73+
funnel_name: string;
74+
}
75+
76+
export const renameFunnel = async (
77+
payload: RenameFunnelPayload,
78+
): Promise<SuccessResponse<FunnelData> | ErrorResponse> => {
79+
const response: AxiosResponse = await axios.put(
80+
`${FUNNELS_BASE_PATH}/${payload.id}/update`,
81+
{ funnel_name: payload.funnel_name },
82+
);
83+
84+
return {
85+
statusCode: 200,
86+
error: null,
87+
message: 'Funnel renamed successfully',
88+
payload: response.data,
89+
};
90+
};
91+
92+
interface DeleteFunnelPayload {
93+
id: string;
94+
}
95+
96+
export const deleteFunnel = async (
97+
payload: DeleteFunnelPayload,
98+
): Promise<SuccessResponse<FunnelData> | ErrorResponse> => {
99+
const response: AxiosResponse = await axios.delete(
100+
`${FUNNELS_BASE_PATH}/delete/${payload.id}`,
101+
);
102+
103+
return {
104+
statusCode: 200,
105+
error: null,
106+
message: 'Funnel deleted successfully',
107+
payload: response.data,
108+
};
109+
};
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
.learn-more {
2+
display: flex;
3+
align-items: center;
4+
gap: 4px;
5+
padding: 0;
6+
font-family: Inter;
7+
font-size: 14px;
8+
font-weight: 500;
9+
line-height: 18px; /* 128.571% */
10+
letter-spacing: -0.07px;
11+
&,&:hover {
12+
color: var(--bg-robin-400) !important;
13+
}
14+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import './LearnMore.styles.scss';
2+
3+
import { Color } from '@signozhq/design-tokens';
4+
import { Button } from 'antd';
5+
import { ArrowUpRight } from 'lucide-react';
6+
7+
type LearnMoreProps = {
8+
text?: string;
9+
url?: string;
10+
onClick?: () => void;
11+
};
12+
13+
function LearnMore({ text, url, onClick }: LearnMoreProps): JSX.Element {
14+
const handleClick = (): void => {
15+
onClick?.();
16+
if (url) {
17+
window.open(url, '_blank');
18+
}
19+
};
20+
return (
21+
<Button type="link" className="learn-more" onClick={handleClick}>
22+
<div className="learn-more__text">{text}</div>
23+
<ArrowUpRight size={16} color={Color.BG_ROBIN_400} />
24+
</Button>
25+
);
26+
}
27+
28+
LearnMore.defaultProps = {
29+
text: 'Learn more',
30+
url: '',
31+
onClick: (): void => {},
32+
};
33+
34+
export default LearnMore;

frontend/src/components/SignozModal/SignozModal.style.scss

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,17 @@
6767
background: var(--bg-ink-300);
6868
}
6969
}
70+
71+
.ant-modal-footer {
72+
.ant-btn {
73+
display: flex;
74+
align-items: center;
75+
gap: 4px;
76+
&-icon {
77+
margin: 0 !important;
78+
}
79+
}
80+
}
7081
}
7182

7283
.lightMode {

0 commit comments

Comments
 (0)