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": {