diff --git a/.eslintrc b/.eslintrc index 3589f2c5..abab857f 100644 --- a/.eslintrc +++ b/.eslintrc @@ -13,6 +13,7 @@ "globals": { "SELECT": true, "INSERT": true, + "UPSERT": true, "UPDATE": true, "DELETE": true, "CREATE": true, diff --git a/hello/srv/world.js b/hello/srv/world.js index ff1a370e..c5cd2495 100644 --- a/hello/srv/world.js +++ b/hello/srv/world.js @@ -1,3 +1,7 @@ module.exports = class say { - hello(req) { return `Hello ${req.data.to}!` } + hello(req) { + let {to} = req.data + if (to === 'me') to = require('os').userInfo().username + return `Hello ${to}!` + } } diff --git a/loggers/app/loggers.html b/loggers/app/loggers.html new file mode 100644 index 00000000..2d588e7b --- /dev/null +++ b/loggers/app/loggers.html @@ -0,0 +1,76 @@ + + + + + cds.log + + + + + + + +
+

Log Levels

+ + + + + + + + + + +
Module ID Log Level
{{ each.id }} +
+

Log Format:

+ [ + | + | + | + | + ] - log message ... +
+ + + + + diff --git a/loggers/package.json b/loggers/package.json new file mode 100644 index 00000000..4f76f7f2 --- /dev/null +++ b/loggers/package.json @@ -0,0 +1,22 @@ +{ + "name": "@capire/loggers", + "version": "1.0.0", + "description": "Simple sample on how to dynamically set cds.log levels and formats.", + "files": [ + "app", + "srv" + ], + "dependencies": { + "@sap/cds": ">=5.9", + "express": "^4.17.1" + }, + "scripts": { + "start": "cds run", + "watch": "cds watch" + }, + "cds": { + "requires": { + "db": "sql" + } + } +} diff --git a/loggers/readme.md b/loggers/readme.md new file mode 100644 index 00000000..c030f889 --- /dev/null +++ b/loggers/readme.md @@ -0,0 +1,11 @@ +# Dynamically Set `cds.log` Levels and Formats + +### Run + +```sh +cds watch +``` + +### Test + +Either using the UI through http://localhost:4004/loggers.html, or try the requests in `test/requests.http` diff --git a/loggers/srv/dummy.cds b/loggers/srv/dummy.cds new file mode 100644 index 00000000..7ed8e09d --- /dev/null +++ b/loggers/srv/dummy.cds @@ -0,0 +1,3 @@ +service Sue { + entity Dummy { key ID: UUID; title: String; } +} diff --git a/loggers/srv/loggers.cds b/loggers/srv/loggers.cds new file mode 100644 index 00000000..280ca33b --- /dev/null +++ b/loggers/srv/loggers.cds @@ -0,0 +1,20 @@ +@rest service LogService { + + @readonly entity Loggers : Logger {}; + entity Logger { + key id : String; + level : String; + } + + action format ( + timestamp : Boolean, + level : Boolean, + tenant : Boolean, + reqid : Boolean, + id : Boolean, + ); + + action debug (logger : String) returns Logger; + action reset (logger : String) returns Logger; + +} diff --git a/loggers/srv/loggers.js b/loggers/srv/loggers.js new file mode 100644 index 00000000..7d0473b8 --- /dev/null +++ b/loggers/srv/loggers.js @@ -0,0 +1,56 @@ +const cds = require ('@sap/cds/lib') +const LOG = cds.log('cds.log') + +module.exports = class LogService extends cds.Service { + init(){ + + this.on('GET','Loggers', (req)=>{ + let loggers = Object.values(cds.log.loggers).map (_logger) + let {$search} = req._.req.query + if ($search) { + const re = RegExp($search,'i') + loggers = loggers.filter (l => re.test(l.id) || re.test(l.level)) + } + return loggers + }) + + this.on('PUT','Logger', (req)=>{ + const {id} = req.params[0] || req.data + if (!id) return req.reject('No logger id specified in request') + return _logger (cds.log (id, req.data)) + }) + + this.on('debug', (req)=>{ + const {logger:id} = req.params[0] || req.data + if (!id) return req.reject('No logger id specified in request') + return _logger (cds.log (id, {level:'debug'})) + }) + + this.on('reset', (req)=>{ + const {logger:id} = req.params[0] || req.data + if (!id) return req.reject('No logger id specified in request') + return _logger (cds.log (id, {level:'info'})) + }) + + this.on('format', (req)=>{ + const $ = req.data; LOG.info('format:',$) + // Set format for new loggers constructed subsequently + cds.log.format = (id, level, ...args) => { + const fmt = [] + if ($.timestamp) fmt.push ('|', (new Date).toISOString()) + if ($.level) fmt.push ('|', _levels[level].padEnd(5)) + if ($.tenant) fmt.push ('|', cds.context && cds.context.tenant) + if ($.reqid) fmt.push ('|', cds.context && cds.context.id) + if ($.id) fmt.push ('|', id) + fmt[0] = '[', fmt.push ('] -', ...args) + return fmt + } + // Apply this format to all existing loggers + Object.values(cds.log.loggers).forEach (l => l.setFormat (cds.log.format)) + }) + } + +} + +const _logger = ({id,level}) => ({id, level:_levels[level] }) +const _levels = [ 'SILENT', 'ERROR', 'WARN', 'INFO', 'DEBUG', 'TRACE' ] diff --git a/loggers/test/requests.http b/loggers/test/requests.http new file mode 100644 index 00000000..904d44bf --- /dev/null +++ b/loggers/test/requests.http @@ -0,0 +1,18 @@ +http://localhost:4004/loggers.html +@body: = Content-Type: application/json\n\n + +### +GET http://localhost:4004/log/Loggers + +### +PUT http://localhost:4004/log/Logger/sqlite +{{body:}} { "level": "debug" } + +### +POST http://localhost:4004/log/debug(logger='sqlite') + +### +POST http://localhost:4004/log/reset(logger='sqlite') + +### Dummy request to see sqlite debug output +GET http://localhost:4004/sue/Dummy diff --git a/package.json b/package.json index 1d0bd55e..f2001e6f 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "./hello", "./media", "./orders", + "./loggers", "./reviews" ], "devDependencies": {