Added loggers sample
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
"globals": {
|
"globals": {
|
||||||
"SELECT": true,
|
"SELECT": true,
|
||||||
"INSERT": true,
|
"INSERT": true,
|
||||||
|
"UPSERT": true,
|
||||||
"UPDATE": true,
|
"UPDATE": true,
|
||||||
"DELETE": true,
|
"DELETE": true,
|
||||||
"CREATE": true,
|
"CREATE": true,
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
module.exports = class say {
|
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}!`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
76
loggers/app/loggers.html
Normal file
76
loggers/app/loggers.html
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title> cds.log </title>
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/primitive-ui/dist/css/main.css">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
|
||||||
|
<style>
|
||||||
|
select { border-color: transparent; padding: 4px 12px; margin: 0px; }
|
||||||
|
button { padding: 2px 11px; margin: 0px 4px; font: 90% italic; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="small-container" , style="margin-top: 70px;">
|
||||||
|
<div id='app'>
|
||||||
|
<h1> Log Levels </h1>
|
||||||
|
<input type="text" placeholder="Search by ID or Log Level..." @input="fetch">
|
||||||
|
<table id='loggers'>
|
||||||
|
<thead>
|
||||||
|
<th> Module ID </th>
|
||||||
|
<th> Log Level </th>
|
||||||
|
</thead>
|
||||||
|
<tr v-for="each in list">
|
||||||
|
<td>{{ each.id }}</td>
|
||||||
|
<td><select v-bind:id="each.id" v-model="each.level" @change="set">
|
||||||
|
<option>SILENT</option>
|
||||||
|
<option>ERROR</option>
|
||||||
|
<option>WARN</option>
|
||||||
|
<option>INFO</option>
|
||||||
|
<option>DEBUG</option>
|
||||||
|
<option>TRACE</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<h4>Log Format:</h4>
|
||||||
|
[ <button class="round-button" :class={'muted-button':!format.timestamp} @click="toggle_format" id="timestamp">Timestamp </button>
|
||||||
|
| <button class="round-button" :class={'muted-button':!format.level} @click="toggle_format" id="level">Log Level </button>
|
||||||
|
| <button class="round-button" :class={'muted-button':!format.tenant} @click="toggle_format" id="tenant">Tenant </button>
|
||||||
|
| <button class="round-button" :class={'muted-button':!format.reqid} @click="toggle_format" id="reqid">Request ID </button>
|
||||||
|
| <button class="round-button" :class={'muted-button':!format.id} @click="toggle_format" id="module">Logger ID </button>
|
||||||
|
] - <i>log message ...</i>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
axios.defaults.headers['Content-Type'] = 'application/json'
|
||||||
|
axios.defaults.baseURL = '/log'
|
||||||
|
const loggers = Vue.createApp({ el: '#app',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
format: { timestamp:false, level:false, tenant:false, reqid:false, id:true, },
|
||||||
|
list: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async fetch (eve) {
|
||||||
|
this.list = (await axios.get (`/Loggers${
|
||||||
|
eve && eve.target.value ? `?$search=${eve.target.value}` : ''
|
||||||
|
}`)).data
|
||||||
|
},
|
||||||
|
async set (eve) {
|
||||||
|
const { id, value:level } = eve.target
|
||||||
|
await axios.put (`/Logger/${id}`, {id,level})
|
||||||
|
},
|
||||||
|
async toggle_format (eve) {
|
||||||
|
this.format[eve.target.id] = !this.format[eve.target.id]
|
||||||
|
await axios.post (`/format`, this.format)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}).mount('#app')
|
||||||
|
loggers.fetch() // initially fill list of loggers
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</html>
|
||||||
22
loggers/package.json
Normal file
22
loggers/package.json
Normal file
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
loggers/readme.md
Normal file
11
loggers/readme.md
Normal file
@@ -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`
|
||||||
3
loggers/srv/dummy.cds
Normal file
3
loggers/srv/dummy.cds
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
service Sue {
|
||||||
|
entity Dummy { key ID: UUID; title: String; }
|
||||||
|
}
|
||||||
20
loggers/srv/loggers.cds
Normal file
20
loggers/srv/loggers.cds
Normal file
@@ -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;
|
||||||
|
|
||||||
|
}
|
||||||
56
loggers/srv/loggers.js
Normal file
56
loggers/srv/loggers.js
Normal file
@@ -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' ]
|
||||||
18
loggers/test/requests.http
Normal file
18
loggers/test/requests.http
Normal file
@@ -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
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
"./hello",
|
"./hello",
|
||||||
"./media",
|
"./media",
|
||||||
"./orders",
|
"./orders",
|
||||||
|
"./loggers",
|
||||||
"./reviews"
|
"./reviews"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
Reference in New Issue
Block a user