• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

dev-ignis / cross-log / 17016589983

17 Aug 2025 04:13AM UTC coverage: 87.462% (+1.8%) from 85.706%
17016589983

push

github

dev-ignis
test: - threshold;

673 of 840 branches covered (80.12%)

Branch coverage included in aggregate %.

1071 of 1154 relevant lines covered (92.81%)

393.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.58
/src/plugins/database.ts
1
import { PluginContext, DatabasePlugin, DatabasePluginConfig, PluginInstance } from './types';
2
import { TypedPlugin } from './plugin-types';
3

4
export class DatabaseQueryPlugin implements TypedPlugin<'database'> {
30✔
5
  name: 'database' = 'database';
168✔
6
  version = '1.0.0';
168✔
7
  config: DatabasePluginConfig;
8
  methods?: DatabasePlugin;
9
  private context?: PluginContext;
10

11
  constructor(config?: DatabasePluginConfig) {
12
    this.config = {
168✔
13
      enabled: true,
14
      truncateQueries: 200,
15
      includeParams: false,
16
      slowQueryThreshold: 1000,
17
      ...config
18
    };
19
  }
20

21
  init(context: PluginContext): void {
22
    this.context = context;
156✔
23

24
    const methods: DatabasePlugin = {
156✔
25
      query: this.query.bind(this),
26
      error: this.error.bind(this),
27
      transaction: this.transaction.bind(this),
28
      slowQuery: this.slowQuery.bind(this)
29
    };
30

31
    (context as any).methods = methods;
156✔
32
    
33
    const instance = context as unknown as PluginInstance;
156✔
34
    instance.methods = methods as any;
156✔
35
  }
36

37
  private truncateQuery(sql: string): string {
38
    if (!this.config.truncateQueries || sql.length <= this.config.truncateQueries) {
99✔
39
      return sql;
93✔
40
    }
41
    return sql.substring(0, this.config.truncateQueries) + '...';
6✔
42
  }
43

44
  private formatDuration(duration?: number): string {
45
    if (duration === undefined) return '';
87!
46
    if (duration < 1000) return `${duration}ms`;
87✔
47
    return `${(duration / 1000).toFixed(2)}s`;
27✔
48
  }
49

50
  private sanitizeQuery(sql: string): string {
51
    return sql.replace(/\s+/g, ' ').trim();
51✔
52
  }
53

54
  query(sql: string, duration?: number, rowCount?: number, params?: any[]): void {
55
    if (!this.context || !this.config.enabled) return;
30!
56

57
    const sanitizedSql = this.sanitizeQuery(sql);
30✔
58
    const logData: Record<string, any> = {
30✔
59
      type: 'database_query',
60
      query: this.truncateQuery(sanitizedSql),
61
      timestamp: new Date().toISOString()
62
    };
63

64
    if (duration !== undefined) {
30✔
65
      logData.duration = this.formatDuration(duration);
30✔
66
      logData.durationMs = duration;
30✔
67

68
      if (this.config.slowQueryThreshold && duration >= this.config.slowQueryThreshold) {
30✔
69
        this.slowQuery(sql, duration, params);
3✔
70
        return;
3✔
71
      }
72
    }
73

74
    if (rowCount !== undefined) {
27✔
75
      logData.rowCount = rowCount;
27✔
76
    }
77

78
    if (this.config.includeParams && params) {
27!
79
      logData.params = params;
×
80
    }
81

82
    const message = `Database Query: ${this.truncateQuery(sanitizedSql)}${
27✔
83
      duration !== undefined ? ` (${this.formatDuration(duration)})` : ''
27!
84
    }${rowCount !== undefined ? ` - ${rowCount} rows` : ''}`;
27!
85

86
    this.context.logger.debug(message, 'Database', logData);
27✔
87
  }
88

89
  error(sql: string, error: Error | string, params?: any[]): void {
90
    if (!this.context || !this.config.enabled) return;
9!
91

92
    const sanitizedSql = this.sanitizeQuery(sql);
9✔
93
    const logData: Record<string, any> = {
9✔
94
      type: 'database_error',
95
      query: this.truncateQuery(sanitizedSql),
96
      error: error instanceof Error ? {
9✔
97
        message: error.message,
98
        stack: error.stack,
99
        name: error.name,
100
        code: (error as any).code
101
      } : error,
102
      timestamp: new Date().toISOString()
103
    };
104

105
    if (this.config.includeParams && params) {
9!
106
      logData.params = params;
×
107
    }
108

109
    const message = `Database Error: ${this.truncateQuery(sanitizedSql)} - ${
9✔
110
      error instanceof Error ? error.message : error
9✔
111
    }`;
112

113
    this.context.logger.error(message, 'Database', logData);
9✔
114
  }
115

116
  transaction(id: string, action: 'begin' | 'commit' | 'rollback', duration?: number): void {
117
    if (!this.context || !this.config.enabled) return;
12!
118

119
    const logData: Record<string, any> = {
12✔
120
      type: 'database_transaction',
121
      transactionId: id,
122
      action,
123
      timestamp: new Date().toISOString()
124
    };
125

126
    if (duration !== undefined) {
12✔
127
      logData.duration = this.formatDuration(duration);
3✔
128
      logData.durationMs = duration;
3✔
129
    }
130

131
    const message = `Database Transaction: ${action.toUpperCase()} ${id}${
12✔
132
      duration !== undefined ? ` (${this.formatDuration(duration)})` : ''
12✔
133
    }`;
134

135
    const level = action === 'rollback' ? 'warn' : 'info';
12✔
136
    
137
    if (level === 'warn') {
12✔
138
      this.context.logger.warn(message, 'Database', logData);
3✔
139
    } else {
140
      this.context.logger.info(message, 'Database', logData);
9✔
141
    }
142
  }
143

144
  slowQuery(sql: string, duration: number, params?: any[]): void {
145
    if (!this.context || !this.config.enabled) return;
12!
146

147
    const sanitizedSql = this.sanitizeQuery(sql);
12✔
148
    const logData: Record<string, any> = {
12✔
149
      type: 'database_slow_query',
150
      query: this.truncateQuery(sanitizedSql),
151
      duration: this.formatDuration(duration),
152
      durationMs: duration,
153
      threshold: this.config.slowQueryThreshold,
154
      timestamp: new Date().toISOString()
155
    };
156

157
    if (this.config.includeParams && params) {
12!
158
      logData.params = params;
×
159
    }
160

161
    const message = `Slow Database Query: ${this.truncateQuery(sanitizedSql)} - ${this.formatDuration(duration)} (threshold: ${this.config.slowQueryThreshold}ms)`;
12✔
162

163
    this.context.logger.warn(message, 'Database', logData);
12✔
164
  }
165

166
  destroy(): void {
167
    this.context = undefined;
9✔
168
  }
169
}
170

171
export function createDatabasePlugin(config?: DatabasePluginConfig): DatabaseQueryPlugin {
30✔
172
  return new DatabaseQueryPlugin(config);
168✔
173
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc