1- import { Socket } from 'node:net' ;
2- import { lookup } from 'node:dns/promises' ;
1+ import { Socket } from 'net' ;
2+ import { lookup } from 'dns/promises' ;
3+ // @ts -ignore - janus-core doesn't have proper ES module type declarations
4+ import stats from '@racker/janus-core/lib/stats/index.js' ;
5+ // @ts -ignore - janus-core doesn't have proper ES module type declarations
6+ import log from '@racker/janus-core/lib/log.js' ;
37
48interface TestTarget {
59 host : string ;
610 port : number ;
711 protocol : 'tcp' | 'http' | 'https' ;
812 path ?: string ;
13+ critical ?: boolean ;
914}
1015
1116interface TestResult {
@@ -18,38 +23,75 @@ interface TestResult {
1823 error ?: string ;
1924 errorCode ?: string ;
2025 httpStatus ?: number ;
26+ critical ?: boolean ;
2127}
2228
2329interface LambdaEvent {
2430 targets : TestTarget [ ] ;
2531}
2632
2733export const handler = async ( event : LambdaEvent ) : Promise < TestResult [ ] > => {
28- console . log (
29- 'Testing connectivity for targets:' ,
30- JSON . stringify ( event . targets )
31- ) ;
32-
33- const results : TestResult [ ] = [ ] ;
34-
35- for ( const target of event . targets ) {
36- if ( target . protocol === 'tcp' ) {
37- results . push ( await testTcp ( target ) ) ;
38- } else if ( target . protocol === 'http' || target . protocol === 'https' ) {
39- results . push ( await testHttp ( target ) ) ;
40- } else {
41- results . push ( {
42- host : target . host ,
43- port : target . port ,
44- protocol : target . protocol ,
45- success : false ,
46- error : `Unsupported protocol: ${ target . protocol } ` ,
47- } ) ;
48- }
49- }
34+ const env = process . env . ENVIRONMENT || 'unknown' ;
35+
36+ log . initialize ( 'connectivity-check' , {
37+ level : env === 'local' ? 'debug' : 'info'
38+ } ) ;
39+
40+ try {
41+ // Parse additional metric tags from environment variable
42+ const additionalTags = process . env . METRIC_TAGS
43+ ? process . env . METRIC_TAGS . split ( ',' ) . map ( tag => tag . trim ( ) )
44+ : [ ] ;
45+
46+ // Initialize Datadog stats
47+ await stats . initializeWithDriver ( 'http' , 'connectivity.' , {
48+ defaultTags : [
49+ `env:${ env } ` ,
50+ 'service:connectivity-check' ,
51+ ...additionalTags
52+ ] ,
53+ mock : [ 'local' , 'test' ] . includes ( env )
54+ } ) ;
55+
56+ log . info (
57+ { targetCount : event . targets . length } ,
58+ 'Testing connectivity for targets'
59+ ) ;
60+
61+ // Run all connectivity checks in parallel for faster execution
62+ const checkPromises = event . targets . map ( async ( target ) => {
63+ let result : TestResult ;
64+
65+ if ( target . protocol === 'tcp' ) {
66+ result = await testTcp ( target ) ;
67+ } else if ( target . protocol === 'http' || target . protocol === 'https' ) {
68+ result = await testHttp ( target ) ;
69+ } else {
70+ result = {
71+ host : target . host ,
72+ port : target . port ,
73+ protocol : target . protocol ,
74+ success : false ,
75+ error : `Unsupported protocol: ${ target . protocol } ` ,
76+ critical : target . critical ,
77+ } ;
78+ }
79+
80+ return result ;
81+ } ) ;
82+
83+ // Wait for all checks to complete
84+ const results = await Promise . all ( checkPromises ) ;
85+
86+ // Publish metrics to Datadog for all results
87+ results . forEach ( result => publishMetrics ( result ) ) ;
88+
89+ log . info ( { successCount : results . filter ( r => r . success ) . length , totalCount : results . length } , 'Connectivity check complete' ) ;
5090
51- console . log ( 'Results:' , JSON . stringify ( results ) ) ;
52- return results ;
91+ return results ;
92+ } finally {
93+ await stats . close ( ) ;
94+ }
5395} ;
5496
5597function isIpAddress ( host : string ) : boolean {
@@ -101,6 +143,7 @@ async function testTcp(target: TestTarget): Promise<TestResult> {
101143 success : false ,
102144 error : `DNS resolution failed: ${ dnsResult . error } ` ,
103145 errorCode : dnsResult . errorCode ,
146+ critical : target . critical ,
104147 } ;
105148 }
106149
@@ -119,6 +162,7 @@ async function testTcp(target: TestTarget): Promise<TestResult> {
119162 success : true ,
120163 resolvedIp : dnsResult . ip ,
121164 latencyMs : Date . now ( ) - start ,
165+ critical : target . critical ,
122166 } ) ;
123167 } ) ;
124168
@@ -132,6 +176,7 @@ async function testTcp(target: TestTarget): Promise<TestResult> {
132176 resolvedIp : dnsResult . ip ,
133177 error : 'Connection timeout (5s)' ,
134178 errorCode : 'ETIMEDOUT' ,
179+ critical : target . critical ,
135180 } ) ;
136181 } ) ;
137182
@@ -145,6 +190,7 @@ async function testTcp(target: TestTarget): Promise<TestResult> {
145190 resolvedIp : dnsResult . ip ,
146191 error : err . message ,
147192 errorCode : err . code ,
193+ critical : target . critical ,
148194 } ) ;
149195 } ) ;
150196
@@ -165,6 +211,7 @@ async function testHttp(target: TestTarget): Promise<TestResult> {
165211 success : false ,
166212 error : `DNS resolution failed: ${ dnsResult . error } ` ,
167213 errorCode : dnsResult . errorCode ,
214+ critical : target . critical ,
168215 } ;
169216 }
170217
@@ -180,14 +227,14 @@ async function testHttp(target: TestTarget): Promise<TestResult> {
180227
181228 // Log response details
182229 const headers = Object . fromEntries ( response . headers . entries ( ) ) ;
183- console . log ( `Response headers for ${ url } :` , JSON . stringify ( headers ) ) ;
230+ log . debug ( { url , headers } , 'HTTP response headers' ) ;
184231
185232 const bodyText = await response . text ( ) ;
186233 const truncatedBody =
187234 bodyText . length > 100
188235 ? bodyText . substring ( 0 , 100 ) + '...(truncated)'
189236 : bodyText ;
190- console . log ( `Response body for ${ url } :` , truncatedBody ) ;
237+ log . debug ( { url , body : truncatedBody } , 'HTTP response body' ) ;
191238
192239 return {
193240 host : target . host ,
@@ -197,6 +244,7 @@ async function testHttp(target: TestTarget): Promise<TestResult> {
197244 resolvedIp : dnsResult . ip ,
198245 latencyMs : Date . now ( ) - start ,
199246 httpStatus : response . status ,
247+ critical : target . critical ,
200248 } ;
201249 } catch ( err : any ) {
202250 return {
@@ -207,6 +255,38 @@ async function testHttp(target: TestTarget): Promise<TestResult> {
207255 resolvedIp : dnsResult . ip ,
208256 error : err . message ,
209257 errorCode : err . code || err . cause ?. code ,
258+ critical : target . critical ,
210259 } ;
211260 }
212261}
262+
263+ /**
264+ * Publish connectivity metrics to Datadog via janus-core stats
265+ */
266+ function publishMetrics ( result : TestResult ) : void {
267+ const endpoint = `${ result . host } :${ result . port } ` ;
268+ const tags = [
269+ `endpoint:${ endpoint } ` ,
270+ `host:${ result . host } ` ,
271+ `protocol:${ result . protocol } ` ,
272+ `critical:${ result . critical || false } ` ,
273+ ] ;
274+
275+ // Connectivity status metric (1 = success, 0 = failure)
276+ stats . gauge ( 'endpoint.status' , result . success ? 1 : 0 , tags ) ;
277+
278+ // Response time metric (using timing for latency measurements)
279+ if ( result . latencyMs !== undefined ) {
280+ stats . timing ( 'endpoint.latency' , result . latencyMs , tags ) ;
281+ }
282+
283+ // Count metrics for success/failure
284+ if ( result . success ) {
285+ stats . increment ( 'endpoint.success.count' , 1 , tags ) ;
286+ } else {
287+ stats . increment ( 'endpoint.error.count' , 1 , tags ) ;
288+ if ( result . errorCode ) {
289+ stats . increment ( 'endpoint.error.count' , 1 , [ ...tags , `error_code:${ result . errorCode } ` ] ) ;
290+ }
291+ }
292+ }
0 commit comments