web-log-viewer 0.0.3 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -14
- package/build/public/build/bundle.css +1 -1
- package/build/public/build/bundle.js +1 -1
- package/build/public/build/bundle.js.map +1 -1
- package/build/public/index.html +1 -0
- package/build/server.js +68 -29
- package/package.json +15 -3
- package/.prettierrc +0 -9
- package/app-console.js +0 -28
- package/nginx.log +0 -51462
- package/produce-log.sh +0 -3
- package/src/config.ts +0 -28
- package/src/defaultMessageParser.ts +0 -16
- package/src/log-index.ts +0 -44
- package/src/server.ts +0 -135
- package/src/stream-utils.ts +0 -28
- package/src/types.ts +0 -51
- package/svelte/.vscode/extensions.json +0 -3
- package/svelte/package-lock.json +0 -998
- package/svelte/package.json +0 -33
- package/svelte/public/favicon.png +0 -0
- package/svelte/public/global.css +0 -104
- package/svelte/public/index.html +0 -18
- package/svelte/rollup.config.js +0 -88
- package/svelte/src/App.svelte +0 -285
- package/svelte/src/LogMessageDetails.svelte +0 -166
- package/svelte/src/log-formatter.ts +0 -21
- package/svelte/src/log-store.ts +0 -209
- package/svelte/src/main.ts +0 -8
- package/svelte/src/types.ts +0 -51
- package/svelte/tsconfig.json +0 -6
- package/tsconfig.json +0 -71
package/produce-log.sh
DELETED
package/src/config.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander'
|
|
2
|
-
import { extractIndexTokens as extractIndexTokensFn } from './log-index'
|
|
3
|
-
|
|
4
|
-
const program = new Command('web-log-viewer')
|
|
5
|
-
program.version('0.0.1')
|
|
6
|
-
program.option('--port <port>', 'specify the port where the server will run', '8000')
|
|
7
|
-
program.option(
|
|
8
|
-
'-p, --parser <filename>',
|
|
9
|
-
'specify the script used for parsing lines of text from stdin and converting them to JSON. Defaults to parse using `json5` (https://www.npmjs.com/package/json5)',
|
|
10
|
-
)
|
|
11
|
-
program.option(
|
|
12
|
-
'-k, --index-keys',
|
|
13
|
-
'allow searching by the log object keys, instead of just its values',
|
|
14
|
-
false,
|
|
15
|
-
)
|
|
16
|
-
program.option('-s, --stdout', 'log every message coming in to stdout', false)
|
|
17
|
-
|
|
18
|
-
program.parse(process.argv)
|
|
19
|
-
const options = program.opts()
|
|
20
|
-
|
|
21
|
-
const config = {
|
|
22
|
-
port: options.port || 8000,
|
|
23
|
-
stdout: options.stdout || false,
|
|
24
|
-
parseRawMessage: options.parser ? require(options.parser) : require('./defaultMessageParser'),
|
|
25
|
-
extractIndexTokens: extractIndexTokensFn({ includeObjectKeys: options.indexKeys }),
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export { config }
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import json5 from 'json5'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Default parser implementation, that transforms a string (usually a single
|
|
5
|
-
* line of text coming in from **stdin**) into a JSON object containing the data
|
|
6
|
-
* present in a log message
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
module.exports = (rawMessage: string) => {
|
|
10
|
-
try {
|
|
11
|
-
return json5.parse(rawMessage)
|
|
12
|
-
} catch (err) {
|
|
13
|
-
const msg = { message: rawMessage }
|
|
14
|
-
return msg
|
|
15
|
-
}
|
|
16
|
-
}
|
package/src/log-index.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
type Tokens = string[]
|
|
2
|
-
|
|
3
|
-
interface Config {
|
|
4
|
-
includeObjectKeys: boolean
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
const extractIndexTokens = (cfg: Config) => (obj: Object, tokens: Tokens = []): Tokens => {
|
|
8
|
-
let newTokens = [...tokens]
|
|
9
|
-
if (cfg.includeObjectKeys) {
|
|
10
|
-
newTokens = [...newTokens, ...Object.keys(obj)]
|
|
11
|
-
}
|
|
12
|
-
return Object.values(obj).reduce((acc, val) => {
|
|
13
|
-
if (!val) {
|
|
14
|
-
return acc
|
|
15
|
-
} else if (typeof val !== 'object') {
|
|
16
|
-
return [...acc, removeDiacritics(val.toString())]
|
|
17
|
-
} else {
|
|
18
|
-
return extractIndexTokens(cfg)(val, acc)
|
|
19
|
-
}
|
|
20
|
-
}, newTokens)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// see: https://github.com/esamattis/underscore.string
|
|
24
|
-
const removeDiacritics = (str: string) => {
|
|
25
|
-
const accents = 'ąàáäâãåæăćčĉęèéëêĝĥìíïîĵłľńňòóöőôõðøśșşšŝťțţŭùúüűûñÿýçżźž'
|
|
26
|
-
const result = 'aaaaaaaaaccceeeeeghiiiijllnnoooooooossssstttuuuuuunyyczzz'
|
|
27
|
-
|
|
28
|
-
return str.toLowerCase().replace(/.{1}/g, function (c: string) {
|
|
29
|
-
var index = accents.indexOf(c)
|
|
30
|
-
return index === -1 ? c : result[index]
|
|
31
|
-
})
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const isIndexMatch = (filter: string) => {
|
|
35
|
-
if (!filter) {
|
|
36
|
-
return () => true
|
|
37
|
-
}
|
|
38
|
-
const tokens = removeDiacritics(filter).split(/\s+/)
|
|
39
|
-
return (index: Tokens) => tokens.every(token => index.find(isSingleMatch(token)))
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const isSingleMatch = (tokenToSearch: string) => (data: string) => data.indexOf(tokenToSearch) != -1
|
|
43
|
-
|
|
44
|
-
export { extractIndexTokens, isIndexMatch }
|
package/src/server.ts
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { map, runEffects, tap } from '@most/core'
|
|
2
|
-
import { newDefaultScheduler } from '@most/scheduler'
|
|
3
|
-
import express from 'express'
|
|
4
|
-
import http from 'http'
|
|
5
|
-
import { pipe } from 'ramda'
|
|
6
|
-
import WebSocket from 'ws'
|
|
7
|
-
import { createReadlineStream } from './stream-utils'
|
|
8
|
-
import { ClientMessage, LogMessage, ServerMessage } from './types'
|
|
9
|
-
import { config } from './config'
|
|
10
|
-
import { isIndexMatch } from './log-index'
|
|
11
|
-
import path from 'path'
|
|
12
|
-
|
|
13
|
-
const LOG_WINDOW_SIZE = 100
|
|
14
|
-
|
|
15
|
-
type ClientStatus =
|
|
16
|
-
| { mode: 'tail' }
|
|
17
|
-
| {
|
|
18
|
-
mode: 'static'
|
|
19
|
-
// the `seq` of the first message the client is locked on
|
|
20
|
-
start: number
|
|
21
|
-
}
|
|
22
|
-
const clients: ClientStatus[] = []
|
|
23
|
-
|
|
24
|
-
/**Contains all the logs that came into the server up until now */
|
|
25
|
-
const logs: LogMessage[] = []
|
|
26
|
-
|
|
27
|
-
// setup the server
|
|
28
|
-
const app = express()
|
|
29
|
-
app.use(express.static(path.join(__dirname, 'public')))
|
|
30
|
-
const server = http.createServer(app)
|
|
31
|
-
const wss = new WebSocket.Server({ server })
|
|
32
|
-
|
|
33
|
-
//start our server
|
|
34
|
-
server.listen(config.port, () => {
|
|
35
|
-
const address = server.address()
|
|
36
|
-
if (address) {
|
|
37
|
-
console.log(
|
|
38
|
-
`Started on ${
|
|
39
|
-
typeof address == 'string' ? address : `${address.port}`
|
|
40
|
-
}. Waiting for log messages on stdin...`,
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
// setup the log stream from stdin to clients
|
|
44
|
-
const logStream = setupLogStream()()
|
|
45
|
-
runEffects(logStream, newDefaultScheduler())
|
|
46
|
-
|
|
47
|
-
// waits for WS clients to connect
|
|
48
|
-
wss.on('connection', setupNewClient)
|
|
49
|
-
}
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Sets up the stream that receives messages from **stdin** and
|
|
54
|
-
* pipes them to all registered clients using websockets.
|
|
55
|
-
*/
|
|
56
|
-
const setupLogStream = () =>
|
|
57
|
-
pipe(
|
|
58
|
-
() => createReadlineStream(),
|
|
59
|
-
tap(rawMessage => {
|
|
60
|
-
if (config.stdout) {
|
|
61
|
-
console.log(rawMessage)
|
|
62
|
-
}
|
|
63
|
-
}),
|
|
64
|
-
map(rawMessage => {
|
|
65
|
-
const data = config.parseRawMessage(rawMessage)
|
|
66
|
-
const msg: LogMessage = {
|
|
67
|
-
seq: logs.length + 1,
|
|
68
|
-
data,
|
|
69
|
-
index: config.extractIndexTokens(data),
|
|
70
|
-
}
|
|
71
|
-
logs.push(msg)
|
|
72
|
-
return msg
|
|
73
|
-
}),
|
|
74
|
-
tap((rawLog: LogMessage) => {
|
|
75
|
-
const updateMsg: ServerMessage = {
|
|
76
|
-
type: 'update',
|
|
77
|
-
size: logs.length,
|
|
78
|
-
message: rawLog,
|
|
79
|
-
}
|
|
80
|
-
wss.clients.forEach(ws => {
|
|
81
|
-
ws.send(encode(updateMsg))
|
|
82
|
-
})
|
|
83
|
-
}),
|
|
84
|
-
)
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Function executed every time a new WS client connects to the server.
|
|
88
|
-
* This will send a `InitMessage` to that client, so it can immediately start showing to the user.
|
|
89
|
-
*/
|
|
90
|
-
function setupNewClient(ws: WebSocket) {
|
|
91
|
-
const clientId = clients.length
|
|
92
|
-
clients.push({ mode: 'tail' })
|
|
93
|
-
|
|
94
|
-
// send a window with the last logs to newly registered clients
|
|
95
|
-
ws.send(encode(buildTailMessage('')))
|
|
96
|
-
|
|
97
|
-
ws.on('message', encodedMsg => {
|
|
98
|
-
const msg = decode(encodedMsg) as ClientMessage
|
|
99
|
-
if (msg.mode == 'tail') {
|
|
100
|
-
ws.send(encode(buildTailMessage(msg.filter)))
|
|
101
|
-
} else if (msg.mode == 'static') {
|
|
102
|
-
ws.send(encode(buildStaticMessage(msg.filter, msg.offsetSeq)))
|
|
103
|
-
}
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
function buildTailMessage(filter: string): ServerMessage {
|
|
107
|
-
const matcher = isIndexMatch(filter)
|
|
108
|
-
const filteredLogs = logs.filter(l => matcher(l.index)).map((l, i) => ({ ...l, seq: i + 1 }))
|
|
109
|
-
return {
|
|
110
|
-
type: 'init',
|
|
111
|
-
mode: 'tail',
|
|
112
|
-
size: filteredLogs.length,
|
|
113
|
-
offsetSeq: -1,
|
|
114
|
-
window: filteredLogs.slice(-LOG_WINDOW_SIZE),
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function buildStaticMessage(filter: string, offsetSeq: number): ServerMessage {
|
|
119
|
-
const matcher = isIndexMatch(filter)
|
|
120
|
-
const filteredLogs = logs.filter(l => matcher(l.index)).map((l, i) => ({ ...l, seq: i + 1 }))
|
|
121
|
-
return {
|
|
122
|
-
type: 'init',
|
|
123
|
-
mode: 'static',
|
|
124
|
-
size: filteredLogs.length,
|
|
125
|
-
offsetSeq,
|
|
126
|
-
window: filteredLogs.slice(
|
|
127
|
-
Math.max(offsetSeq - LOG_WINDOW_SIZE / 2, 0),
|
|
128
|
-
offsetSeq + LOG_WINDOW_SIZE / 2,
|
|
129
|
-
),
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const encode = (data: ServerMessage) => JSON.stringify(data)
|
|
135
|
-
const decode = (data: WebSocket.Data): ClientMessage => JSON.parse(data.toString('utf-8'))
|
package/src/stream-utils.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { createAdapter } from "@most/adapter";
|
|
2
|
-
import * as readline from "readline";
|
|
3
|
-
import json5 from "json5";
|
|
4
|
-
|
|
5
|
-
const memoizedFromJson = (s: string) => {
|
|
6
|
-
try {
|
|
7
|
-
return json5.parse(s);
|
|
8
|
-
} catch (err) {
|
|
9
|
-
return {};
|
|
10
|
-
}
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
const createReadlineStream = () => {
|
|
14
|
-
const [induce, readlineStream] = createAdapter<string>();
|
|
15
|
-
|
|
16
|
-
const rl = readline.createInterface({
|
|
17
|
-
input: process.stdin,
|
|
18
|
-
output: process.stdout,
|
|
19
|
-
terminal: false,
|
|
20
|
-
});
|
|
21
|
-
rl.on("line", (line) => {
|
|
22
|
-
induce(line);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
return readlineStream;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export { memoizedFromJson, createReadlineStream };
|
package/src/types.ts
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
type OperationMode = 'static' | 'tail'
|
|
2
|
-
|
|
3
|
-
/**A log message has sent by the server to the clients */
|
|
4
|
-
type LogMessage = {
|
|
5
|
-
seq: number
|
|
6
|
-
data: Record<string, any>
|
|
7
|
-
index: string[]
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/**A log message that's already been formatted and ready to be displayed */
|
|
11
|
-
type FormattedMessage = {
|
|
12
|
-
seq: number
|
|
13
|
-
rawMessage: Record<string, any>
|
|
14
|
-
formattedMessage: Record<string, any>
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**A function that formats a log message */
|
|
18
|
-
type LogFormatter = Record<string, LogColumnFormatter>
|
|
19
|
-
type LogColumnFormatter = (message: LogMessage['data'], seq: number) => any
|
|
20
|
-
|
|
21
|
-
// ***
|
|
22
|
-
// SERVER MESSAGES
|
|
23
|
-
// ***
|
|
24
|
-
|
|
25
|
-
// the message sent to clients that either just connected or changed operation model (tail <-> static)
|
|
26
|
-
type InitMessage = {
|
|
27
|
-
type: 'init'
|
|
28
|
-
mode: OperationMode
|
|
29
|
-
size: number
|
|
30
|
-
offsetSeq: number
|
|
31
|
-
window: LogMessage[]
|
|
32
|
-
}
|
|
33
|
-
// the message sent to all clients once a new message comes in from stdin
|
|
34
|
-
type UpdateMessage = { type: 'update'; size: number; message: LogMessage }
|
|
35
|
-
// all messages in the direction Server -> Client
|
|
36
|
-
type ServerMessage = InitMessage | UpdateMessage
|
|
37
|
-
|
|
38
|
-
// CLIENT MESSAGES
|
|
39
|
-
type StaticClientMessage = { mode: 'static'; filter: string; offsetSeq: number }
|
|
40
|
-
type TailClientMessage = { mode: 'tail'; filter: string }
|
|
41
|
-
/**Messages sent from the client to the server, basically to signal it want to swith operation mode */
|
|
42
|
-
type ClientMessage = StaticClientMessage | TailClientMessage
|
|
43
|
-
|
|
44
|
-
export type {
|
|
45
|
-
LogMessage,
|
|
46
|
-
FormattedMessage,
|
|
47
|
-
LogFormatter,
|
|
48
|
-
LogColumnFormatter,
|
|
49
|
-
ServerMessage,
|
|
50
|
-
ClientMessage,
|
|
51
|
-
}
|