mirror of
https://github.com/ikun0014/lx-music-mobile.git
synced 2025-05-23 22:37:41 +08:00
改进软件错误处理,添加对软件崩溃的错误日志记录
This commit is contained in:
parent
3a6b889829
commit
b1822f4584
2
index.js
2
index.js
@ -6,6 +6,7 @@
|
||||
// import '@/utils/log'
|
||||
import './shim'
|
||||
import '@/utils/errorHandle'
|
||||
import { init as initLog } from '@/utils/log'
|
||||
import '@/config/globalData'
|
||||
import SplashScreen from 'react-native-splash-screen'
|
||||
import { init as initNavigation, navigations, showPactModal } from '@/navigation'
|
||||
@ -25,6 +26,7 @@ console.log('starting app...')
|
||||
let store
|
||||
let isInited = false
|
||||
let isFirstRun = true
|
||||
initLog()
|
||||
|
||||
const init = () => {
|
||||
if (isInited) return Promise.resolve()
|
||||
|
@ -1,5 +1,7 @@
|
||||
### 优化
|
||||
|
||||
- 改进软件错误处理,添加对软件崩溃的错误日志记录,可在设置-其他查看错误日志历史。注:清理缓存时日志也将会被清理
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复修复协议弹窗可以被绕过的问题
|
||||
- 修复从在线列表使用稍后播放功能播放歌曲时,歌曲封面不显示的问题
|
||||
- 修复正在播放“稍后播放”的歌曲时,对“稍后播放”前播放的列表进行添加、删除操作会导致切歌的问题
|
||||
- 修复显示版本更新弹窗会导致应用崩溃的问题
|
||||
|
@ -10,12 +10,14 @@ const styles = StyleSheet.create({
|
||||
// flexGrow: 0,
|
||||
flexShrink: 1,
|
||||
marginTop: 15,
|
||||
marginLeft: 15,
|
||||
marginRight: 15,
|
||||
marginLeft: 5,
|
||||
marginRight: 5,
|
||||
marginBottom: 25,
|
||||
},
|
||||
content: {
|
||||
flexGrow: 0,
|
||||
paddingLeft: 10,
|
||||
paddingRight: 10,
|
||||
},
|
||||
title: {
|
||||
fontSize: 14,
|
||||
@ -24,9 +26,15 @@ const styles = StyleSheet.create({
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
paddingBottom: 15,
|
||||
paddingLeft: 15,
|
||||
// paddingRight: 15,
|
||||
},
|
||||
btnsDirection: {
|
||||
paddingLeft: 15,
|
||||
},
|
||||
btnsReversedDirection: {
|
||||
paddingLeft: 15,
|
||||
flexDirection: 'row-reverse',
|
||||
},
|
||||
btn: {
|
||||
flex: 1,
|
||||
paddingTop: 10,
|
||||
@ -35,8 +43,13 @@ const styles = StyleSheet.create({
|
||||
paddingRight: 10,
|
||||
alignItems: 'center',
|
||||
borderRadius: 4,
|
||||
},
|
||||
btnDirection: {
|
||||
marginRight: 15,
|
||||
},
|
||||
btnReversedDirection: {
|
||||
marginLeft: 15,
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@ -51,8 +64,9 @@ export default ({
|
||||
text = '',
|
||||
cancelText = '',
|
||||
confirmText = '',
|
||||
showCancel = true,
|
||||
showConfirm = true,
|
||||
children,
|
||||
reverseBtn = false,
|
||||
}) => {
|
||||
const theme = useGetter('common', 'theme')
|
||||
const { t } = useTranslation()
|
||||
@ -64,15 +78,15 @@ export default ({
|
||||
{children || <Text style={{ ...styles.title, color: theme.normal }}>{text}</Text>}
|
||||
</ScrollView>
|
||||
</View>
|
||||
<View style={styles.btns}>
|
||||
{showCancel
|
||||
? <Button style={{ ...styles.btn, backgroundColor: theme.secondary45 }} onPress={onCancel}>
|
||||
<Text style={{ color: theme.secondary_5 }}>{cancelText || t('cancel')}</Text>
|
||||
<View style={{ ...styles.btns, ...(reverseBtn ? styles.btnsReversedDirection : styles.btnsDirection) }}>
|
||||
<Button style={{ ...styles.btn, ...(reverseBtn ? styles.btnReversedDirection : styles.btnDirection), backgroundColor: theme.secondary45 }} onPress={onCancel}>
|
||||
<Text style={{ color: theme.secondary_5 }}>{cancelText || t('cancel')}</Text>
|
||||
</Button>
|
||||
{showConfirm
|
||||
? <Button style={{ ...styles.btn, ...(reverseBtn ? styles.btnReversedDirection : styles.btnDirection), backgroundColor: theme.secondary45 }} onPress={onConfirm}>
|
||||
<Text style={{ fontSize: 14, color: theme.secondary_5 }}>{confirmText || t('confirm')}</Text>
|
||||
</Button>
|
||||
: null}
|
||||
<Button style={{ ...styles.btn, backgroundColor: theme.secondary45 }} onPress={onConfirm}>
|
||||
<Text style={{ fontSize: 14, color: theme.secondary_5 }}>{confirmText || t('confirm')}</Text>
|
||||
</Button>
|
||||
</View>
|
||||
</Dialog>
|
||||
)
|
||||
|
@ -14,7 +14,7 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
modalView: {
|
||||
maxWidth: '90%',
|
||||
minWidth: '50%',
|
||||
minWidth: '60%',
|
||||
maxHeight: '78%',
|
||||
backgroundColor: 'white',
|
||||
borderRadius: 4,
|
||||
|
@ -168,11 +168,17 @@
|
||||
"setting_backup_part_import_list_desc": "Select the list of backup files",
|
||||
"setting_backup_part_export_list_desc": "Select the save location of the playlist backup file",
|
||||
|
||||
"setting_other": "Extras",
|
||||
"setting_other_cache": "Cache management (including the cache of songs, lyrics, etc., it is not recommended to clean up if there is no problem related to song playback)",
|
||||
"setting_other_cache_size": "Currently used cache size: ",
|
||||
"setting_other": "Other",
|
||||
"setting_other_cache": "Cache management (including the cache of songs, lyrics, error logs, etc., it is not recommended to clean up if there is no problem related to song playback)",
|
||||
"setting_other_cache_size": "Currently used cache size:",
|
||||
"setting_other_cache_clear_btn": "Clear Cache",
|
||||
"setting_other_cache_clear_success_tip": "Cache clearing completed",
|
||||
"setting_other_log": "Error log (error log when the software crashes 💥)",
|
||||
"setting_other_log_tip_clean_success": "Log cleaning completed",
|
||||
"setting_other_log_tip_null": "The log is empty~",
|
||||
"setting_other_log_btn_show": "View log",
|
||||
"setting_other_log_btn_hide": "Close",
|
||||
"setting_other_log_btn_clean": "Clear",
|
||||
|
||||
"setting_version": "Software Update",
|
||||
"setting_version_show_ver_modal": "Open the update window 🚀",
|
||||
|
@ -169,10 +169,16 @@
|
||||
"setting_backup_part_export_list_desc": "选择歌单备份文件保存位置",
|
||||
|
||||
"setting_other": "其他",
|
||||
"setting_other_cache": "缓存管理(包括歌曲、歌词等缓存,没有歌曲播放相关的问题不建议清理)",
|
||||
"setting_other_cache": "缓存管理(包括歌曲、歌词、错误日志等缓存,没有歌曲播放相关的问题不建议清理)",
|
||||
"setting_other_cache_size": "当前已用缓存大小:",
|
||||
"setting_other_cache_clear_btn": "清理缓存",
|
||||
"setting_other_cache_clear_success_tip": "缓存清理完成",
|
||||
"setting_other_log": "错误日志(软件崩溃💥时的错误日志)",
|
||||
"setting_other_log_tip_clean_success": "日志清理完成",
|
||||
"setting_other_log_tip_null": "日志是空的哦~",
|
||||
"setting_other_log_btn_show": "查看日志",
|
||||
"setting_other_log_btn_hide": "关闭",
|
||||
"setting_other_log_btn_clean": "清空",
|
||||
|
||||
"setting_version": "软件更新",
|
||||
"setting_version_show_ver_modal": "打开更新窗口 🚀",
|
||||
|
@ -34,6 +34,7 @@ const VersionModal = ({ componentId }) => {
|
||||
|
||||
const textStyle = StyleSheet.compose(styles.text, {
|
||||
color: theme.normal,
|
||||
marginBottom: 10,
|
||||
})
|
||||
const textLinkStyle = StyleSheet.compose(styles.text, {
|
||||
textDecorationLine: 'underline',
|
||||
@ -74,46 +75,22 @@ const VersionModal = ({ componentId }) => {
|
||||
<View style={styles.main}>
|
||||
<Text style={{ ...styles.title, color: theme.normal }}>许可协议</Text>
|
||||
<ScrollView style={styles.content} keyboardShouldPersistTaps={'always'}>
|
||||
<View style={styles.part}>
|
||||
<Text style={textStyle} >本项目(软件)基于 <Text onPress={openLicensePage} style={textLinkStyle}>Apache License 2.0</Text> 许可证发行,在使用本软件前,你(使用者)需签署本协议才可继续使用,以下协议是对于 Apache License 2.0 的补充,如有冲突,以以下协议为准。</Text>
|
||||
</View>
|
||||
<View style={{ ...styles.part, flexDirection: 'row', flexWrap: 'wrap' }}>
|
||||
<Text style={textStyle} >词语约定:本协议中的“本软件”指洛雪音乐桌面版项目;“使用者”指签署本协议的使用者;“官方音乐平台”指对本软件内置的包括酷我、酷狗、咪咕等音乐源的官方平台统称;“版权数据”指包括但不限于图像、音频、名字等在内的他人拥有所属版权的数据。</Text>
|
||||
</View>
|
||||
<View style={{ ...styles.part, flexDirection: 'row', flexWrap: 'wrap' }}>
|
||||
<Text style={textStyle} ><Text style={styles.bold}>1.</Text> 本软件的数据来源原理是从各官方音乐平台的公开服务器中拉取数据,经过对数据简单地筛选与合并后进行展示,因此本软件不对数据的准确性负责。</Text>
|
||||
</View>
|
||||
<View style={{ ...styles.part, flexDirection: 'row', flexWrap: 'wrap' }}>
|
||||
<Text style={textStyle} ><Text style={styles.bold}>2.</Text> 使用本软件的过程中可能会产生版权数据,对于这些版权数据,本软件不拥有它们的所有权,为了避免造成侵权,使用者务必在 <Text style={styles.bold}>24小时内</Text> 清除使用本软件的过程中所产生的版权数据。</Text>
|
||||
</View>
|
||||
<View style={{ ...styles.part, flexDirection: 'row', flexWrap: 'wrap' }}>
|
||||
<Text style={textStyle} ><Text style={styles.bold}>3.</Text> 本软件内的官方音乐平台别名为本软件内对官方音乐平台的一个称呼,不包含恶意,如果官方音乐平台觉得不妥,可联系本软件更改或移除。</Text>
|
||||
</View>
|
||||
<View style={{ ...styles.part, flexDirection: 'row', flexWrap: 'wrap' }}>
|
||||
<Text style={textStyle} ><Text style={styles.bold}>4.</Text> 本软件内使用的部分包括但不限于字体、图片等资源来源于互联网,如果出现侵权可联系本软件移除。</Text>
|
||||
</View>
|
||||
<View style={{ ...styles.part, flexDirection: 'row', flexWrap: 'wrap' }}>
|
||||
<Text style={textStyle} ><Text style={styles.bold}>5.</Text> 由于使用本软件产生的包括由于本协议或由于使用或无法使用本软件而引起的任何性质的任何直接、间接、特殊、偶然或结果性损害(包括但不限于因商誉损失、停工、计算机故障或故障引起的损害赔偿,或任何及所有其他商业损害或损失)由使用者负责。</Text>
|
||||
</View>
|
||||
<View style={{ ...styles.part, flexDirection: 'row', flexWrap: 'wrap' }}>
|
||||
<Text style={textStyle} ><Text style={styles.bold}>6.</Text> 本项目完全免费,且开源发布于 <Text onPress={openHomePage} style={textLinkStyle}>GitHub</Text> 面向全世界人用作对技术的学习交流,本软件不对项目内的技术可能存在违反当地法律法规的行为作保证,<Text style={styles.bold}>禁止在违反当地法律法规的情况下使用本软件</Text>,对于使用者在明知或不知当地法律法规不允许的情况下使用本软件所造成的任何违法违规行为由使用者承担,本软件不承担由此造成的任何直接、间接、特殊、偶然或结果性责任。</Text>
|
||||
</View>
|
||||
<View style={{ ...styles.part, flexDirection: 'row', flexWrap: 'wrap' }}>
|
||||
<Text style={textStyle} ><Text style={styles.bold}>*</Text> 若协议更新,恕不另行通知,可到开源地址查看。</Text>
|
||||
</View>
|
||||
<View style={{ ...styles.part, flexDirection: 'row', flexWrap: 'wrap' }}>
|
||||
<Text style={textStyle} ><Text style={styles.bold}>*</Text> 本软件的初衷是帮助官方音乐平台简化数据后代为展示,帮助使用者根据歌曲名、艺术家等关键字快速地定位所需内容所在的音乐平台。</Text>
|
||||
</View>
|
||||
<View style={{ ...styles.part, flexDirection: 'row', flexWrap: 'wrap' }}>
|
||||
<Text style={textStyle} ><Text style={styles.bold}>*</Text> 音乐平台不易,建议到对应音乐平台支持正版资源。</Text>
|
||||
</View>
|
||||
<Text selectable style={textStyle} >本项目(软件)基于 <Text onPress={openLicensePage} style={textLinkStyle}>Apache License 2.0</Text> 许可证发行,在使用本软件前,你(使用者)需签署本协议才可继续使用,以下协议是对于 Apache License 2.0 的补充,如有冲突,以以下协议为准。</Text>
|
||||
<Text selectable style={textStyle} >词语约定:本协议中的“本软件”指洛雪音乐桌面版项目;“使用者”指签署本协议的使用者;“官方音乐平台”指对本软件内置的包括酷我、酷狗、咪咕等音乐源的官方平台统称;“版权数据”指包括但不限于图像、音频、名字等在内的他人拥有所属版权的数据。</Text>
|
||||
<Text selectable style={textStyle} ><Text style={styles.bold}>1.</Text> 本软件的数据来源原理是从各官方音乐平台的公开服务器中拉取数据,经过对数据简单地筛选与合并后进行展示,因此本软件不对数据的准确性负责。</Text>
|
||||
<Text selectable style={textStyle} ><Text style={styles.bold}>2.</Text> 使用本软件的过程中可能会产生版权数据,对于这些版权数据,本软件不拥有它们的所有权,为了避免造成侵权,使用者务必在 <Text style={styles.bold}>24小时内</Text> 清除使用本软件的过程中所产生的版权数据。</Text>
|
||||
<Text selectable style={textStyle} ><Text style={styles.bold}>3.</Text> 本软件内的官方音乐平台别名为本软件内对官方音乐平台的一个称呼,不包含恶意,如果官方音乐平台觉得不妥,可联系本软件更改或移除。</Text>
|
||||
<Text selectable style={textStyle} ><Text style={styles.bold}>4.</Text> 本软件内使用的部分包括但不限于字体、图片等资源来源于互联网,如果出现侵权可联系本软件移除。</Text>
|
||||
<Text selectable style={textStyle} ><Text style={styles.bold}>5.</Text> 由于使用本软件产生的包括由于本协议或由于使用或无法使用本软件而引起的任何性质的任何直接、间接、特殊、偶然或结果性损害(包括但不限于因商誉损失、停工、计算机故障或故障引起的损害赔偿,或任何及所有其他商业损害或损失)由使用者负责。</Text>
|
||||
<Text selectable style={textStyle} ><Text style={styles.bold}>6.</Text> 本项目完全免费,且开源发布于 <Text onPress={openHomePage} style={textLinkStyle}>GitHub</Text> 面向全世界人用作对技术的学习交流,本软件不对项目内的技术可能存在违反当地法律法规的行为作保证,<Text style={styles.bold}>禁止在违反当地法律法规的情况下使用本软件</Text>,对于使用者在明知或不知当地法律法规不允许的情况下使用本软件所造成的任何违法违规行为由使用者承担,本软件不承担由此造成的任何直接、间接、特殊、偶然或结果性责任。</Text>
|
||||
<Text selectable style={textStyle} ><Text style={styles.bold}>*</Text> 若协议更新,恕不另行通知,可到开源地址查看。</Text>
|
||||
<Text selectable style={textStyle} ><Text style={styles.bold}>*</Text> 本软件的初衷是帮助官方音乐平台简化数据后代为展示,帮助使用者根据歌曲名、艺术家等关键字快速地定位所需内容所在的音乐平台。</Text>
|
||||
<Text selectable style={textStyle} ><Text style={styles.bold}>*</Text> 音乐平台不易,建议到对应音乐平台支持正版资源。</Text>
|
||||
{
|
||||
isAgreePact
|
||||
? null
|
||||
: (
|
||||
<View style={{ ...styles.part, flexDirection: 'row', flexWrap: 'wrap' }}>
|
||||
<Text style={{ ...styles.text, ...styles.bold, color: theme.normal }} >若你(使用者)接受以上协议,请点击下面的“接受”按钮签署本协议,若不接受,请点击“不接受”后退出软件并清除本软件的所有数据。</Text>
|
||||
</View>
|
||||
<Text selectable style={{ ...styles.text, ...styles.bold, color: theme.normal }} >若你(使用者)接受以上协议,请点击下面的“接受”按钮签署本协议,若不接受,请点击“不接受”后退出软件并清除本软件的所有数据。</Text>
|
||||
)
|
||||
}
|
||||
</ScrollView>
|
||||
|
95
src/screens/Home/Setting/Other/Log.js
Normal file
95
src/screens/Home/Setting/Other/Log.js
Normal file
@ -0,0 +1,95 @@
|
||||
import React, { memo, useRef, useState, useEffect } from 'react'
|
||||
import { StyleSheet, View, Text, InteractionManager } from 'react-native'
|
||||
import { LOG_TYPE, getLogs, clearLogs } from '@/utils/log'
|
||||
import { useGetter } from '@/store'
|
||||
// import { gzip, ungzip } from 'pako'
|
||||
|
||||
import SubTitle from '../components/SubTitle'
|
||||
import Button from '../components/Button'
|
||||
import { useTranslation } from '@/plugins/i18n'
|
||||
import { toast } from '@/utils/tools'
|
||||
import ConfirmAlert from '@/components/common/ConfirmAlert'
|
||||
|
||||
export default memo(() => {
|
||||
const { t } = useTranslation()
|
||||
const [visibleNewFolder, setVisibleNewFolder] = useState(false)
|
||||
const [logText, setLogText] = useState('')
|
||||
const theme = useGetter('common', 'theme')
|
||||
const isUnmountedRef = useRef(true)
|
||||
|
||||
const getErrorLog = () => {
|
||||
getLogs(LOG_TYPE.error).then(log => {
|
||||
if (isUnmountedRef.current) return
|
||||
const logArr = log.split('\n')
|
||||
logArr.reverse()
|
||||
setLogText(logArr.join('\n\n').replace(/\n+$/, ''))
|
||||
})
|
||||
}
|
||||
|
||||
const openLogModal = () => {
|
||||
getErrorLog()
|
||||
setVisibleNewFolder(true)
|
||||
}
|
||||
|
||||
const handleHide = () => {
|
||||
setVisibleNewFolder(false)
|
||||
}
|
||||
|
||||
const handleCleanLog = () => {
|
||||
clearLogs(LOG_TYPE.error).then(() => {
|
||||
toast(t('setting_other_log_tip_clean_success'))
|
||||
getErrorLog()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
isUnmountedRef.current = false
|
||||
return () => {
|
||||
isUnmountedRef.current = true
|
||||
}
|
||||
// handleGetAppCacheSize()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<SubTitle title={t('setting_other_log')}>
|
||||
<View style={styles.btn}>
|
||||
<Button onPress={openLogModal}>{t('setting_other_log_btn_show')}</Button>
|
||||
</View>
|
||||
</SubTitle>
|
||||
<ConfirmAlert
|
||||
cancelText={t('setting_other_log_btn_hide')}
|
||||
confirmText={t('setting_other_log_btn_clean')}
|
||||
visible={visibleNewFolder}
|
||||
onCancel={handleHide}
|
||||
onConfirm={handleCleanLog}
|
||||
showConfirm={!!logText}
|
||||
reverseBtn={true}
|
||||
>
|
||||
<View style={styles.newFolderContent} onStartShouldSetResponder={() => true}>
|
||||
{
|
||||
logText
|
||||
? <Text selectable style={{ ...styles.logText, color: theme.normal10 }}>{ logText }</Text>
|
||||
: <Text style={{ ...styles.tipText, color: theme.normal10 }}>{t('setting_other_log_tip_null')}</Text>
|
||||
}
|
||||
</View>
|
||||
</ConfirmAlert>
|
||||
</>
|
||||
)
|
||||
})
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
cacheSize: {
|
||||
marginBottom: 5,
|
||||
},
|
||||
btn: {
|
||||
flexDirection: 'row',
|
||||
},
|
||||
tipText: {
|
||||
fontSize: 14,
|
||||
},
|
||||
logText: {
|
||||
fontSize: 12,
|
||||
},
|
||||
})
|
@ -2,6 +2,7 @@ import React, { memo } from 'react'
|
||||
|
||||
import Section from '../components/Section'
|
||||
import Cache from './Cache'
|
||||
import Log from './Log'
|
||||
// import MaxCache from './MaxCache'
|
||||
import { useTranslation } from '@/plugins/i18n'
|
||||
|
||||
@ -11,6 +12,7 @@ export default memo(() => {
|
||||
return (
|
||||
<Section title={t('setting_other')}>
|
||||
<Cache />
|
||||
<Log />
|
||||
{/* <MaxCache /> */}
|
||||
</Section>
|
||||
)
|
||||
|
@ -1,7 +1,11 @@
|
||||
import { Alert } from 'react-native'
|
||||
import { exitApp } from '@/utils/tools'
|
||||
import { setJSExceptionHandler, setNativeExceptionHandler } from 'react-native-exception-handler'
|
||||
import { log } from '@/utils/log'
|
||||
|
||||
const errorHandler = (e, isFatal) => {
|
||||
if (isFatal) {
|
||||
log.error(e.message)
|
||||
Alert.alert(
|
||||
'💥Unexpected error occurred💥',
|
||||
`
|
||||
@ -12,15 +16,20 @@ ${isFatal ? 'Fatal:' : ''} ${e.name} ${e.message}
|
||||
`,
|
||||
[{
|
||||
text: '关闭 (Close)',
|
||||
onPress: () => {
|
||||
exitApp()
|
||||
},
|
||||
}],
|
||||
)
|
||||
} else {
|
||||
log.error(e.message)
|
||||
console.log(e) // So that we can see it in the ADB logs in case of Android if needed
|
||||
}
|
||||
}
|
||||
|
||||
setJSExceptionHandler(errorHandler)
|
||||
setJSExceptionHandler(errorHandler, true)
|
||||
|
||||
setNativeExceptionHandler((errorString) => {
|
||||
log.error(errorString)
|
||||
console.error('+++++', errorString, '+++++')
|
||||
})
|
||||
|
124
src/utils/log.js
124
src/utils/log.js
@ -1,6 +1,125 @@
|
||||
import { requestStoragePermission } from '@/utils/common'
|
||||
import { externalDirectoryPath, existsFile, writeFile, appendFile } from '@/utils/fs'
|
||||
// import { requestStoragePermission } from '@/utils/common'
|
||||
import { temporaryDirectoryPath, existsFile, writeFile, appendFile, mkdir, readFile, unlink } from '@/utils/fs'
|
||||
|
||||
export const LOG_TYPE = {
|
||||
info: 'INFO',
|
||||
warn: 'WARN',
|
||||
error: 'ERROR',
|
||||
}
|
||||
const logDir = temporaryDirectoryPath + '/lx_logs'
|
||||
const logPath = {
|
||||
info: logDir + '/info.log',
|
||||
warn: logDir + '/warn.log',
|
||||
error: logDir + '/error.log',
|
||||
}
|
||||
const logTools = {
|
||||
tempLog: {
|
||||
info: [],
|
||||
warn: [],
|
||||
error: [],
|
||||
},
|
||||
writeLog(type, msg) {
|
||||
switch (type) {
|
||||
case LOG_TYPE.info:
|
||||
appendFile(logPath.info, '\n' + msg)
|
||||
break
|
||||
case LOG_TYPE.warn:
|
||||
appendFile(logPath.warn, '\n' + msg)
|
||||
break
|
||||
case LOG_TYPE.error:
|
||||
appendFile(logPath.error, '\n' + msg)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
},
|
||||
async initLogFile(type, filePath) {
|
||||
try {
|
||||
let isExists = await existsFile(filePath)
|
||||
if (!isExists) await writeFile(filePath, '')
|
||||
if (this.tempLog[type].length) this.writeLog(LOG_TYPE[type], this.tempLog[type].map(m => `${m.time} ${m.type} ${m.text}`).join('\n'))
|
||||
this.tempLog[type] = null
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export const init = () => {
|
||||
return mkdir(logDir).then(() => {
|
||||
const tasks = []
|
||||
for (const [type, path] of Object.entries(logPath)) {
|
||||
tasks.push(logTools.initLogFile(type, path))
|
||||
}
|
||||
console.log('init log tools')
|
||||
return Promise.all(tasks)
|
||||
})
|
||||
}
|
||||
|
||||
export const getLogs = (type = LOG_TYPE.error) => {
|
||||
let path
|
||||
switch (type) {
|
||||
case LOG_TYPE.info:
|
||||
path = logPath.info
|
||||
break
|
||||
case LOG_TYPE.warn:
|
||||
path = logPath.warn
|
||||
break
|
||||
case LOG_TYPE.error:
|
||||
path = logPath.error
|
||||
break
|
||||
default:
|
||||
return Promise.reject(new Error('Unknow log type'))
|
||||
}
|
||||
return readFile(path)
|
||||
}
|
||||
|
||||
export const clearLogs = (type = LOG_TYPE.error) => {
|
||||
let path
|
||||
switch (type) {
|
||||
case LOG_TYPE.info:
|
||||
path = logPath.info
|
||||
break
|
||||
case LOG_TYPE.warn:
|
||||
path = logPath.warn
|
||||
break
|
||||
case LOG_TYPE.error:
|
||||
path = logPath.error
|
||||
break
|
||||
default:
|
||||
return Promise.reject(new Error('Unknow log type'))
|
||||
}
|
||||
return unlink(path).then(() => writeFile(path, ''))
|
||||
}
|
||||
|
||||
export const log = {
|
||||
info(...msgs) {
|
||||
console.info(...msgs)
|
||||
let msg = msgs.map(m => typeof m == 'object' ? JSON.stringify(m) : m).join(' ')
|
||||
if (msg.startsWith('%c')) return
|
||||
let time = new Date().toLocaleString()
|
||||
if (logTools.tempLog.info) {
|
||||
logTools.tempLog.info.push({ type: 'LOG', time, text: msg })
|
||||
} else logTools.writeLog(LOG_TYPE.info, `${time} LOG ${msg}`)
|
||||
},
|
||||
warn(...msgs) {
|
||||
console.warn(...msgs)
|
||||
let msg = msgs.map(m => typeof m == 'object' ? JSON.stringify(m) : m).join(' ')
|
||||
let time = new Date().toLocaleString()
|
||||
if (logTools.tempLog.warn) {
|
||||
logTools.tempLog.warn.push({ type: 'WARN', time, text: msg })
|
||||
} else logTools.writeLog(LOG_TYPE.warn, `${time} WARN ${msg}`)
|
||||
},
|
||||
error(...msgs) {
|
||||
console.error(...msgs)
|
||||
let msg = msgs.map(m => typeof m == 'object' ? JSON.stringify(m) : m).join(' ')
|
||||
let time = new Date().toLocaleString()
|
||||
if (logTools.tempLog.error) {
|
||||
logTools.tempLog.error.push({ type: 'ERROR', time, text: msg })
|
||||
} else logTools.writeLog(LOG_TYPE.error, `${time} ERROR ${msg}`)
|
||||
},
|
||||
}
|
||||
/*
|
||||
if (process.env.NODE_ENV !== 'development') {
|
||||
const logPath = externalDirectoryPath + '/debug.log'
|
||||
|
||||
@ -56,3 +175,4 @@ if (process.env.NODE_ENV !== 'development') {
|
||||
init()
|
||||
}
|
||||
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user