add LoggingProvider
unified interface for console & remote JSON logging! had to write my own as i don't want to send this information through google. fixup! add LoggingProviderios
parent
816d672383
commit
8010bd0a0c
@ -1,4 +1,11 @@
|
|||||||
|
import { LogLevel, LogOptions } from "./providers/logging/logging";
|
||||||
|
|
||||||
export const COLORS = {
|
export const COLORS = {
|
||||||
PRIMARY: '#4EAF47', // sensebox green
|
PRIMARY: '#4EAF47', // sensebox green
|
||||||
}
|
}
|
||||||
export const DEFAULT_LANG = 'en'
|
export const DEFAULT_LANG = 'en'
|
||||||
|
export const LOG_OPTIONS: LogOptions = {
|
||||||
|
local: LogLevel.INFO,
|
||||||
|
remote: LogLevel.WARN,
|
||||||
|
endpoint: 'https://logs.snsbx.nroo.de/log',
|
||||||
|
}
|
||||||
|
@ -0,0 +1,125 @@
|
|||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { AppVersion } from '@ionic-native/app-version/ngx';
|
||||||
|
import { Platform } from 'ionic-angular';
|
||||||
|
|
||||||
|
import { LOG_OPTIONS } from '../../constants';
|
||||||
|
import { StorageProvider, SETTINGS } from '../storage/storage';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
// these types must be defined here to avoid a circular dependency with LoggingProvider
|
||||||
|
export interface LogOptions {
|
||||||
|
local: boolean | LogLevel,
|
||||||
|
remote: boolean | LogLevel,
|
||||||
|
endpoint: string,
|
||||||
|
}
|
||||||
|
export enum LogLevel {
|
||||||
|
DEBUG = 0,
|
||||||
|
INFO = 1,
|
||||||
|
WARN = 2,
|
||||||
|
ERROR = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class LoggingProvider {
|
||||||
|
private opts: LogOptions = LOG_OPTIONS
|
||||||
|
private defaultFields: any = {}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private http: HttpClient,
|
||||||
|
private plt: Platform,
|
||||||
|
private version: AppVersion,
|
||||||
|
private storage: StorageProvider,
|
||||||
|
private translate: TranslateService,
|
||||||
|
) {
|
||||||
|
if ((<any>window).cordova) {
|
||||||
|
this.version.getPackageName()
|
||||||
|
.then(name => this.defaultFields.app = name)
|
||||||
|
this.version.getVersionNumber()
|
||||||
|
.then(version => this.defaultFields.appVersion = version)
|
||||||
|
}
|
||||||
|
this.defaultFields.platform = this.plt.platforms().join(' ')
|
||||||
|
this.defaultFields.platformVersion = this.plt.version().str
|
||||||
|
this.defaultFields.lang = translate.currentLang
|
||||||
|
}
|
||||||
|
|
||||||
|
createChild (component: string, defaultFields: object = {}) {
|
||||||
|
const child = new LoggingProvider(this.http, this.plt, this.version, this.storage, this.translate)
|
||||||
|
Object.assign(child.defaultFields, defaultFields, { component })
|
||||||
|
return child
|
||||||
|
}
|
||||||
|
|
||||||
|
debug (...data) { return this.log(LogLevel.DEBUG, ...data) }
|
||||||
|
info (...data) { return this.log(LogLevel.INFO, ...data) }
|
||||||
|
warn (...data) { return this.log(LogLevel.WARN, ...data) }
|
||||||
|
error (...data) { return this.log(LogLevel.ERROR, ...data) }
|
||||||
|
|
||||||
|
private log (level: LogLevel, ...fields: (string | object)[]): LogMessage {
|
||||||
|
const msg = this.buildLogMessage(level, ...fields)
|
||||||
|
|
||||||
|
if (this.opts.local !== false && level >= this.opts.local) {
|
||||||
|
this.getLocalLogFunc(msg.level)(msg.time, msg.msg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.opts.remote !== false && level >= this.opts.remote) {
|
||||||
|
if (this.storage.get(SETTINGS).logOptin) {
|
||||||
|
// fire & forget, no async handling as logging should not have impact on application flow
|
||||||
|
this.http.post(this.opts.endpoint, msg, { responseType: 'text' })
|
||||||
|
.toPromise()
|
||||||
|
.catch(console.error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
|
||||||
|
private buildLogMessage (level: LogLevel, ...fields: (string | object)[]): LogMessage {
|
||||||
|
const logentry = { } as LogMessage
|
||||||
|
let msg = ''
|
||||||
|
|
||||||
|
for (const param of fields) {
|
||||||
|
if (typeof param === 'object')
|
||||||
|
Object.assign(logentry, param)
|
||||||
|
else
|
||||||
|
msg = msg ? `${msg} ${param}` : param
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg)
|
||||||
|
logentry.msg = msg
|
||||||
|
|
||||||
|
Object.assign(logentry, this.defaultFields, {
|
||||||
|
time: Date.now(),
|
||||||
|
level,
|
||||||
|
})
|
||||||
|
|
||||||
|
return logentry
|
||||||
|
}
|
||||||
|
|
||||||
|
private getLocalLogFunc (level: LogLevel): (...params: any[]) => any {
|
||||||
|
switch (level) {
|
||||||
|
case LogLevel.DEBUG:
|
||||||
|
case LogLevel.INFO:
|
||||||
|
return console.log
|
||||||
|
|
||||||
|
case LogLevel.WARN:
|
||||||
|
return console.warn
|
||||||
|
|
||||||
|
case LogLevel.ERROR:
|
||||||
|
default:
|
||||||
|
return console.error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LogMessage {
|
||||||
|
level: LogLevel,
|
||||||
|
time: Date,
|
||||||
|
app: string,
|
||||||
|
appVersion: string,
|
||||||
|
platform: string,
|
||||||
|
platformVersion: string,
|
||||||
|
|
||||||
|
component?: string,
|
||||||
|
msg?: string,
|
||||||
|
[k: string]: any,
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const http = require('http')
|
||||||
|
const fs = require('fs')
|
||||||
|
|
||||||
|
const port = process.argv[2] || 4444
|
||||||
|
const logfile = process.argv[3] || '/tmp/logs.json'
|
||||||
|
|
||||||
|
const resHeaders = {
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
'Access-Control-Allow-Headers': 'content-type',
|
||||||
|
'Content-Type': 'text/plain',
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleLog = (req, res) => {
|
||||||
|
let body = ''
|
||||||
|
req.on('data', chunk => {
|
||||||
|
body += chunk.toString()
|
||||||
|
})
|
||||||
|
|
||||||
|
req.on('end', () => {
|
||||||
|
try {
|
||||||
|
const msg = JSON.parse(body)
|
||||||
|
msg.logclient = {
|
||||||
|
ip: req.connection.remoteAddress,
|
||||||
|
ua: req.headers['user-agent']
|
||||||
|
}
|
||||||
|
fileStream.write(JSON.stringify(msg))
|
||||||
|
fileStream.write('\n')
|
||||||
|
|
||||||
|
res.writeHead(200, 'ok', resHeaders)
|
||||||
|
res.end('ok')
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
res.writeHead(400)
|
||||||
|
res.end('invalid payload')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestHandler = (req, res) => {
|
||||||
|
console.log(req.method, req.url)
|
||||||
|
switch(req.method) {
|
||||||
|
case 'OPTIONS':
|
||||||
|
res.writeHead(200, 'ok', resHeaders)
|
||||||
|
return res.end('ok')
|
||||||
|
case 'POST':
|
||||||
|
if (req.url === '/log') return handleLog(req, res)
|
||||||
|
default:
|
||||||
|
res.writeHead(404)
|
||||||
|
return res.end('not found')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileStream = fs.createWriteStream(logfile, 'utf-8')
|
||||||
|
const server = http.createServer(requestHandler)
|
||||||
|
|
||||||
|
server.listen(port, err => {
|
||||||
|
if (err) {
|
||||||
|
console.error(err)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
console.log('listening on', port)
|
||||||
|
console.log('writing to', logfile)
|
||||||
|
})
|
Loading…
Reference in New Issue