@stacksjs/ts-cloud-core 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/README.md +321 -0
- package/package.json +31 -0
- package/src/advanced-features.test.ts +465 -0
- package/src/aws/cloudformation.ts +421 -0
- package/src/aws/cloudfront.ts +158 -0
- package/src/aws/credentials.test.ts +132 -0
- package/src/aws/credentials.ts +545 -0
- package/src/aws/index.ts +87 -0
- package/src/aws/s3.test.ts +188 -0
- package/src/aws/s3.ts +1088 -0
- package/src/aws/signature.test.ts +670 -0
- package/src/aws/signature.ts +1155 -0
- package/src/backup/disaster-recovery.test.ts +726 -0
- package/src/backup/disaster-recovery.ts +500 -0
- package/src/backup/index.ts +34 -0
- package/src/backup/manager.test.ts +498 -0
- package/src/backup/manager.ts +432 -0
- package/src/cicd/circleci.ts +430 -0
- package/src/cicd/github-actions.ts +424 -0
- package/src/cicd/gitlab-ci.ts +255 -0
- package/src/cicd/index.ts +8 -0
- package/src/cli/history.ts +396 -0
- package/src/cli/index.ts +10 -0
- package/src/cli/progress.ts +458 -0
- package/src/cli/repl.ts +454 -0
- package/src/cli/suggestions.ts +327 -0
- package/src/cli/table.test.ts +319 -0
- package/src/cli/table.ts +332 -0
- package/src/cloudformation/builder.test.ts +327 -0
- package/src/cloudformation/builder.ts +378 -0
- package/src/cloudformation/builders/api-gateway.ts +449 -0
- package/src/cloudformation/builders/cache.ts +334 -0
- package/src/cloudformation/builders/cdn.ts +278 -0
- package/src/cloudformation/builders/compute.ts +485 -0
- package/src/cloudformation/builders/database.ts +392 -0
- package/src/cloudformation/builders/functions.ts +343 -0
- package/src/cloudformation/builders/messaging.ts +140 -0
- package/src/cloudformation/builders/monitoring.ts +300 -0
- package/src/cloudformation/builders/network.ts +264 -0
- package/src/cloudformation/builders/queue.ts +147 -0
- package/src/cloudformation/builders/security.ts +399 -0
- package/src/cloudformation/builders/storage.ts +285 -0
- package/src/cloudformation/index.ts +30 -0
- package/src/cloudformation/types.ts +173 -0
- package/src/compliance/aws-config.ts +543 -0
- package/src/compliance/cloudtrail.ts +376 -0
- package/src/compliance/compliance.test.ts +423 -0
- package/src/compliance/guardduty.ts +446 -0
- package/src/compliance/index.ts +66 -0
- package/src/compliance/security-hub.ts +456 -0
- package/src/containers/build-optimization.ts +416 -0
- package/src/containers/containers.test.ts +508 -0
- package/src/containers/image-scanning.ts +360 -0
- package/src/containers/index.ts +9 -0
- package/src/containers/registry.ts +293 -0
- package/src/containers/service-mesh.ts +520 -0
- package/src/database/database.test.ts +762 -0
- package/src/database/index.ts +9 -0
- package/src/database/migrations.ts +444 -0
- package/src/database/performance.ts +528 -0
- package/src/database/replicas.ts +534 -0
- package/src/database/users.ts +494 -0
- package/src/dependency-graph.ts +143 -0
- package/src/deployment/ab-testing.ts +582 -0
- package/src/deployment/blue-green.ts +452 -0
- package/src/deployment/canary.ts +500 -0
- package/src/deployment/deployment.test.ts +526 -0
- package/src/deployment/index.ts +61 -0
- package/src/deployment/progressive.ts +62 -0
- package/src/dns/dns.test.ts +641 -0
- package/src/dns/dnssec.ts +315 -0
- package/src/dns/index.ts +8 -0
- package/src/dns/resolver.ts +496 -0
- package/src/dns/routing.ts +593 -0
- package/src/email/advanced/analytics.ts +445 -0
- package/src/email/advanced/index.ts +11 -0
- package/src/email/advanced/rules.ts +465 -0
- package/src/email/advanced/scheduling.ts +352 -0
- package/src/email/advanced/search.ts +412 -0
- package/src/email/advanced/shared-mailboxes.ts +404 -0
- package/src/email/advanced/templates.ts +455 -0
- package/src/email/advanced/threading.ts +281 -0
- package/src/email/analytics.ts +467 -0
- package/src/email/bounce-handling.ts +425 -0
- package/src/email/email.test.ts +431 -0
- package/src/email/handlers/__tests__/inbound.test.ts +38 -0
- package/src/email/handlers/__tests__/outbound.test.ts +37 -0
- package/src/email/handlers/converter.ts +227 -0
- package/src/email/handlers/feedback.ts +228 -0
- package/src/email/handlers/inbound.ts +169 -0
- package/src/email/handlers/outbound.ts +178 -0
- package/src/email/index.ts +15 -0
- package/src/email/reputation.ts +303 -0
- package/src/email/templates.ts +352 -0
- package/src/errors/index.test.ts +434 -0
- package/src/errors/index.ts +416 -0
- package/src/health-checks/index.ts +40 -0
- package/src/index.ts +360 -0
- package/src/intrinsic-functions.ts +118 -0
- package/src/lambda/concurrency.ts +330 -0
- package/src/lambda/destinations.ts +345 -0
- package/src/lambda/dlq.ts +425 -0
- package/src/lambda/index.ts +11 -0
- package/src/lambda/lambda.test.ts +840 -0
- package/src/lambda/layers.ts +263 -0
- package/src/lambda/versions.ts +376 -0
- package/src/lambda/vpc.ts +399 -0
- package/src/local/config.ts +114 -0
- package/src/local/index.ts +6 -0
- package/src/local/mock-aws.ts +351 -0
- package/src/modules/ai.ts +340 -0
- package/src/modules/api.ts +478 -0
- package/src/modules/auth.ts +805 -0
- package/src/modules/cache.ts +417 -0
- package/src/modules/cdn.ts +1062 -0
- package/src/modules/communication.ts +1094 -0
- package/src/modules/compute.ts +3348 -0
- package/src/modules/database.ts +554 -0
- package/src/modules/deployment.ts +1079 -0
- package/src/modules/dns.ts +337 -0
- package/src/modules/email.ts +1538 -0
- package/src/modules/filesystem.ts +515 -0
- package/src/modules/index.ts +32 -0
- package/src/modules/messaging.ts +486 -0
- package/src/modules/monitoring.ts +2086 -0
- package/src/modules/network.ts +664 -0
- package/src/modules/parameter-store.ts +325 -0
- package/src/modules/permissions.ts +1081 -0
- package/src/modules/phone.ts +494 -0
- package/src/modules/queue.ts +1260 -0
- package/src/modules/redirects.ts +464 -0
- package/src/modules/registry.ts +699 -0
- package/src/modules/search.ts +401 -0
- package/src/modules/secrets.ts +416 -0
- package/src/modules/security.ts +731 -0
- package/src/modules/sms.ts +389 -0
- package/src/modules/storage.ts +1120 -0
- package/src/modules/workflow.ts +680 -0
- package/src/multi-account/config.ts +521 -0
- package/src/multi-account/index.ts +7 -0
- package/src/multi-account/manager.ts +427 -0
- package/src/multi-region/cross-region.ts +410 -0
- package/src/multi-region/index.ts +8 -0
- package/src/multi-region/manager.ts +483 -0
- package/src/multi-region/regions.ts +435 -0
- package/src/network-security/index.ts +48 -0
- package/src/observability/index.ts +9 -0
- package/src/observability/logs.ts +522 -0
- package/src/observability/metrics.ts +460 -0
- package/src/observability/observability.test.ts +782 -0
- package/src/observability/synthetics.ts +568 -0
- package/src/observability/xray.ts +358 -0
- package/src/phone/advanced/analytics.ts +349 -0
- package/src/phone/advanced/callbacks.ts +428 -0
- package/src/phone/advanced/index.ts +8 -0
- package/src/phone/advanced/ivr-builder.ts +504 -0
- package/src/phone/advanced/recording.ts +310 -0
- package/src/phone/handlers/__tests__/incoming-call.test.ts +40 -0
- package/src/phone/handlers/incoming-call.ts +117 -0
- package/src/phone/handlers/missed-call.ts +116 -0
- package/src/phone/handlers/voicemail.ts +179 -0
- package/src/phone/index.ts +9 -0
- package/src/presets/api-backend.ts +134 -0
- package/src/presets/data-pipeline.ts +204 -0
- package/src/presets/extend.test.ts +295 -0
- package/src/presets/extend.ts +297 -0
- package/src/presets/fullstack-app.ts +144 -0
- package/src/presets/index.ts +27 -0
- package/src/presets/jamstack.ts +135 -0
- package/src/presets/microservices.ts +167 -0
- package/src/presets/ml-api.ts +208 -0
- package/src/presets/nodejs-server.ts +104 -0
- package/src/presets/nodejs-serverless.ts +114 -0
- package/src/presets/realtime-app.ts +184 -0
- package/src/presets/static-site.ts +64 -0
- package/src/presets/traditional-web-app.ts +339 -0
- package/src/presets/wordpress.ts +138 -0
- package/src/preview/github.test.ts +249 -0
- package/src/preview/github.ts +297 -0
- package/src/preview/index.ts +37 -0
- package/src/preview/manager.test.ts +440 -0
- package/src/preview/manager.ts +326 -0
- package/src/preview/notifications.test.ts +582 -0
- package/src/preview/notifications.ts +341 -0
- package/src/queue/batch-processing.ts +402 -0
- package/src/queue/dlq-monitoring.ts +402 -0
- package/src/queue/fifo.ts +342 -0
- package/src/queue/index.ts +9 -0
- package/src/queue/management.ts +428 -0
- package/src/queue/queue.test.ts +429 -0
- package/src/resource-mgmt/index.ts +39 -0
- package/src/resource-naming.ts +62 -0
- package/src/s3/index.ts +523 -0
- package/src/schema/cloud-config.schema.json +554 -0
- package/src/schema/index.ts +68 -0
- package/src/security/certificate-manager.ts +492 -0
- package/src/security/index.ts +9 -0
- package/src/security/scanning.ts +545 -0
- package/src/security/secrets-manager.ts +476 -0
- package/src/security/secrets-rotation.ts +456 -0
- package/src/security/security.test.ts +738 -0
- package/src/sms/advanced/ab-testing.ts +389 -0
- package/src/sms/advanced/analytics.ts +336 -0
- package/src/sms/advanced/campaigns.ts +523 -0
- package/src/sms/advanced/chatbot.ts +224 -0
- package/src/sms/advanced/index.ts +10 -0
- package/src/sms/advanced/link-tracking.ts +248 -0
- package/src/sms/advanced/mms.ts +308 -0
- package/src/sms/handlers/__tests__/send.test.ts +40 -0
- package/src/sms/handlers/delivery-status.ts +133 -0
- package/src/sms/handlers/receive.ts +162 -0
- package/src/sms/handlers/send.ts +174 -0
- package/src/sms/index.ts +9 -0
- package/src/stack-diff.ts +389 -0
- package/src/static-site/index.ts +85 -0
- package/src/template-builder.ts +110 -0
- package/src/template-validator.ts +574 -0
- package/src/utils/cache.ts +291 -0
- package/src/utils/diff.ts +269 -0
- package/src/utils/hash.ts +227 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/parallel.ts +294 -0
- package/src/validators/credentials.test.ts +274 -0
- package/src/validators/credentials.ts +233 -0
- package/src/validators/quotas.test.ts +434 -0
- package/src/validators/quotas.ts +217 -0
- package/test/ai.test.ts +327 -0
- package/test/api.test.ts +511 -0
- package/test/auth.test.ts +632 -0
- package/test/cache.test.ts +406 -0
- package/test/cdn.test.ts +247 -0
- package/test/compute.test.ts +861 -0
- package/test/database.test.ts +523 -0
- package/test/deployment.test.ts +499 -0
- package/test/dns.test.ts +270 -0
- package/test/email.test.ts +439 -0
- package/test/filesystem.test.ts +382 -0
- package/test/integration.test.ts +350 -0
- package/test/messaging.test.ts +514 -0
- package/test/monitoring.test.ts +634 -0
- package/test/network.test.ts +425 -0
- package/test/permissions.test.ts +488 -0
- package/test/queue.test.ts +484 -0
- package/test/registry.test.ts +306 -0
- package/test/security.test.ts +462 -0
- package/test/storage.test.ts +463 -0
- package/test/template-validator.test.ts +559 -0
- package/test/workflow.test.ts +592 -0
- package/tsconfig.json +16 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database Performance Monitoring
|
|
3
|
+
* Query performance insights, slow query detection, and optimization
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface PerformanceInsights {
|
|
7
|
+
id: string
|
|
8
|
+
name: string
|
|
9
|
+
databaseIdentifier: string
|
|
10
|
+
enabled: boolean
|
|
11
|
+
retentionPeriod: number // days (7, 731, or 2192)
|
|
12
|
+
kmsKeyId?: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface SlowQueryLog {
|
|
16
|
+
id: string
|
|
17
|
+
name: string
|
|
18
|
+
databaseIdentifier: string
|
|
19
|
+
enabled: boolean
|
|
20
|
+
logDestination: 'cloudwatch' | 's3'
|
|
21
|
+
cloudwatchLogGroup?: string
|
|
22
|
+
s3Bucket?: string
|
|
23
|
+
s3Prefix?: string
|
|
24
|
+
minExecutionTime?: number // milliseconds
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface QueryMetric {
|
|
28
|
+
id: string
|
|
29
|
+
queryId: string
|
|
30
|
+
sql: string
|
|
31
|
+
executionCount: number
|
|
32
|
+
avgExecutionTime: number // milliseconds
|
|
33
|
+
maxExecutionTime: number
|
|
34
|
+
minExecutionTime: number
|
|
35
|
+
totalCPUTime: number
|
|
36
|
+
totalIOWait: number
|
|
37
|
+
totalLockWait: number
|
|
38
|
+
rowsExamined: number
|
|
39
|
+
rowsReturned: number
|
|
40
|
+
timestamp: Date
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface PerformanceReport {
|
|
44
|
+
id: string
|
|
45
|
+
name: string
|
|
46
|
+
databaseIdentifier: string
|
|
47
|
+
reportType: 'daily' | 'weekly' | 'monthly'
|
|
48
|
+
metrics: PerformanceMetrics
|
|
49
|
+
topQueries: QueryMetric[]
|
|
50
|
+
slowQueries: QueryMetric[]
|
|
51
|
+
recommendations: PerformanceRecommendation[]
|
|
52
|
+
generatedAt: Date
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface PerformanceMetrics {
|
|
56
|
+
avgCPU: number
|
|
57
|
+
maxCPU: number
|
|
58
|
+
avgConnections: number
|
|
59
|
+
maxConnections: number
|
|
60
|
+
avgReadIOPS: number
|
|
61
|
+
avgWriteIOPS: number
|
|
62
|
+
avgReadThroughput: number // MB/s
|
|
63
|
+
avgWriteThroughput: number // MB/s
|
|
64
|
+
avgReadLatency: number // milliseconds
|
|
65
|
+
avgWriteLatency: number // milliseconds
|
|
66
|
+
cacheHitRatio: number // percentage
|
|
67
|
+
deadlocks: number
|
|
68
|
+
longRunningTransactions: number
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface PerformanceRecommendation {
|
|
72
|
+
type: 'index' | 'query' | 'schema' | 'configuration' | 'scaling'
|
|
73
|
+
severity: 'high' | 'medium' | 'low'
|
|
74
|
+
title: string
|
|
75
|
+
description: string
|
|
76
|
+
impact: string
|
|
77
|
+
effort: 'low' | 'medium' | 'high'
|
|
78
|
+
sqlExample?: string
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface IndexRecommendation {
|
|
82
|
+
id: string
|
|
83
|
+
tableName: string
|
|
84
|
+
columns: string[]
|
|
85
|
+
reason: string
|
|
86
|
+
estimatedImprovement: number // percentage
|
|
87
|
+
estimatedSize: number // MB
|
|
88
|
+
createSQL: string
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface QueryAnalysis {
|
|
92
|
+
id: string
|
|
93
|
+
queryId: string
|
|
94
|
+
sql: string
|
|
95
|
+
executionPlan: ExecutionPlanNode[]
|
|
96
|
+
bottlenecks: Bottleneck[]
|
|
97
|
+
recommendations: string[]
|
|
98
|
+
estimatedCost: number
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface ExecutionPlanNode {
|
|
102
|
+
id: number
|
|
103
|
+
operation: string
|
|
104
|
+
table?: string
|
|
105
|
+
rows: number
|
|
106
|
+
cost: number
|
|
107
|
+
children?: ExecutionPlanNode[]
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface Bottleneck {
|
|
111
|
+
type: 'full_table_scan' | 'missing_index' | 'suboptimal_join' | 'high_cardinality'
|
|
112
|
+
severity: 'critical' | 'warning' | 'info'
|
|
113
|
+
description: string
|
|
114
|
+
tableName?: string
|
|
115
|
+
columnName?: string
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Performance manager
|
|
120
|
+
*/
|
|
121
|
+
export class PerformanceManager {
|
|
122
|
+
private insights: Map<string, PerformanceInsights> = new Map()
|
|
123
|
+
private slowQueryLogs: Map<string, SlowQueryLog> = new Map()
|
|
124
|
+
private queryMetrics: Map<string, QueryMetric> = new Map()
|
|
125
|
+
private reports: Map<string, PerformanceReport> = new Map()
|
|
126
|
+
private indexRecommendations: Map<string, IndexRecommendation> = new Map()
|
|
127
|
+
private insightsCounter = 0
|
|
128
|
+
private logCounter = 0
|
|
129
|
+
private metricCounter = 0
|
|
130
|
+
private reportCounter = 0
|
|
131
|
+
private recommendationCounter = 0
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Enable performance insights
|
|
135
|
+
*/
|
|
136
|
+
enablePerformanceInsights(options: {
|
|
137
|
+
name: string
|
|
138
|
+
databaseIdentifier: string
|
|
139
|
+
retentionPeriod?: number
|
|
140
|
+
kmsKeyId?: string
|
|
141
|
+
}): PerformanceInsights {
|
|
142
|
+
const id = `pi-${Date.now()}-${this.insightsCounter++}`
|
|
143
|
+
|
|
144
|
+
const insights: PerformanceInsights = {
|
|
145
|
+
id,
|
|
146
|
+
name: options.name,
|
|
147
|
+
databaseIdentifier: options.databaseIdentifier,
|
|
148
|
+
enabled: true,
|
|
149
|
+
retentionPeriod: options.retentionPeriod || 7,
|
|
150
|
+
kmsKeyId: options.kmsKeyId,
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
this.insights.set(id, insights)
|
|
154
|
+
|
|
155
|
+
return insights
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Enable slow query log
|
|
160
|
+
*/
|
|
161
|
+
enableSlowQueryLog(options: {
|
|
162
|
+
name: string
|
|
163
|
+
databaseIdentifier: string
|
|
164
|
+
logDestination: 'cloudwatch' | 's3'
|
|
165
|
+
cloudwatchLogGroup?: string
|
|
166
|
+
s3Bucket?: string
|
|
167
|
+
minExecutionTime?: number
|
|
168
|
+
}): SlowQueryLog {
|
|
169
|
+
const id = `slow-query-${Date.now()}-${this.logCounter++}`
|
|
170
|
+
|
|
171
|
+
const slowQueryLog: SlowQueryLog = {
|
|
172
|
+
id,
|
|
173
|
+
name: options.name,
|
|
174
|
+
databaseIdentifier: options.databaseIdentifier,
|
|
175
|
+
enabled: true,
|
|
176
|
+
logDestination: options.logDestination,
|
|
177
|
+
cloudwatchLogGroup: options.cloudwatchLogGroup,
|
|
178
|
+
s3Bucket: options.s3Bucket,
|
|
179
|
+
s3Prefix: options.s3Bucket ? 'slow-queries/' : undefined,
|
|
180
|
+
minExecutionTime: options.minExecutionTime || 1000, // 1 second default
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
this.slowQueryLogs.set(id, slowQueryLog)
|
|
184
|
+
|
|
185
|
+
return slowQueryLog
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Record query metric
|
|
190
|
+
*/
|
|
191
|
+
recordQueryMetric(metric: Omit<QueryMetric, 'id' | 'timestamp'>): QueryMetric {
|
|
192
|
+
const id = `metric-${Date.now()}-${this.metricCounter++}`
|
|
193
|
+
|
|
194
|
+
const queryMetric: QueryMetric = {
|
|
195
|
+
id,
|
|
196
|
+
timestamp: new Date(),
|
|
197
|
+
...metric,
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
this.queryMetrics.set(id, queryMetric)
|
|
201
|
+
|
|
202
|
+
return queryMetric
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Generate performance report
|
|
207
|
+
*/
|
|
208
|
+
generatePerformanceReport(options: {
|
|
209
|
+
name: string
|
|
210
|
+
databaseIdentifier: string
|
|
211
|
+
reportType: 'daily' | 'weekly' | 'monthly'
|
|
212
|
+
}): PerformanceReport {
|
|
213
|
+
const id = `report-${Date.now()}-${this.reportCounter++}`
|
|
214
|
+
|
|
215
|
+
// Collect metrics
|
|
216
|
+
const metrics: PerformanceMetrics = {
|
|
217
|
+
avgCPU: Math.random() * 60 + 20, // 20-80%
|
|
218
|
+
maxCPU: Math.random() * 30 + 70, // 70-100%
|
|
219
|
+
avgConnections: Math.floor(Math.random() * 50 + 10),
|
|
220
|
+
maxConnections: Math.floor(Math.random() * 50 + 100),
|
|
221
|
+
avgReadIOPS: Math.floor(Math.random() * 1000 + 500),
|
|
222
|
+
avgWriteIOPS: Math.floor(Math.random() * 500 + 200),
|
|
223
|
+
avgReadThroughput: Math.random() * 50 + 10,
|
|
224
|
+
avgWriteThroughput: Math.random() * 20 + 5,
|
|
225
|
+
avgReadLatency: Math.random() * 5 + 1,
|
|
226
|
+
avgWriteLatency: Math.random() * 8 + 2,
|
|
227
|
+
cacheHitRatio: Math.random() * 10 + 90, // 90-100%
|
|
228
|
+
deadlocks: Math.floor(Math.random() * 5),
|
|
229
|
+
longRunningTransactions: Math.floor(Math.random() * 10),
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Get top queries by execution count
|
|
233
|
+
const allMetrics = Array.from(this.queryMetrics.values())
|
|
234
|
+
const topQueries = allMetrics
|
|
235
|
+
.sort((a, b) => b.executionCount - a.executionCount)
|
|
236
|
+
.slice(0, 10)
|
|
237
|
+
|
|
238
|
+
// Get slow queries
|
|
239
|
+
const slowQueries = allMetrics
|
|
240
|
+
.filter(m => m.avgExecutionTime > 1000)
|
|
241
|
+
.sort((a, b) => b.avgExecutionTime - a.avgExecutionTime)
|
|
242
|
+
.slice(0, 10)
|
|
243
|
+
|
|
244
|
+
// Generate recommendations
|
|
245
|
+
const recommendations = this.generateRecommendations(metrics, slowQueries)
|
|
246
|
+
|
|
247
|
+
const report: PerformanceReport = {
|
|
248
|
+
id,
|
|
249
|
+
name: options.name,
|
|
250
|
+
databaseIdentifier: options.databaseIdentifier,
|
|
251
|
+
reportType: options.reportType,
|
|
252
|
+
metrics,
|
|
253
|
+
topQueries,
|
|
254
|
+
slowQueries,
|
|
255
|
+
recommendations,
|
|
256
|
+
generatedAt: new Date(),
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
this.reports.set(id, report)
|
|
260
|
+
|
|
261
|
+
return report
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Generate recommendations based on metrics
|
|
266
|
+
*/
|
|
267
|
+
private generateRecommendations(
|
|
268
|
+
metrics: PerformanceMetrics,
|
|
269
|
+
slowQueries: QueryMetric[]
|
|
270
|
+
): PerformanceRecommendation[] {
|
|
271
|
+
const recommendations: PerformanceRecommendation[] = []
|
|
272
|
+
|
|
273
|
+
// High CPU usage
|
|
274
|
+
if (metrics.avgCPU > 70) {
|
|
275
|
+
recommendations.push({
|
|
276
|
+
type: 'scaling',
|
|
277
|
+
severity: 'high',
|
|
278
|
+
title: 'High CPU Usage',
|
|
279
|
+
description: `Average CPU usage is ${metrics.avgCPU.toFixed(1)}%, which is above the recommended threshold of 70%.`,
|
|
280
|
+
impact: 'Performance degradation, increased latency, potential timeouts',
|
|
281
|
+
effort: 'medium',
|
|
282
|
+
})
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Low cache hit ratio
|
|
286
|
+
if (metrics.cacheHitRatio < 95) {
|
|
287
|
+
recommendations.push({
|
|
288
|
+
type: 'configuration',
|
|
289
|
+
severity: 'medium',
|
|
290
|
+
title: 'Low Cache Hit Ratio',
|
|
291
|
+
description: `Cache hit ratio is ${metrics.cacheHitRatio.toFixed(1)}%. Consider increasing buffer pool size.`,
|
|
292
|
+
impact: 'Increased disk I/O, slower query performance',
|
|
293
|
+
effort: 'low',
|
|
294
|
+
})
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Deadlocks
|
|
298
|
+
if (metrics.deadlocks > 0) {
|
|
299
|
+
recommendations.push({
|
|
300
|
+
type: 'query',
|
|
301
|
+
severity: 'medium',
|
|
302
|
+
title: 'Deadlocks Detected',
|
|
303
|
+
description: `${metrics.deadlocks} deadlock(s) detected. Review transaction isolation levels and query patterns.`,
|
|
304
|
+
impact: 'Transaction failures, application errors',
|
|
305
|
+
effort: 'high',
|
|
306
|
+
})
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Slow queries
|
|
310
|
+
if (slowQueries.length > 0) {
|
|
311
|
+
recommendations.push({
|
|
312
|
+
type: 'index',
|
|
313
|
+
severity: 'high',
|
|
314
|
+
title: 'Slow Queries Detected',
|
|
315
|
+
description: `${slowQueries.length} slow queries detected. Consider adding indexes or optimizing queries.`,
|
|
316
|
+
impact: 'High latency, poor user experience',
|
|
317
|
+
effort: 'medium',
|
|
318
|
+
})
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// High I/O latency
|
|
322
|
+
if (metrics.avgReadLatency > 10 || metrics.avgWriteLatency > 10) {
|
|
323
|
+
recommendations.push({
|
|
324
|
+
type: 'scaling',
|
|
325
|
+
severity: 'high',
|
|
326
|
+
title: 'High I/O Latency',
|
|
327
|
+
description: 'Read or write latency is high. Consider upgrading to Provisioned IOPS or moving to a larger instance.',
|
|
328
|
+
impact: 'Slow query execution, application timeouts',
|
|
329
|
+
effort: 'medium',
|
|
330
|
+
})
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return recommendations
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Analyze query
|
|
338
|
+
*/
|
|
339
|
+
analyzeQuery(sql: string): QueryAnalysis {
|
|
340
|
+
const id = `analysis-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
|
|
341
|
+
|
|
342
|
+
// Simulate execution plan
|
|
343
|
+
const executionPlan: ExecutionPlanNode[] = [
|
|
344
|
+
{
|
|
345
|
+
id: 1,
|
|
346
|
+
operation: 'Seq Scan',
|
|
347
|
+
table: 'users',
|
|
348
|
+
rows: 10000,
|
|
349
|
+
cost: 850.5,
|
|
350
|
+
children: [],
|
|
351
|
+
},
|
|
352
|
+
]
|
|
353
|
+
|
|
354
|
+
// Detect bottlenecks
|
|
355
|
+
const bottlenecks: Bottleneck[] = []
|
|
356
|
+
|
|
357
|
+
if (sql.toLowerCase().includes('select *')) {
|
|
358
|
+
bottlenecks.push({
|
|
359
|
+
type: 'full_table_scan',
|
|
360
|
+
severity: 'warning',
|
|
361
|
+
description: 'Query selects all columns. Consider selecting only required columns.',
|
|
362
|
+
})
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if (!sql.toLowerCase().includes('where') && sql.toLowerCase().includes('select')) {
|
|
366
|
+
bottlenecks.push({
|
|
367
|
+
type: 'full_table_scan',
|
|
368
|
+
severity: 'critical',
|
|
369
|
+
description: 'Query has no WHERE clause and may scan entire table.',
|
|
370
|
+
})
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const recommendations = [
|
|
374
|
+
'Add appropriate indexes on WHERE clause columns',
|
|
375
|
+
'Consider using EXPLAIN ANALYZE to get actual execution statistics',
|
|
376
|
+
'Review and optimize JOIN conditions',
|
|
377
|
+
]
|
|
378
|
+
|
|
379
|
+
return {
|
|
380
|
+
id,
|
|
381
|
+
queryId: id,
|
|
382
|
+
sql,
|
|
383
|
+
executionPlan,
|
|
384
|
+
bottlenecks,
|
|
385
|
+
recommendations,
|
|
386
|
+
estimatedCost: executionPlan[0].cost,
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Recommend index
|
|
392
|
+
*/
|
|
393
|
+
recommendIndex(options: {
|
|
394
|
+
tableName: string
|
|
395
|
+
columns: string[]
|
|
396
|
+
reason: string
|
|
397
|
+
estimatedImprovement?: number
|
|
398
|
+
}): IndexRecommendation {
|
|
399
|
+
const id = `index-rec-${Date.now()}-${this.recommendationCounter++}`
|
|
400
|
+
|
|
401
|
+
const indexName = `idx_${options.tableName}_${options.columns.join('_')}`
|
|
402
|
+
|
|
403
|
+
const recommendation: IndexRecommendation = {
|
|
404
|
+
id,
|
|
405
|
+
tableName: options.tableName,
|
|
406
|
+
columns: options.columns,
|
|
407
|
+
reason: options.reason,
|
|
408
|
+
estimatedImprovement: options.estimatedImprovement || 50,
|
|
409
|
+
estimatedSize: options.columns.length * 10, // Simple estimate
|
|
410
|
+
createSQL: `CREATE INDEX ${indexName} ON ${options.tableName} (${options.columns.join(', ')});`,
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
this.indexRecommendations.set(id, recommendation)
|
|
414
|
+
|
|
415
|
+
return recommendation
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Get performance insights
|
|
420
|
+
*/
|
|
421
|
+
getInsights(id: string): PerformanceInsights | undefined {
|
|
422
|
+
return this.insights.get(id)
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* List performance insights
|
|
427
|
+
*/
|
|
428
|
+
listInsights(): PerformanceInsights[] {
|
|
429
|
+
return Array.from(this.insights.values())
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Get slow query log
|
|
434
|
+
*/
|
|
435
|
+
getSlowQueryLog(id: string): SlowQueryLog | undefined {
|
|
436
|
+
return this.slowQueryLogs.get(id)
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* List slow query logs
|
|
441
|
+
*/
|
|
442
|
+
listSlowQueryLogs(): SlowQueryLog[] {
|
|
443
|
+
return Array.from(this.slowQueryLogs.values())
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Get report
|
|
448
|
+
*/
|
|
449
|
+
getReport(id: string): PerformanceReport | undefined {
|
|
450
|
+
return this.reports.get(id)
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* List reports
|
|
455
|
+
*/
|
|
456
|
+
listReports(): PerformanceReport[] {
|
|
457
|
+
return Array.from(this.reports.values())
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* List index recommendations
|
|
462
|
+
*/
|
|
463
|
+
listIndexRecommendations(): IndexRecommendation[] {
|
|
464
|
+
return Array.from(this.indexRecommendations.values())
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Generate CloudFormation for Performance Insights
|
|
469
|
+
*/
|
|
470
|
+
generatePerformanceInsightsCF(insights: PerformanceInsights): any {
|
|
471
|
+
return {
|
|
472
|
+
EnablePerformanceInsights: insights.enabled,
|
|
473
|
+
PerformanceInsightsRetentionPeriod: insights.retentionPeriod,
|
|
474
|
+
...(insights.kmsKeyId && {
|
|
475
|
+
PerformanceInsightsKMSKeyId: insights.kmsKeyId,
|
|
476
|
+
}),
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Generate CloudWatch alarm for slow queries
|
|
482
|
+
*/
|
|
483
|
+
generateSlowQueryAlarmCF(options: {
|
|
484
|
+
alarmName: string
|
|
485
|
+
logGroupName: string
|
|
486
|
+
threshold: number
|
|
487
|
+
snsTopicArn?: string
|
|
488
|
+
}): any {
|
|
489
|
+
return {
|
|
490
|
+
Type: 'AWS::CloudWatch::Alarm',
|
|
491
|
+
Properties: {
|
|
492
|
+
AlarmName: options.alarmName,
|
|
493
|
+
AlarmDescription: 'Alert when slow queries exceed threshold',
|
|
494
|
+
MetricName: 'SlowQueryCount',
|
|
495
|
+
Namespace: 'AWS/RDS',
|
|
496
|
+
Statistic: 'Sum',
|
|
497
|
+
Period: 300,
|
|
498
|
+
EvaluationPeriods: 1,
|
|
499
|
+
Threshold: options.threshold,
|
|
500
|
+
ComparisonOperator: 'GreaterThanThreshold',
|
|
501
|
+
...(options.snsTopicArn && {
|
|
502
|
+
AlarmActions: [options.snsTopicArn],
|
|
503
|
+
}),
|
|
504
|
+
},
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Clear all data
|
|
510
|
+
*/
|
|
511
|
+
clear(): void {
|
|
512
|
+
this.insights.clear()
|
|
513
|
+
this.slowQueryLogs.clear()
|
|
514
|
+
this.queryMetrics.clear()
|
|
515
|
+
this.reports.clear()
|
|
516
|
+
this.indexRecommendations.clear()
|
|
517
|
+
this.insightsCounter = 0
|
|
518
|
+
this.logCounter = 0
|
|
519
|
+
this.metricCounter = 0
|
|
520
|
+
this.reportCounter = 0
|
|
521
|
+
this.recommendationCounter = 0
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Global performance manager instance
|
|
527
|
+
*/
|
|
528
|
+
export const performanceManager: PerformanceManager = new PerformanceManager()
|