Skip to content

Commit 51c7fb3

Browse files
authored
Merge pull request #6 from noyitz/main
real-time observability data (istio logs and prometheus)
2 parents c6964be + 10490b6 commit 51c7fb3

File tree

14 files changed

+2572
-269
lines changed

14 files changed

+2572
-269
lines changed

apps/backend/src/app.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import { logger } from './utils/logger';
44
import metricsRoutes from './routes/metrics';
55
import policiesRoutes from './routes/policies';
66

7-
const app = express();
8-
const PORT = process.env.PORT || 3001;
7+
const app: express.Application = express();
8+
const PORT = process.env.PORT || 3002;
99

1010
// Middleware
1111
app.use(cors({

apps/backend/src/routes/metrics.ts

Lines changed: 151 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import express from 'express';
22
import { MetricsService } from '../services/metricsService';
33
import { logger } from '../utils/logger';
44

5-
const router = express.Router();
5+
const router: express.Router = express.Router();
66
const metricsService = new MetricsService();
77

88
// Get live requests with policy enforcement data
@@ -23,30 +23,168 @@ router.get('/live-requests', async (req, res) => {
2323
}
2424
});
2525

26-
// Get dashboard statistics
27-
router.get('/dashboard', async (req, res) => {
26+
// Get detailed request information by ID
27+
router.get('/requests/:id', async (req, res) => {
2828
try {
29-
const status = await metricsService.getMetricsStatus();
29+
const { id } = req.params;
3030
const requests = await metricsService.getRealLiveRequests();
31+
const request = requests.find(r => r.id === id);
3132

32-
const totalRequests = requests.length;
33-
const acceptedRequests = requests.filter(r => r.decision === 'accept').length;
34-
const rejectedRequests = requests.filter(r => r.decision === 'reject').length;
35-
const policyEnforcedRequests = requests.filter(r => r.policyType && r.policyType !== 'None').length;
33+
if (!request) {
34+
return res.status(404).json({
35+
success: false,
36+
error: 'Request not found'
37+
});
38+
}
39+
40+
res.json({
41+
success: true,
42+
data: request,
43+
timestamp: new Date().toISOString()
44+
});
45+
} catch (error) {
46+
logger.error('Failed to fetch request details:', error);
47+
res.status(500).json({
48+
success: false,
49+
error: 'Failed to fetch request details'
50+
});
51+
}
52+
});
53+
54+
// Get aggregated policy enforcement statistics
55+
router.get('/policy-stats', async (req, res) => {
56+
try {
57+
const requests = await metricsService.getRealLiveRequests();
58+
59+
const stats = {
60+
totalRequests: requests.length,
61+
approvedRequests: requests.filter(r => r.decision === 'accept').length,
62+
rejectedRequests: requests.filter(r => r.decision === 'reject').length,
63+
policyDecisions: {
64+
authPolicy: {
65+
total: requests.reduce((sum, r) => sum + r.policyDecisions.filter(p => p.policyType === 'AuthPolicy').length, 0),
66+
allowed: requests.reduce((sum, r) => sum + r.policyDecisions.filter(p => p.policyType === 'AuthPolicy' && p.decision === 'allow').length, 0),
67+
denied: requests.reduce((sum, r) => sum + r.policyDecisions.filter(p => p.policyType === 'AuthPolicy' && p.decision === 'deny').length, 0)
68+
},
69+
rateLimitPolicy: {
70+
total: requests.reduce((sum, r) => sum + r.policyDecisions.filter(p => p.policyType === 'RateLimitPolicy').length, 0),
71+
allowed: requests.reduce((sum, r) => sum + r.policyDecisions.filter(p => p.policyType === 'RateLimitPolicy' && p.decision === 'allow').length, 0),
72+
denied: requests.reduce((sum, r) => sum + r.policyDecisions.filter(p => p.policyType === 'RateLimitPolicy' && p.decision === 'deny').length, 0)
73+
}
74+
},
75+
enforcementPoints: {
76+
authorino: requests.reduce((sum, r) => sum + r.policyDecisions.filter(p => p.enforcementPoint === 'authorino').length, 0),
77+
limitador: requests.reduce((sum, r) => sum + r.policyDecisions.filter(p => p.enforcementPoint === 'limitador').length, 0),
78+
envoy: requests.reduce((sum, r) => sum + r.policyDecisions.filter(p => p.enforcementPoint === 'envoy').length, 0),
79+
opa: requests.reduce((sum, r) => sum + r.policyDecisions.filter(p => p.enforcementPoint === 'opa').length, 0),
80+
kuadrant: requests.reduce((sum, r) => sum + r.policyDecisions.filter(p => p.enforcementPoint === 'kuadrant').length, 0)
81+
},
82+
modelInferences: {
83+
total: requests.filter(r => r.modelInference).length,
84+
totalTokens: requests.reduce((sum, r) => sum + (r.modelInference?.totalTokens || 0), 0),
85+
avgResponseTime: requests.filter(r => r.modelInference).reduce((sum, r) => sum + (r.modelInference?.responseTime || 0), 0) / Math.max(1, requests.filter(r => r.modelInference).length),
86+
totalCost: requests.reduce((sum, r) => sum + (r.estimatedCost || 0), 0)
87+
},
88+
authentication: {
89+
apiKey: requests.filter(r => r.authentication?.method === 'api-key').length,
90+
none: requests.filter(r => r.authentication?.method === 'none').length,
91+
valid: requests.filter(r => r.authentication?.isValid).length,
92+
invalid: requests.filter(r => r.authentication && !r.authentication.isValid).length
93+
}
94+
};
3695

96+
res.json({
97+
success: true,
98+
data: stats,
99+
timestamp: new Date().toISOString()
100+
});
101+
} catch (error) {
102+
logger.error('Failed to fetch policy stats:', error);
103+
res.status(500).json({
104+
success: false,
105+
error: 'Failed to fetch policy statistics'
106+
});
107+
}
108+
});
109+
110+
// Get dashboard statistics from real Prometheus metrics
111+
router.get('/dashboard', async (req, res) => {
112+
try {
113+
// Get real data from Prometheus sources
114+
const [istioMetrics, authorinoMetrics, status] = await Promise.all([
115+
metricsService.fetchIstioMetrics(),
116+
metricsService.fetchAuthorinoMetrics(),
117+
metricsService.getMetricsStatus()
118+
]);
119+
120+
// Calculate totals from real Prometheus data
121+
let totalRequests = 0;
122+
let acceptedRequests = 0;
123+
let authFailedRequests = 0;
124+
let rateLimitedRequests = 0;
125+
let rejectedRequests = 0;
126+
127+
if (istioMetrics) {
128+
// Use real Istio metrics for accurate counts
129+
acceptedRequests = istioMetrics.successRequests || 0;
130+
authFailedRequests = istioMetrics.authFailedRequests || 0;
131+
rateLimitedRequests = istioMetrics.rateLimitedRequests || 0;
132+
rejectedRequests = authFailedRequests + rateLimitedRequests + (istioMetrics.notFoundRequests || 0);
133+
totalRequests = acceptedRequests + rejectedRequests;
134+
}
135+
136+
// Enhanced status with real metrics sources
137+
const enhancedStatus = {
138+
...status,
139+
istioConnected: istioMetrics !== null,
140+
metricsSource: istioMetrics ? 'istio-prometheus' : 'fallback',
141+
realData: totalRequests > 0
142+
};
143+
37144
res.json({
38145
success: true,
39146
data: {
147+
// Real metrics from Prometheus
40148
totalRequests,
41149
acceptedRequests,
42150
rejectedRequests,
43-
policyEnforcedRequests,
151+
authFailedRequests,
152+
rateLimitedRequests,
153+
policyEnforcedRequests: authFailedRequests + rateLimitedRequests,
154+
155+
// Enhanced status
44156
kuadrantStatus: {
45-
limitadorConnected: status.limitadorConnected,
46-
authorinoConnected: status.authorinoConnected,
47-
hasRealTraffic: status.hasRealTraffic
157+
...enhancedStatus,
158+
notFoundRequests: istioMetrics?.notFoundRequests || 0,
159+
debugIstioMetrics: istioMetrics ? {
160+
successRequests: istioMetrics.successRequests,
161+
authFailedRequests: istioMetrics.authFailedRequests,
162+
rateLimitedRequests: istioMetrics.rateLimitedRequests,
163+
notFoundRequests: istioMetrics.notFoundRequests,
164+
totalRequests: istioMetrics.totalRequests
165+
} : null
166+
},
167+
168+
// Real Authorino controller metrics from Prometheus
169+
authorinoStats: authorinoMetrics ? {
170+
authConfigs: Array.from(authorinoMetrics.authByNamespace?.keys() || []).length,
171+
totalEvaluations: authorinoMetrics.authRequests || 0,
172+
successfulReconciles: authorinoMetrics.authSuccesses || 0,
173+
failedReconciles: authorinoMetrics.authFailures || 0,
174+
// Additional controller metrics
175+
reconcileOperations: authorinoMetrics.totalReconciles || 0,
176+
avgReconcileTime: authorinoMetrics.avgReconcileTime || 0
177+
} : {
178+
authConfigs: 0,
179+
totalEvaluations: 0,
180+
successfulReconciles: 0,
181+
failedReconciles: 0,
182+
reconcileOperations: 0,
183+
avgReconcileTime: 0
48184
},
49-
lastUpdate: status.lastUpdate
185+
186+
lastUpdate: new Date().toISOString(),
187+
source: 'prometheus-metrics'
50188
}
51189
});
52190
} catch (error) {

apps/backend/src/routes/policies.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import express from 'express';
22
import { logger } from '../utils/logger';
33
import { kuadrantService } from '../services/kuadrantService';
44

5-
const router = express.Router();
5+
const router: express.Router = express.Router();
66

77
// Get all policies from Kuadrant
88
router.get('/', async (req, res) => {
@@ -19,7 +19,7 @@ router.get('/', async (req, res) => {
1919
data: policies,
2020
timestamp: new Date().toISOString()
2121
});
22-
} catch (error) {
22+
} catch (error: any) {
2323
logger.error('Failed to fetch policies:', error);
2424
res.status(500).json({
2525
success: false,
@@ -51,7 +51,7 @@ router.post('/', async (req, res) => {
5151
success: true,
5252
data: newPolicy
5353
});
54-
} catch (error) {
54+
} catch (error: any) {
5555
logger.error('Failed to create policy:', error);
5656
res.status(500).json({
5757
success: false,
@@ -73,7 +73,7 @@ router.put('/:id', async (req, res) => {
7373
success: true,
7474
data: updatedPolicy
7575
});
76-
} catch (error) {
76+
} catch (error: any) {
7777
logger.error('Failed to update policy:', error);
7878
res.status(500).json({
7979
success: false,
@@ -94,7 +94,7 @@ router.delete('/:id', async (req, res) => {
9494
success: true,
9595
message: `Policy ${policyId} deleted successfully`
9696
});
97-
} catch (error) {
97+
} catch (error: any) {
9898
logger.error('Failed to delete policy:', error);
9999
res.status(500).json({
100100
success: false,

0 commit comments

Comments
 (0)