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() {
|
render() {
|
||||||
let key = 0;
|
let key = 0;
|
||||||
let menuOptionComponents = [];
|
let menuOptionComponents = [];
|
||||||
@ -56,10 +63,10 @@ class ScreenHeaderComponent extends Component {
|
|||||||
menuOptionComponents.push(<View key={'menuOption_' + key++} style={styles.divider}/>);
|
menuOptionComponents.push(<View key={'menuOption_' + key++} style={styles.divider}/>);
|
||||||
}
|
}
|
||||||
|
|
||||||
// menuOptionComponents.push(
|
menuOptionComponents.push(
|
||||||
// <MenuOption value={1} key={'menuOption_' + key++}>
|
<MenuOption value={() => this.log_press()} key={'menuOption_' + key++}>
|
||||||
// <Text>{_('Configuration')}</Text>
|
<Text>{_('Log')}</Text>
|
||||||
// </MenuOption>);
|
</MenuOption>);
|
||||||
|
|
||||||
let title = 'title' in this.props && this.props.title !== null ? this.props.title : _(this.props.navState.routeName);
|
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 };
|
@ -52,12 +52,20 @@ class Logger {
|
|||||||
output = object;
|
output = object;
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
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() {
|
static databaseCreateTableSql() {
|
||||||
let output = `
|
let output = `
|
||||||
CREATE TABLE logs (
|
CREATE TABLE IF NOT EXISTS logs (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
source TEXT,
|
source TEXT,
|
||||||
level INT NOT NULL,
|
level INT NOT NULL,
|
||||||
@ -68,14 +76,25 @@ class Logger {
|
|||||||
return output.split("\n").join(' ');
|
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;
|
if (this.level() < level || !this.targets_.length) return;
|
||||||
|
|
||||||
let levelString = '';
|
let levelString = '';
|
||||||
if (this.level() == Logger.LEVEL_INFO) levelString = '[info] ';
|
let line = moment().format('YYYY-MM-DD HH:mm:ss') + ': ';
|
||||||
if (this.level() == Logger.LEVEL_WARN) levelString = '[warn] ';
|
|
||||||
if (this.level() == Logger.LEVEL_ERROR) levelString = '[error] ';
|
if (level == Logger.LEVEL_WARN) levelString += '[warn] ';
|
||||||
let line = moment().format('YYYY-MM-DD HH:mm:ss') + ': ' + levelString;
|
if (level == Logger.LEVEL_ERROR) levelString += '[error] ';
|
||||||
|
|
||||||
for (let i = 0; i < this.targets_.length; i++) {
|
for (let i = 0; i < this.targets_.length; i++) {
|
||||||
let target = this.targets_[i];
|
let target = this.targets_[i];
|
||||||
@ -84,27 +103,23 @@ class Logger {
|
|||||||
if (level = Logger.LEVEL_ERROR) fn = 'error';
|
if (level = Logger.LEVEL_ERROR) fn = 'error';
|
||||||
if (level = Logger.LEVEL_WARN) fn = 'warn';
|
if (level = Logger.LEVEL_WARN) fn = 'warn';
|
||||||
if (level = Logger.LEVEL_INFO) fn = 'info';
|
if (level = Logger.LEVEL_INFO) fn = 'info';
|
||||||
if (typeof object === 'object') {
|
console[fn](line + this.objectsToString(...object));
|
||||||
console[fn](line, object);
|
|
||||||
} else {
|
|
||||||
console[fn](line + object);
|
|
||||||
}
|
|
||||||
} else if (target.type == 'file') {
|
} else if (target.type == 'file') {
|
||||||
let serializedObject = this.objectToString(object);
|
let serializedObject = this.objectsToString(...object);
|
||||||
Logger.fsDriver().appendFileSync(target.path, line + serializedObject + "\n");
|
Logger.fsDriver().appendFileSync(target.path, line + serializedObject + "\n");
|
||||||
} else if (target.type == 'vorpal') {
|
} else if (target.type == 'vorpal') {
|
||||||
target.vorpal.log(object);
|
target.vorpal.log(...object);
|
||||||
} else if (target.type == 'database') {
|
} 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()]);
|
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); }
|
error(...object) { return this.log(Logger.LEVEL_ERROR, ...object); }
|
||||||
warn(object) { return this.log(Logger.LEVEL_WARN, object); }
|
warn(...object) { return this.log(Logger.LEVEL_WARN, ...object); }
|
||||||
info(object) { return this.log(Logger.LEVEL_INFO, object); }
|
info(...object) { return this.log(Logger.LEVEL_INFO, ...object); }
|
||||||
debug(object) { return this.log(Logger.LEVEL_DEBUG, object); }
|
debug(...object) { return this.log(Logger.LEVEL_DEBUG, ...object); }
|
||||||
|
|
||||||
static levelStringToId(s) {
|
static levelStringToId(s) {
|
||||||
if (s == 'none') return Logger.LEVEL_NONE;
|
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';
|
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) {
|
msleep(ms) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -8,6 +8,7 @@ import { StackNavigator } from 'react-navigation';
|
|||||||
import { addNavigationHelpers } from 'react-navigation';
|
import { addNavigationHelpers } from 'react-navigation';
|
||||||
import { shim } from 'lib/shim.js';
|
import { shim } from 'lib/shim.js';
|
||||||
import { Log } from 'lib/log.js'
|
import { Log } from 'lib/log.js'
|
||||||
|
import { Logger } from 'lib/logger.js'
|
||||||
import { Note } from 'lib/models/note.js'
|
import { Note } from 'lib/models/note.js'
|
||||||
import { Folder } from 'lib/models/folder.js'
|
import { Folder } from 'lib/models/folder.js'
|
||||||
import { Resource } from 'lib/models/resource.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 { BaseItem } from 'lib/models/base-item.js'
|
||||||
import { BaseModel } from 'lib/base-model.js'
|
import { BaseModel } from 'lib/base-model.js'
|
||||||
import { JoplinDatabase } from 'lib/joplin-database.js'
|
import { JoplinDatabase } from 'lib/joplin-database.js'
|
||||||
|
import { Database } from 'lib/database.js'
|
||||||
import { ItemList } from 'lib/components/item-list.js'
|
import { ItemList } from 'lib/components/item-list.js'
|
||||||
import { NotesScreen } from 'lib/components/screens/notes.js'
|
import { NotesScreen } from 'lib/components/screens/notes.js'
|
||||||
import { NotesScreenUtils } from 'lib/components/screens/notes-utils.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 { FolderScreen } from 'lib/components/screens/folder.js'
|
||||||
import { FoldersScreen } from 'lib/components/screens/folders.js'
|
import { FoldersScreen } from 'lib/components/screens/folders.js'
|
||||||
import { LoginScreen } from 'lib/components/screens/login.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 { LoadingScreen } from 'lib/components/screens/loading.js'
|
||||||
import { OneDriveLoginScreen } from 'lib/components/screens/onedrive-login.js'
|
import { OneDriveLoginScreen } from 'lib/components/screens/onedrive-login.js'
|
||||||
import { Setting } from 'lib/models/setting.js'
|
import { Setting } from 'lib/models/setting.js'
|
||||||
@ -45,7 +48,7 @@ let defaultState = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const reducer = (state = defaultState, action) => {
|
const reducer = (state = defaultState, action) => {
|
||||||
Log.info('Reducer action', action.type);
|
reg.logger().info('Reducer action', action.type);
|
||||||
|
|
||||||
let newState = state;
|
let newState = state;
|
||||||
|
|
||||||
@ -58,8 +61,8 @@ const reducer = (state = defaultState, action) => {
|
|||||||
const currentRoute = r.length ? r[r.length - 1] : null;
|
const currentRoute = r.length ? r[r.length - 1] : null;
|
||||||
const currentRouteName = currentRoute ? currentRoute.routeName : '';
|
const currentRouteName = currentRoute ? currentRoute.routeName : '';
|
||||||
|
|
||||||
Log.info('Current route name', currentRouteName);
|
reg.logger().info('Current route name', currentRouteName);
|
||||||
Log.info('New route name', action.routeName);
|
reg.logger().info('New route name', action.routeName);
|
||||||
|
|
||||||
newState = Object.assign({}, state);
|
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;
|
return newState;
|
||||||
}
|
}
|
||||||
@ -193,6 +196,7 @@ const AppNavigator = StackNavigator({
|
|||||||
Login: { screen: LoginScreen },
|
Login: { screen: LoginScreen },
|
||||||
Loading: { screen: LoadingScreen },
|
Loading: { screen: LoadingScreen },
|
||||||
OneDriveLogin: { screen: OneDriveLoginScreen },
|
OneDriveLogin: { screen: OneDriveLoginScreen },
|
||||||
|
Log: { screen: LogScreen },
|
||||||
});
|
});
|
||||||
|
|
||||||
class AppComponent extends React.Component {
|
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());
|
let db = new JoplinDatabase(new DatabaseDriverReactNative());
|
||||||
reg.setDb(db);
|
reg.setDb(db);
|
||||||
|
|
||||||
@ -247,8 +261,8 @@ class AppComponent extends React.Component {
|
|||||||
BaseItem.loadClass('NoteTag', NoteTag);
|
BaseItem.loadClass('NoteTag', NoteTag);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await db.open({ name: '/storage/emulated/0/Download/joplin-48.sqlite' })
|
await db.open({ name: 'joplin-50.sqlite' })
|
||||||
Log.info('Database is ready.');
|
reg.logger().info('Database is ready.');
|
||||||
|
|
||||||
//await db.exec('DELETE FROM notes');
|
//await db.exec('DELETE FROM notes');
|
||||||
//await db.exec('DELETE FROM folders');
|
//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 resources');
|
||||||
//await db.exec('DELETE FROM deleted_items');
|
//await db.exec('DELETE FROM deleted_items');
|
||||||
|
|
||||||
Log.info('Loading settings...');
|
reg.logger().info('Loading settings...');
|
||||||
await Setting.load();
|
await Setting.load();
|
||||||
|
|
||||||
Setting.setConstant('appId', 'net.cozic.joplin-android');
|
|
||||||
Setting.setConstant('appType', 'mobile');
|
|
||||||
Setting.setConstant('resourceDir', RNFetchBlob.fs.dirs.DocumentDir);
|
Setting.setConstant('resourceDir', RNFetchBlob.fs.dirs.DocumentDir);
|
||||||
|
|
||||||
Log.info('Loading folders...');
|
reg.logger().info('Loading folders...');
|
||||||
|
|
||||||
let folders = await Folder.all();
|
let folders = await Folder.all();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user