@@ -12,43 +12,60 @@ export class TraefikIntegration extends BaseIntegration {
1212 async collect ( ) : Promise < TraefikStats | null > {
1313 if ( ! this . config . enabled ) return null ;
1414
15- // 1. Build Candidate List (Priority + Fallbacks)
16- // We use a Set to handle duplicates if the user config matches a default
1715 const candidates = new Set < string > ( ) ;
1816
19- // Priority: User Configured URL
20- if ( this . config . url && this . config . url . trim ( ) !== '' ) {
21- candidates . add ( this . config . url ) ;
17+ // 1. Prioritize User URL
18+ const userUrl = this . config . url && this . config . url . trim ( ) !== '' ? this . config . url : null ;
19+ if ( userUrl ) {
20+ candidates . add ( userUrl ) ;
2221 }
2322
24- // Fallbacks: Auto-Discovery Defaults
25- // Useful for Coolify/Dokploy where 127.0.0.1 might fail inside the container
26- candidates . add ( 'http://127.0.0.1:8080' ) ; // Host Networking
27- candidates . add ( 'http://172.17.0.1:8080' ) ; // Docker Bridge Gateway
28- candidates . add ( 'http://host.docker.internal:8080' ) ; // Docker Desktop
29- candidates . add ( 'http://traefik:8080' ) ; // Internal Service Name
23+ // 2. Auto-Discovery Fallbacks
24+ // These are tried if the user URL fails (or isn't provided)
25+ candidates . add ( 'http://127.0.0.1:8080' ) ;
26+ candidates . add ( 'http://172.17.0.1:8080' ) ;
27+ candidates . add ( 'http://host.docker.internal:8080' ) ;
28+ candidates . add ( 'http://traefik:8080' ) ;
3029
31- // 2. Try endpoints sequentially
32- let lastError : Error | null = null ;
30+ let userUrlError : Error | null = null ;
31+ let anySuccess = false ;
3332
3433 for ( const url of candidates ) {
3534 try {
3635 const stats = await this . fetchStats ( url ) ;
3736 if ( stats ) {
38- return stats ; // Success!
37+ anySuccess = true ;
38+ return stats ;
3939 }
4040 } catch ( error : any ) {
41- lastError = error ;
42- // Continue to next candidate...
41+ // If this was the user's specific URL, save the error for reporting
42+ if ( userUrl && url === userUrl ) {
43+ userUrlError = error ;
44+ }
45+ // Continue to next candidate
4346 }
4447 }
4548
46- // 3. Log warning only if ALL candidates failed
47- if ( lastError ) {
48- const code = ( lastError as any ) . code ;
49- // Suppress common connectivity errors to avoid log spam
50- if ( code !== 'ECONNREFUSED' && code !== 'ETIMEDOUT' && code !== 'ECONNRESET' ) {
51- logger . warn ( `[Traefik] Failed to collect stats from any candidate. Last error: ${ lastError . message } ` ) ;
49+ // 3. Robust Error Reporting
50+ if ( ! anySuccess ) {
51+ // If the user explicitly configured a URL, report WHY that one failed.
52+ // This hides the noise of "ENOTFOUND traefik" which is expected in fallbacks.
53+ if ( userUrl && userUrlError ) {
54+ const code = ( userUrlError as any ) . code ;
55+ const status = ( userUrlError as any ) . response ?. status ;
56+ const msg = ( userUrlError as any ) . message ;
57+
58+ // Log detailed auth errors
59+ if ( status === 401 || status === 403 ) {
60+ logger . warn ( `[Traefik] Auth failed for configured URL (${ userUrl } ). Check username/password. (${ status } )` ) ;
61+ } else {
62+ logger . warn ( `[Traefik] Configured URL (${ userUrl } ) failed: ${ msg } [${ code || 'HTTP Error' } ]` ) ;
63+ }
64+ } else {
65+ // General failure (Auto-discovery failed everywhere)
66+ // We log a generic warning, avoiding specific "ENOTFOUND" noise unless debug
67+ // logger.debug(...) could be used here if you had a debug level
68+ logger . debug ( userUrlError ) ;
5269 }
5370 }
5471
@@ -72,7 +89,7 @@ export class TraefikIntegration extends BaseIntegration {
7289 const httpsAgent = new https . Agent ( { rejectUnauthorized : false } ) ;
7390
7491 const response = await axios . get ( endpoint , {
75- timeout : 2000 ,
92+ timeout : 3000 ,
7693 ...authConfig ,
7794 httpsAgent
7895 } ) ;
0 commit comments