import path from 'path'
import fs from 'fs'
import ot from 'dayjs'
import get from 'lodash-es/get.js'
import each from 'lodash-es/each.js'
import map from 'lodash-es/map.js'
import join from 'lodash-es/join.js'
import trim from 'lodash-es/trim.js'
import isestr from './isestr.mjs'
import isbol from './isbol.mjs'
import isobj from './isobj.mjs'
import isarr from './isarr.mjs'
import cstr from './cstr.mjs'
import now2str from './now2str.mjs'
import sep from './sep.mjs'
import strleft from './strleft.mjs'
import strright from './strright.mjs'
import strdelleft from './strdelleft.mjs'
import strdelright from './strdelright.mjs'
import fsIsFolder from './fsIsFolder.mjs'
import fsCreateFolder from './fsCreateFolder.mjs'
/**
* 後端顯示與紀錄log訊息
*
* Unit Test: {@link https://github.com/yuda-lyu/wsemi/blob/master/test/fsSrlog.test.mjs Github}
* @memberOf wsemi
* @param {Object} [opt={}] 輸入設定物件,預設{}
* @param {String} [opt.fdSys=path.resolve()] 輸入工作路徑字串,若useLocRela=true時取代用,預設path.resolve()
* @param {String} [opt.fdLog='./syslog'] 輸入儲存log檔案之資料夾位置字串,預設'./syslog'
* @param {String} [opt.dlm='ꓹ'] 輸入分隔log參數字串,預設'ꓹ'
* @param {Boolean} [opt.useTime=true] 輸入是否給予紀錄時間布林值,預設true
* @param {Boolean} [opt.useLoc=true] 輸入是否紀錄觸發程式碼位置布林值,預設true
* @param {Boolean} [opt.useLocRela=true] 輸入當useLoc=true時,是否紀錄觸發程式碼位置改用相對工作路徑之位置布林值,預設true
* @returns {Function} 回傳log函數,比照console.log使用
* @example
* need test in nodejs.
*
* let opt = {
* useTime: false,
* }
* let srlog = fsSrlog(opt)
* srlog('abc', 123, 4.56, { xyz: ['a', 'bc', true, { xy: 'z' }] })
*
*/
function fsSrlog(opt = {}) {
//fdSys
let fdSys = get(opt, 'fdSys', '')
if (!isestr(fdSys)) {
fdSys = path.resolve()
fdSys = fdSys.replaceAll('\\', '/')
}
//fdLog
let fdLog = get(opt, 'fdLog', '')
if (!isestr(fdLog)) {
fdLog = `./syslog`
}
if (!fsIsFolder(fdLog)) {
fsCreateFolder(fdLog)
}
//dlm
let dlm = get(opt, 'dlm', '')
if (!isestr(dlm)) {
dlm = 'ꓹ' //用特殊符號取代逗號, 供切分資料之需求
}
//useTime
let useTime = get(opt, 'useTime', null)
if (!isbol(useTime)) {
useTime = true
}
//useLoc
let useLoc = get(opt, 'useLoc', null)
if (!isbol(useLoc)) {
useLoc = true
}
//useLocRela
let useLocRela = get(opt, 'useLocRela', null)
if (!isbol(useLocRela)) {
useLocRela = true
}
//gneFp
let gneFp = () => {
let cdday = ot().format('YYYY-MM-DD')
let fp = `${fdLog}/${cdday}.log`
return fp
}
async function core(time, loc, ...args) {
//fp
let fp = gneFp()
//cargs
let cargs = map(args, (v) => {
let t = ''
if (isobj(v) || isarr(v)) {
t = JSON.stringify(v)
}
else if (isbol(v)) {
t = v ? 'true' : 'false'
}
else {
t = cstr(v)
}
return t
})
//appendFileSync
let c = ''
if (useTime) {
c = `[${time}]\n`
fs.appendFileSync(fp, c, 'utf8')
}
if (useLoc) {
c = `[${loc}]\n`
fs.appendFileSync(fp, c, 'utf8')
}
if (true) {
c = `${join(cargs, `${dlm} `)}\n\n`
fs.appendFileSync(fp, c, 'utf8')
}
}
function srlog(...args) {
// console.log(...args)
//time
let time = ''
if (useTime) {
time = now2str()
}
//locInfor, locInforRela
let locInfor = ''
let locInforRela = ''
let stackLines = []
if (useLoc) {
//e
let e = new Error()
//stackLines
stackLines = sep(e.stack, '\n')
// console.log('stackLines', stackLines)
//locInfor
each(stackLines, (s) => {
//trim
s = trim(s)
//check
if (s.indexOf(`file:`) < 0) { //沒有file資訊則跳出
return true //跳出換下一個
}
if (s.indexOf('fsSrlog.mjs') >= 0) { //為srlog則跳出
return true //跳出換下一個
}
//ss, 依照空白切分
let ss = sep(s, ' ')
//尋找file:
each(ss, (v) => {
if (v.indexOf('file:') >= 0) {
locInfor = v
return false //跳出
}
})
//check
if (isestr(locInfor)) {
return false //跳出
}
})
//清理locInfor, locInforRela
if (isestr(locInfor)) {
//locInfor
if (strleft(locInfor, 1) === '(') {
locInfor = strdelleft(locInfor, 1)
}
if (strright(locInfor, 1) === ')') {
locInfor = strdelright(locInfor, 1)
}
try {
locInfor = decodeURIComponent(locInfor)
}
catch (err) {
console.log(err)
}
//locInforRela
locInforRela = locInfor.replace(fdSys, '')
locInforRela = strdelleft(locInforRela, 8)
}
else {
console.log('stackLines', stackLines)
throw new Error(`can not parse stackLines`)
}
// console.log('locInfor', locInfor)
// console.log('locInforRela', locInforRela)
}
//ags
let ags = []
if (useTime) {
ags = [
...ags,
`[${time}]`
]
}
let loc = ''
if (useLoc) {
loc = locInfor
if (useLocRela) {
loc = locInforRela
}
ags = [
...ags,
`[${loc}]`
]
}
if (true) {
ags = [
...ags,
...args
]
}
//show log
console.log(...ags)
//save log
core(time, loc, ...args)
}
return srlog
}
export default fsSrlog