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

RobotWebTools / rclnodejs / 19852408168

02 Dec 2025 08:42AM UTC coverage: 82.719% (-0.03%) from 82.751%
19852408168

Pull #1336

github

web-flow
Merge f0627beb2 into 2221b4ae6
Pull Request #1336: Support logging rosout

1099 of 1457 branches covered (75.43%)

Branch coverage included in aggregate %.

29 of 30 new or added lines in 3 files covered. (96.67%)

32 existing lines in 1 file now uncovered.

2491 of 2883 relevant lines covered (86.4%)

486.03 hits per line

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

74.74
/lib/logging.js
1
// Copyright (c) 2018 Intel Corporation. All rights reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
'use strict';
16

17
const path = require('path');
26✔
18
const rclnodejs = require('./native_loader.js');
26✔
19
const { TypeValidationError } = require('./errors.js');
26✔
20

21
/**
22
 * Enum for LoggingSeverity
23
 * @readonly
24
 * @enum {number}
25
 */
26
let LoggingSeverity = {
26✔
27
  /** @member {number} */
28
  UNSET: 0,
29
  /** @member {number} */
30
  DEBUG: 10,
31
  /** @member {number} */
32
  INFO: 20,
33
  /** @member {number} */
34
  WARN: 30,
35
  /** @member {number} */
36
  ERROR: 40,
37
  /** @member {number} */
38
  FATAL: 50,
39
};
40

41
class Caller {
42
  constructor() {
43
    this._info = {
157✔
44
      functionName: 'unknown',
45
      fileName: 'unknown',
46
      lineNumber: 'unknown',
47
    };
48

49
    const stackLines = new Error().stack.split('\n');
157✔
50

51
    // Adjust the index (usually 3 or 4) to correctly point to the caller frame.
52
    const callerFrame = stackLines[4] || stackLines[3];
157!
53
    // Match both named and anonymous function stack frames.
54
    const frameRegex = /^\s*at\s+(?:(.+)\s+\()?(.+):(\d+):(\d+)\)?$/;
157✔
55
    const match = callerFrame.match(frameRegex);
157✔
56
    if (match && match.length === 5) {
157!
57
      this._info.functionName = match[1] || '(anonymous)';
157✔
58
      this._info.fileName = path.basename(match[2]);
157✔
59
      this._info.lineNumber = match[3];
157✔
60
    } else {
61
      // Handle anonymous functions or different stack formats.
62
      const altMatch = callerFrame.match(/at\s+(.*):(\d+):(\d+)/i);
×
63
      if (altMatch && altMatch.length >= 4) {
×
64
        this._info.functionName = '(anonymous)';
×
65
        this._info.fileName = path.basename(altMatch[1]);
×
66
        this._info.lineNumber = altMatch[2];
×
67
      }
68
    }
69
  }
70

71
  get functionName() {
72
    return this._info.functionName;
157✔
73
  }
74

75
  get lineNumber() {
76
    return this._info.lineNumber;
157✔
77
  }
78

79
  get fileName() {
80
    return this._info.fileName;
157✔
81
  }
82
}
83

84
/**
85
 * @class - Class representing logger in ROS
86
 * @hideconstructor
87
 */
88

89
class Logging {
90
  constructor(name) {
91
    this._name = name;
797✔
92
    this._parentName = null;
797✔
93
    this._subName = null;
797✔
94
  }
95

96
  /**
97
   * Set the logging severity level.
98
   * @param {LoggingSeverity} level - The logging severity level.
99
   * @function
100
   * @return {undefined}
101
   */
102
  setLoggerLevel(level) {
103
    if (typeof level !== 'number') {
3!
104
      throw new TypeValidationError('level', level, 'number', {
×
105
        entityType: 'logger',
106
        entityName: this._name,
107
      });
108
    }
109
    rclnodejs.setLoggerLevel(this._name, level);
3✔
110
  }
111

112
  /**
113
   * Get the logging severity level.
114
   * @function
115
   * @return {LoggingSeverity} - The severity level of the logger.
116
   */
117
  get loggerEffectiveLevel() {
118
    return rclnodejs.getLoggerEffectiveLevel(this._name);
8✔
119
  }
120

121
  /**
122
   * Log a message with the DEBUG severity.
123
   * @param {string} message - message to be logged.
124
   * @function
125
   * @return {bool} Return true if the message has been logged.
126
   */
127
  debug(message) {
128
    return this._log(message, LoggingSeverity.DEBUG);
136✔
129
  }
130

131
  /**
132
   * Log a message with the INFO severity.
133
   * @param {string} message - message to be logged.
134
   * @function
135
   * @return {bool} Return true if the message has been logged.
136
   */
137
  info(message) {
138
    return this._log(message, LoggingSeverity.INFO);
6✔
139
  }
140

141
  /**
142
   * Log a message with the WARN severity.
143
   * @param {string} message - message to be logged.
144
   * @function
145
   * @return {bool} Return true if the message has been logged.
146
   */
147
  warn(message) {
148
    return this._log(message, LoggingSeverity.WARN);
8✔
149
  }
150

151
  /**
152
   * Log a message with the ERROR severity.
153
   * @param {string} message - message to be logged.
154
   * @function
155
   * @return {bool} Return true if the message has been logged.
156
   */
157
  error(message) {
158
    return this._log(message, LoggingSeverity.ERROR);
4✔
159
  }
160

161
  /**
162
   * Log a message with the FATAL severity.
163
   * @param {string} message - message to be logged.
164
   * @function
165
   * @return {bool} Return true if the message has been logged.
166
   */
167
  fatal(message) {
168
    return this._log(message, LoggingSeverity.FATAL);
3✔
169
  }
170

171
  _log(message, severity) {
172
    if (typeof message !== 'string') {
157!
173
      throw new TypeValidationError('message', message, 'string', {
×
174
        entityType: 'logger',
175
        entityName: this._name,
176
      });
177
    }
178

179
    let caller = new Caller();
157✔
180
    return rclnodejs.log(
157✔
181
      this._name,
182
      severity,
183
      message,
184
      caller.functionName,
185
      parseInt(caller.lineNumber, 10),
186
      caller.fileName
187
    );
188
  }
189

190
  /**
191
   * Get LoggingSeverity enum.
192
   * @function
193
   * @return {LoggingSeverity} Return LoggingSeverity enum.
194
   */
195
  get LoggingSeverity() {
196
    return LoggingSeverity;
11✔
197
  }
198

199
  /**
200
   * Get name of the logger.
201
   * @function
202
   * @return {string} logger's name.
203
   */
204
  get name() {
205
    return this._name;
3✔
206
  }
207

208
  /**
209
   * Create a child logger.
210
   * @param {string} name - name of the child logger.
211
   * @function
212
   * @return {Logging} Return the child logger object.
213
   */
214
  getChild(name) {
215
    if (typeof name !== 'string' || !name) {
1!
NEW
216
      throw new Error('Child logger name must be a non-empty string.');
×
217
    }
218

219
    let fullname = name;
1✔
220
    if (this._name) {
1!
221
      fullname = this._name + '.' + name;
1✔
222
    }
223

224
    const logger = new Logging(fullname);
1✔
225
    if (this._name) {
1!
226
      if (
1!
227
        rclnodejs.addRosoutSublogger &&
2✔
228
        rclnodejs.addRosoutSublogger(this._name, name)
229
      ) {
230
        logger._parentName = this._name;
1✔
231
        logger._subName = name;
1✔
232
      }
233
    }
234
    return logger;
1✔
235
  }
236

237
  /**
238
   * Destroy the logger and remove it from the parent logger if it is a child logger.
239
   * @function
240
   * @return {undefined}
241
   */
242
  destroy() {
243
    if (this._parentName && this._subName) {
1!
244
      if (rclnodejs.removeRosoutSublogger) {
1!
245
        rclnodejs.removeRosoutSublogger(this._parentName, this._subName);
1✔
246
      }
247
      this._parentName = null;
1✔
248
      this._subName = null;
1✔
249
    }
250
  }
251

252
  /**
253
   * Create a logger by name.
254
   * @param {string} name - name of the logger.
255
   * @function
256
   * @return {Logging} Return the logger object.
257
   */
258
  static getLogger(name) {
259
    if (typeof name !== 'string') {
15!
260
      throw new TypeValidationError('name', name, 'string', {
×
261
        entityType: 'logger',
262
      });
263
    }
264
    return new Logging(name);
15✔
265
  }
266
}
267

268
module.exports = Logging;
26✔
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