mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
Log screen in RN app
This commit is contained in:
parent
216a6780cb
commit
e0664167eb
@ -41,6 +41,13 @@ class ScreenHeaderComponent extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
log_press() {
|
||||
this.props.dispatch({
|
||||
type: 'Navigation/NAVIGATE',
|
||||
routeName: 'Log',
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
let key = 0;
|
||||
let menuOptionComponents = [];
|
||||
@ -56,10 +63,10 @@ class ScreenHeaderComponent extends Component {
|
||||
menuOptionComponents.push(<View key={'menuOption_' + key++} style={styles.divider}/>);
|
||||
}
|
||||
|
||||
// menuOptionComponents.push(
|
||||
// <MenuOption value={1} key={'menuOption_' + key++}>
|
||||
// <Text>{_('Configuration')}</Text>
|
||||
// </MenuOption>);
|
||||
menuOptionComponents.push(
|
||||
<MenuOption value={() => this.log_press()} key={'menuOption_' + key++}>
|
||||
<Text>{_('Log')}</Text>
|
||||
</MenuOption>);
|
||||
|
||||
let title = 'title' in this.props && this.props.title !== null ? this.props.title : _(this.props.navState.routeName);
|
||||
|
||||
|
62
ReactNativeClient/lib/components/screens/log.js
Normal file
62
ReactNativeClient/lib/components/screens/log.js
Normal file
@ -0,0 +1,62 @@
|
||||
import React, { Component } from 'react';
|
||||
import { ListView, View, Text } from 'react-native';
|
||||
import { connect } from 'react-redux'
|
||||
import { Log } from 'lib/log.js'
|
||||
import { reg } from 'lib/registry.js'
|
||||
import { ScreenHeader } from 'lib/components/screen-header.js';
|
||||
import { time } from 'lib/time-utils'
|
||||
|
||||
class LogScreenComponent extends React.Component {
|
||||
|
||||
static navigationOptions(options) {
|
||||
return { header: null };
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
const ds = new ListView.DataSource({
|
||||
rowHasChanged: (r1, r2) => { return r1 !== r2; }
|
||||
});
|
||||
this.state = {
|
||||
dataSource: ds,
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
reg.logger().lastEntries(1000).then((entries) => {
|
||||
const newDataSource = this.state.dataSource.cloneWithRows(entries);
|
||||
this.setState({ dataSource: newDataSource });
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
let renderRow = (item) => {
|
||||
return (
|
||||
<View style={{flexDirection: 'row', paddingLeft: 1, paddingRight: 1, paddingTop:0, paddingBottom:0 }}>
|
||||
<Text style={{fontFamily: 'monospace', fontSize: 10}}>{time.unixMsToIsoSec(item.timestamp) + ': ' + item.message}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
// `enableEmptySections` is to fix this warning: https://github.com/FaridSafi/react-native-gifted-listview/issues/39
|
||||
return (
|
||||
<View style={{flex: 1}}>
|
||||
<ScreenHeader navState={this.props.navigation.state} />
|
||||
<ListView
|
||||
dataSource={this.state.dataSource}
|
||||
renderRow={renderRow}
|
||||
enableEmptySections={true}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const LogScreen = connect(
|
||||
(state) => {
|
||||
return {};
|
||||
}
|
||||
)(LogScreenComponent)
|
||||
|
||||
export { LogScreen };
|
@ -55,9 +55,17 @@ class Logger {
|
||||
return output;
|
||||
}
|
||||
|
||||
objectsToString(...object) {
|
||||
let output = [];
|
||||
for (let i = 0; i < object.length; i++) {
|
||||
output.push('"' + this.objectToString(object[i]) + '"');
|
||||
}
|
||||
return output.join(', ');
|
||||
}
|
||||
|
||||
static databaseCreateTableSql() {
|
||||
let output = `
|
||||
CREATE TABLE logs (
|
||||
CREATE TABLE IF NOT EXISTS logs (
|
||||
id INTEGER PRIMARY KEY,
|
||||
source TEXT,
|
||||
level INT NOT NULL,
|
||||
@ -68,14 +76,25 @@ class Logger {
|
||||
return output.split("\n").join(' ');
|
||||
}
|
||||
|
||||
log(level, object) {
|
||||
// Only for database at the moment
|
||||
async lastEntries(limit = 100) {
|
||||
for (let i = 0; i < this.targets_.length; i++) {
|
||||
const target = this.targets_[i];
|
||||
if (target.type == 'database') {
|
||||
return await target.database.selectAll('SELECT * FROM logs ORDER BY timestamp DESC LIMIT ' + limit);
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
log(level, ...object) {
|
||||
if (this.level() < level || !this.targets_.length) return;
|
||||
|
||||
let levelString = '';
|
||||
if (this.level() == Logger.LEVEL_INFO) levelString = '[info] ';
|
||||
if (this.level() == Logger.LEVEL_WARN) levelString = '[warn] ';
|
||||
if (this.level() == Logger.LEVEL_ERROR) levelString = '[error] ';
|
||||
let line = moment().format('YYYY-MM-DD HH:mm:ss') + ': ' + levelString;
|
||||
let line = moment().format('YYYY-MM-DD HH:mm:ss') + ': ';
|
||||
|
||||
if (level == Logger.LEVEL_WARN) levelString += '[warn] ';
|
||||
if (level == Logger.LEVEL_ERROR) levelString += '[error] ';
|
||||
|
||||
for (let i = 0; i < this.targets_.length; i++) {
|
||||
let target = this.targets_[i];
|
||||
@ -84,27 +103,23 @@ class Logger {
|
||||
if (level = Logger.LEVEL_ERROR) fn = 'error';
|
||||
if (level = Logger.LEVEL_WARN) fn = 'warn';
|
||||
if (level = Logger.LEVEL_INFO) fn = 'info';
|
||||
if (typeof object === 'object') {
|
||||
console[fn](line, object);
|
||||
} else {
|
||||
console[fn](line + object);
|
||||
}
|
||||
console[fn](line + this.objectsToString(...object));
|
||||
} else if (target.type == 'file') {
|
||||
let serializedObject = this.objectToString(object);
|
||||
let serializedObject = this.objectsToString(...object);
|
||||
Logger.fsDriver().appendFileSync(target.path, line + serializedObject + "\n");
|
||||
} else if (target.type == 'vorpal') {
|
||||
target.vorpal.log(object);
|
||||
target.vorpal.log(...object);
|
||||
} else if (target.type == 'database') {
|
||||
let msg = this.objectToString(object);
|
||||
let msg = this.objectsToString(...object);
|
||||
target.database.exec('INSERT INTO logs (`source`, `level`, `message`, `timestamp`) VALUES (?, ?, ?, ?)', [target.source, level, msg, time.unixMs()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error(object) { return this.log(Logger.LEVEL_ERROR, object); }
|
||||
warn(object) { return this.log(Logger.LEVEL_WARN, object); }
|
||||
info(object) { return this.log(Logger.LEVEL_INFO, object); }
|
||||
debug(object) { return this.log(Logger.LEVEL_DEBUG, object); }
|
||||
error(...object) { return this.log(Logger.LEVEL_ERROR, ...object); }
|
||||
warn(...object) { return this.log(Logger.LEVEL_WARN, ...object); }
|
||||
info(...object) { return this.log(Logger.LEVEL_INFO, ...object); }
|
||||
debug(...object) { return this.log(Logger.LEVEL_DEBUG, ...object); }
|
||||
|
||||
static levelStringToId(s) {
|
||||
if (s == 'none') return Logger.LEVEL_NONE;
|
||||
|
9
ReactNativeClient/lib/react-logger.js
vendored
Normal file
9
ReactNativeClient/lib/react-logger.js
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
import { Logger } from 'lib/logger.js';
|
||||
|
||||
class ReactLogger extends Logger {
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
export { ReactLogger }
|
@ -18,6 +18,10 @@ let time = {
|
||||
return moment.unix(ms / 1000).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z';
|
||||
},
|
||||
|
||||
unixMsToIsoSec(ms) {
|
||||
return moment.unix(ms / 1000).utc().format('YYYY-MM-DDTHH:mm:ss') + 'Z';
|
||||
},
|
||||
|
||||
msleep(ms) {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
|
@ -8,6 +8,7 @@ import { StackNavigator } from 'react-navigation';
|
||||
import { addNavigationHelpers } from 'react-navigation';
|
||||
import { shim } from 'lib/shim.js';
|
||||
import { Log } from 'lib/log.js'
|
||||
import { Logger } from 'lib/logger.js'
|
||||
import { Note } from 'lib/models/note.js'
|
||||
import { Folder } from 'lib/models/folder.js'
|
||||
import { Resource } from 'lib/models/resource.js'
|
||||
@ -16,6 +17,7 @@ import { NoteTag } from 'lib/models/note-tag.js'
|
||||
import { BaseItem } from 'lib/models/base-item.js'
|
||||
import { BaseModel } from 'lib/base-model.js'
|
||||
import { JoplinDatabase } from 'lib/joplin-database.js'
|
||||
import { Database } from 'lib/database.js'
|
||||
import { ItemList } from 'lib/components/item-list.js'
|
||||
import { NotesScreen } from 'lib/components/screens/notes.js'
|
||||
import { NotesScreenUtils } from 'lib/components/screens/notes-utils.js'
|
||||
@ -23,6 +25,7 @@ import { NoteScreen } from 'lib/components/screens/note.js'
|
||||
import { FolderScreen } from 'lib/components/screens/folder.js'
|
||||
import { FoldersScreen } from 'lib/components/screens/folders.js'
|
||||
import { LoginScreen } from 'lib/components/screens/login.js'
|
||||
import { LogScreen } from 'lib/components/screens/log.js'
|
||||
import { LoadingScreen } from 'lib/components/screens/loading.js'
|
||||
import { OneDriveLoginScreen } from 'lib/components/screens/onedrive-login.js'
|
||||
import { Setting } from 'lib/models/setting.js'
|
||||
@ -45,7 +48,7 @@ let defaultState = {
|
||||
};
|
||||
|
||||
const reducer = (state = defaultState, action) => {
|
||||
Log.info('Reducer action', action.type);
|
||||
reg.logger().info('Reducer action', action.type);
|
||||
|
||||
let newState = state;
|
||||
|
||||
@ -58,8 +61,8 @@ const reducer = (state = defaultState, action) => {
|
||||
const currentRoute = r.length ? r[r.length - 1] : null;
|
||||
const currentRouteName = currentRoute ? currentRoute.routeName : '';
|
||||
|
||||
Log.info('Current route name', currentRouteName);
|
||||
Log.info('New route name', action.routeName);
|
||||
reg.logger().info('Current route name', currentRouteName);
|
||||
reg.logger().info('New route name', action.routeName);
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
|
||||
@ -178,7 +181,7 @@ const reducer = (state = defaultState, action) => {
|
||||
|
||||
}
|
||||
|
||||
// Log.info('newState.selectedFolderId', newState.selectedFolderId);
|
||||
// reg.logger().info('newState.selectedFolderId', newState.selectedFolderId);
|
||||
|
||||
return newState;
|
||||
}
|
||||
@ -193,6 +196,7 @@ const AppNavigator = StackNavigator({
|
||||
Login: { screen: LoginScreen },
|
||||
Loading: { screen: LoadingScreen },
|
||||
OneDriveLogin: { screen: OneDriveLoginScreen },
|
||||
Log: { screen: LogScreen },
|
||||
});
|
||||
|
||||
class AppComponent extends React.Component {
|
||||
@ -233,6 +237,16 @@ class AppComponent extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
Setting.setConstant('appId', 'net.cozic.joplin-android');
|
||||
Setting.setConstant('appType', 'mobile');
|
||||
|
||||
const logDatabase = new Database(new DatabaseDriverReactNative());
|
||||
await logDatabase.open({ name: 'log.sqlite' });
|
||||
await logDatabase.exec(Logger.databaseCreateTableSql());
|
||||
reg.logger().addTarget('database', { database: logDatabase, source: 'm' });
|
||||
|
||||
reg.logger().info('Starting application' + Setting.value('appId'));
|
||||
|
||||
let db = new JoplinDatabase(new DatabaseDriverReactNative());
|
||||
reg.setDb(db);
|
||||
|
||||
@ -247,8 +261,8 @@ class AppComponent extends React.Component {
|
||||
BaseItem.loadClass('NoteTag', NoteTag);
|
||||
|
||||
try {
|
||||
await db.open({ name: '/storage/emulated/0/Download/joplin-48.sqlite' })
|
||||
Log.info('Database is ready.');
|
||||
await db.open({ name: 'joplin-50.sqlite' })
|
||||
reg.logger().info('Database is ready.');
|
||||
|
||||
//await db.exec('DELETE FROM notes');
|
||||
//await db.exec('DELETE FROM folders');
|
||||
@ -257,14 +271,12 @@ class AppComponent extends React.Component {
|
||||
//await db.exec('DELETE FROM resources');
|
||||
//await db.exec('DELETE FROM deleted_items');
|
||||
|
||||
Log.info('Loading settings...');
|
||||
reg.logger().info('Loading settings...');
|
||||
await Setting.load();
|
||||
|
||||
Setting.setConstant('appId', 'net.cozic.joplin-android');
|
||||
Setting.setConstant('appType', 'mobile');
|
||||
Setting.setConstant('resourceDir', RNFetchBlob.fs.dirs.DocumentDir);
|
||||
|
||||
Log.info('Loading folders...');
|
||||
reg.logger().info('Loading folders...');
|
||||
|
||||
let folders = await Folder.all();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user