mirror of
https://github.com/LifeArchiveProject/WeChatDataAnalysis.git
synced 2026-06-18 15:54:08 +08:00
improvement(log): 补充聊天消息与会话加载阶段日志
- 为会话加载、刷新和联系人初始化补充阶段性 trace - 为消息加载、归一化、状态提交和媒体刷新补充耗时日志 - 便于定位聊天页卡顿和加载异常
This commit is contained in:
@@ -5,6 +5,7 @@ import {
|
|||||||
getVoiceDurationInSeconds,
|
getVoiceDurationInSeconds,
|
||||||
getVoiceWidth
|
getVoiceWidth
|
||||||
} from '~/lib/chat/formatters'
|
} from '~/lib/chat/formatters'
|
||||||
|
import { createPerfTrace } from '~/lib/chat/perf-logger'
|
||||||
import { createMessageNormalizer, dedupeMessagesById } from '~/lib/chat/message-normalizer'
|
import { createMessageNormalizer, dedupeMessagesById } from '~/lib/chat/message-normalizer'
|
||||||
|
|
||||||
export const useChatMessages = ({
|
export const useChatMessages = ({
|
||||||
@@ -410,9 +411,15 @@ export const useChatMessages = ({
|
|||||||
const loadMessages = async ({ username, reset }) => {
|
const loadMessages = async ({ username, reset }) => {
|
||||||
if (!username || !selectedAccount.value) return
|
if (!username || !selectedAccount.value) return
|
||||||
|
|
||||||
logMessagePhase('loadMessages:enter', {
|
const trace = createPerfTrace('chat-messages', {
|
||||||
username,
|
account: String(selectedAccount.value || '').trim(),
|
||||||
reset
|
selectedUsername: String(selectedContact.value?.username || '').trim(),
|
||||||
|
username: String(username || '').trim(),
|
||||||
|
reset: !!reset
|
||||||
|
})
|
||||||
|
|
||||||
|
trace.log('loadMessages:enter', {
|
||||||
|
activeMessagesFor: String(activeMessagesFor.value || '').trim()
|
||||||
})
|
})
|
||||||
messagesError.value = ''
|
messagesError.value = ''
|
||||||
isLoadingMessages.value = true
|
isLoadingMessages.value = true
|
||||||
@@ -438,46 +445,37 @@ export const useChatMessages = ({
|
|||||||
if (realtimeEnabled.value) {
|
if (realtimeEnabled.value) {
|
||||||
params.source = 'realtime'
|
params.source = 'realtime'
|
||||||
}
|
}
|
||||||
logMessagePhase('loadMessages:request:start', {
|
trace.log('loadMessages:request:start', {
|
||||||
username,
|
|
||||||
reset,
|
|
||||||
offset,
|
offset,
|
||||||
existingCount: existing.length,
|
existingCount: existing.length,
|
||||||
renderTypeFilter: messageTypeFilter.value,
|
renderTypeFilter: messageTypeFilter.value,
|
||||||
realtime: !!realtimeEnabled.value
|
realtime: !!realtimeEnabled.value
|
||||||
})
|
})
|
||||||
const response = await api.listChatMessages(params)
|
const response = await api.listChatMessages(params)
|
||||||
logMessagePhase('loadMessages:request:end', {
|
trace.log('loadMessages:request:end', {
|
||||||
username,
|
|
||||||
reset,
|
|
||||||
rawCount: Array.isArray(response?.messages) ? response.messages.length : 0,
|
rawCount: Array.isArray(response?.messages) ? response.messages.length : 0,
|
||||||
total: Number(response?.total || 0),
|
total: Number(response?.total || 0),
|
||||||
hasMore: response?.hasMore
|
hasMore: response?.hasMore
|
||||||
})
|
})
|
||||||
|
|
||||||
const raw = response?.messages || []
|
const raw = response?.messages || []
|
||||||
logMessagePhase('loadMessages:normalize:start', {
|
trace.log('loadMessages:normalize:start', {
|
||||||
username,
|
|
||||||
rawCount: raw.length
|
rawCount: raw.length
|
||||||
})
|
})
|
||||||
const mapped = dedupeMessagesById(raw.map(normalizeMessage))
|
const mapped = dedupeMessagesById(raw.map(normalizeMessage))
|
||||||
logMessagePhase('loadMessages:normalize:end', {
|
trace.log('loadMessages:normalize:end', {
|
||||||
username,
|
|
||||||
mappedCount: mapped.length,
|
mappedCount: mapped.length,
|
||||||
renderTypeCounts: summarizeRenderTypes(mapped)
|
renderTypeCounts: summarizeRenderTypes(mapped)
|
||||||
})
|
})
|
||||||
|
|
||||||
if (activeMessagesFor.value !== username) {
|
if (activeMessagesFor.value !== username) {
|
||||||
logMessagePhase('loadMessages:abort-stale', {
|
trace.log('loadMessages:abort-stale', {
|
||||||
username,
|
|
||||||
activeMessagesFor: activeMessagesFor.value
|
activeMessagesFor: activeMessagesFor.value
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
logMessagePhase('loadMessages:state-commit:start', {
|
trace.log('loadMessages:state-commit:start', {
|
||||||
username,
|
|
||||||
reset,
|
|
||||||
mappedCount: mapped.length
|
mappedCount: mapped.length
|
||||||
})
|
})
|
||||||
if (reset) {
|
if (reset) {
|
||||||
@@ -496,8 +494,7 @@ export const useChatMessages = ({
|
|||||||
[username]: [...older, ...existing]
|
[username]: [...older, ...existing]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logMessagePhase('loadMessages:state-commit:end', {
|
trace.log('loadMessages:state-commit:end', {
|
||||||
username,
|
|
||||||
storedCount: (allMessages.value[username] || []).length
|
storedCount: (allMessages.value[username] || []).length
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -508,18 +505,14 @@ export const useChatMessages = ({
|
|||||||
hasMore: response?.hasMore
|
hasMore: response?.hasMore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logMessagePhase('loadMessages:meta-commit:end', {
|
trace.log('loadMessages:meta-commit:end', {
|
||||||
username,
|
|
||||||
total: Number(response?.total || 0),
|
total: Number(response?.total || 0),
|
||||||
hasMore: response?.hasMore
|
hasMore: response?.hasMore
|
||||||
})
|
})
|
||||||
|
|
||||||
logMessagePhase('loadMessages:nextTick:start', {
|
trace.log('loadMessages:nextTick:start')
|
||||||
username
|
|
||||||
})
|
|
||||||
await nextTick()
|
await nextTick()
|
||||||
logMessagePhase('loadMessages:nextTick:end', {
|
trace.log('loadMessages:nextTick:end', {
|
||||||
username,
|
|
||||||
renderedCount: (allMessages.value[username] || []).length
|
renderedCount: (allMessages.value[username] || []).length
|
||||||
})
|
})
|
||||||
const nextContainer = messageContainerRef.value
|
const nextContainer = messageContainerRef.value
|
||||||
@@ -532,13 +525,16 @@ export const useChatMessages = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateJumpToBottomState()
|
updateJumpToBottomState()
|
||||||
logMessagePhase('loadMessages:scroll:end', {
|
trace.log('loadMessages:scroll:end', {
|
||||||
username,
|
|
||||||
hasContainer: !!nextContainer,
|
hasContainer: !!nextContainer,
|
||||||
scrollTop: nextContainer ? nextContainer.scrollTop : null,
|
scrollTop: nextContainer ? nextContainer.scrollTop : null,
|
||||||
scrollHeight: nextContainer ? nextContainer.scrollHeight : null
|
scrollHeight: nextContainer ? nextContainer.scrollHeight : null
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
trace.log('loadMessages:error', {
|
||||||
|
message: String(error?.message || ''),
|
||||||
|
errorName: String(error?.name || '')
|
||||||
|
})
|
||||||
console.error('[chat-messages] loadMessages:error', {
|
console.error('[chat-messages] loadMessages:error', {
|
||||||
account: String(selectedAccount.value || '').trim(),
|
account: String(selectedAccount.value || '').trim(),
|
||||||
username: String(username || '').trim(),
|
username: String(username || '').trim(),
|
||||||
@@ -548,9 +544,7 @@ export const useChatMessages = ({
|
|||||||
messagesError.value = error?.message || '加载聊天记录失败'
|
messagesError.value = error?.message || '加载聊天记录失败'
|
||||||
} finally {
|
} finally {
|
||||||
isLoadingMessages.value = false
|
isLoadingMessages.value = false
|
||||||
logMessagePhase('loadMessages:exit', {
|
trace.log('loadMessages:exit', {
|
||||||
username,
|
|
||||||
reset,
|
|
||||||
loading: isLoadingMessages.value,
|
loading: isLoadingMessages.value,
|
||||||
error: messagesError.value
|
error: messagesError.value
|
||||||
})
|
})
|
||||||
@@ -571,9 +565,24 @@ export const useChatMessages = ({
|
|||||||
|
|
||||||
const refreshCurrentMessageMedia = async () => {
|
const refreshCurrentMessageMedia = async () => {
|
||||||
if (!selectedContact.value?.username) return
|
if (!selectedContact.value?.username) return
|
||||||
|
const trace = createPerfTrace('chat-messages', {
|
||||||
|
account: String(selectedAccount.value || '').trim(),
|
||||||
|
username: String(selectedContact.value?.username || '').trim(),
|
||||||
|
action: 'refreshCurrentMessageMedia'
|
||||||
|
})
|
||||||
|
trace.log('refreshCurrentMessageMedia:start', {
|
||||||
|
localMediaVersion: Number(localMediaVersion.value || 0)
|
||||||
|
})
|
||||||
bumpLocalMediaVersion()
|
bumpLocalMediaVersion()
|
||||||
|
trace.log('refreshCurrentMessageMedia:version-bumped', {
|
||||||
|
localMediaVersion: Number(localMediaVersion.value || 0)
|
||||||
|
})
|
||||||
renormalizeLoadedMessages(selectedContact.value.username)
|
renormalizeLoadedMessages(selectedContact.value.username)
|
||||||
|
trace.log('refreshCurrentMessageMedia:renormalized', {
|
||||||
|
renderedCount: (allMessages.value[selectedContact.value.username] || []).length
|
||||||
|
})
|
||||||
await nextTick()
|
await nextTick()
|
||||||
|
trace.log('refreshCurrentMessageMedia:end')
|
||||||
}
|
}
|
||||||
|
|
||||||
const refreshRealtimeIncremental = async () => {
|
const refreshRealtimeIncremental = async () => {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, onMounted, ref } from 'vue'
|
||||||
import { normalizeSessionPreview } from '~/lib/chat/formatters'
|
import { normalizeSessionPreview } from '~/lib/chat/formatters'
|
||||||
|
import { createPerfTrace } from '~/lib/chat/perf-logger'
|
||||||
|
|
||||||
const SESSION_LIST_WIDTH_KEY = 'ui.chat.session_list_width_physical'
|
const SESSION_LIST_WIDTH_KEY = 'ui.chat.session_list_width_physical'
|
||||||
const SESSION_LIST_WIDTH_KEY_LEGACY = 'ui.chat.session_list_width'
|
const SESSION_LIST_WIDTH_KEY_LEGACY = 'ui.chat.session_list_width'
|
||||||
@@ -170,6 +171,14 @@ export const useChatSessions = ({ chatAccounts, selectedAccount, realtimeEnabled
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const trace = createPerfTrace('chat-sessions', {
|
||||||
|
account: String(selectedAccount.value || '').trim(),
|
||||||
|
action: 'loadSessionsForSelectedAccount'
|
||||||
|
})
|
||||||
|
trace.log('loadSessions:start', {
|
||||||
|
realtimeEnabled: !!realtimeEnabled?.value
|
||||||
|
})
|
||||||
|
|
||||||
const fetchSessions = async (source) => {
|
const fetchSessions = async (source) => {
|
||||||
const params = {
|
const params = {
|
||||||
account: selectedAccount.value,
|
account: selectedAccount.value,
|
||||||
@@ -184,18 +193,38 @@ export const useChatSessions = ({ chatAccounts, selectedAccount, realtimeEnabled
|
|||||||
let sessionsResp = null
|
let sessionsResp = null
|
||||||
if (realtimeEnabled?.value) {
|
if (realtimeEnabled?.value) {
|
||||||
try {
|
try {
|
||||||
|
trace.log('loadSessions:request:start', {
|
||||||
|
source: 'realtime'
|
||||||
|
})
|
||||||
sessionsResp = await fetchSessions('realtime')
|
sessionsResp = await fetchSessions('realtime')
|
||||||
|
trace.log('loadSessions:request:end', {
|
||||||
|
source: 'realtime',
|
||||||
|
rawCount: Array.isArray(sessionsResp?.sessions) ? sessionsResp.sessions.length : 0
|
||||||
|
})
|
||||||
} catch {
|
} catch {
|
||||||
sessionsResp = null
|
sessionsResp = null
|
||||||
|
trace.log('loadSessions:request:error', {
|
||||||
|
source: 'realtime'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!sessionsResp) {
|
if (!sessionsResp) {
|
||||||
|
trace.log('loadSessions:request:start', {
|
||||||
|
source: 'default'
|
||||||
|
})
|
||||||
sessionsResp = await fetchSessions('')
|
sessionsResp = await fetchSessions('')
|
||||||
|
trace.log('loadSessions:request:end', {
|
||||||
|
source: 'default',
|
||||||
|
rawCount: Array.isArray(sessionsResp?.sessions) ? sessionsResp.sessions.length : 0
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const sessions = Array.isArray(sessionsResp?.sessions) ? sessionsResp.sessions : []
|
const sessions = Array.isArray(sessionsResp?.sessions) ? sessionsResp.sessions : []
|
||||||
contacts.value = mapSessions(sessions)
|
contacts.value = mapSessions(sessions)
|
||||||
contactsError.value = ''
|
contactsError.value = ''
|
||||||
|
trace.log('loadSessions:end', {
|
||||||
|
contactCount: contacts.value.length
|
||||||
|
})
|
||||||
return contacts.value
|
return contacts.value
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,6 +237,14 @@ export const useChatSessions = ({ chatAccounts, selectedAccount, realtimeEnabled
|
|||||||
const desiredSource = (sourceOverride != null)
|
const desiredSource = (sourceOverride != null)
|
||||||
? String(sourceOverride || '').trim()
|
? String(sourceOverride || '').trim()
|
||||||
: (realtimeEnabled?.value ? 'realtime' : '')
|
: (realtimeEnabled?.value ? 'realtime' : '')
|
||||||
|
const trace = createPerfTrace('chat-sessions', {
|
||||||
|
account: String(selectedAccount.value || '').trim(),
|
||||||
|
action: 'refreshSessionsForSelectedAccount',
|
||||||
|
desiredSource
|
||||||
|
})
|
||||||
|
trace.log('refreshSessions:start', {
|
||||||
|
previousUsername
|
||||||
|
})
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
account: selectedAccount.value,
|
account: selectedAccount.value,
|
||||||
@@ -219,15 +256,35 @@ export const useChatSessions = ({ chatAccounts, selectedAccount, realtimeEnabled
|
|||||||
let sessionsResp = null
|
let sessionsResp = null
|
||||||
if (desiredSource) {
|
if (desiredSource) {
|
||||||
try {
|
try {
|
||||||
|
trace.log('refreshSessions:request:start', {
|
||||||
|
source: desiredSource
|
||||||
|
})
|
||||||
sessionsResp = await api.listChatSessions({ ...params, source: desiredSource })
|
sessionsResp = await api.listChatSessions({ ...params, source: desiredSource })
|
||||||
|
trace.log('refreshSessions:request:end', {
|
||||||
|
source: desiredSource,
|
||||||
|
rawCount: Array.isArray(sessionsResp?.sessions) ? sessionsResp.sessions.length : 0
|
||||||
|
})
|
||||||
} catch {
|
} catch {
|
||||||
sessionsResp = null
|
sessionsResp = null
|
||||||
|
trace.log('refreshSessions:request:error', {
|
||||||
|
source: desiredSource
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!sessionsResp) {
|
if (!sessionsResp) {
|
||||||
try {
|
try {
|
||||||
|
trace.log('refreshSessions:request:start', {
|
||||||
|
source: 'default'
|
||||||
|
})
|
||||||
sessionsResp = await api.listChatSessions(params)
|
sessionsResp = await api.listChatSessions(params)
|
||||||
|
trace.log('refreshSessions:request:end', {
|
||||||
|
source: 'default',
|
||||||
|
rawCount: Array.isArray(sessionsResp?.sessions) ? sessionsResp.sessions.length : 0
|
||||||
|
})
|
||||||
} catch {
|
} catch {
|
||||||
|
trace.log('refreshSessions:request:error', {
|
||||||
|
source: 'default'
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -240,6 +297,10 @@ export const useChatSessions = ({ chatAccounts, selectedAccount, realtimeEnabled
|
|||||||
const matched = nextContacts.find((contact) => contact.username === previousUsername)
|
const matched = nextContacts.find((contact) => contact.username === previousUsername)
|
||||||
if (matched) selectedContact.value = matched
|
if (matched) selectedContact.value = matched
|
||||||
}
|
}
|
||||||
|
trace.log('refreshSessions:end', {
|
||||||
|
contactCount: nextContacts.length,
|
||||||
|
selectedUsername: String(selectedContact.value?.username || '').trim()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadContacts = async () => {
|
const loadContacts = async () => {
|
||||||
@@ -249,25 +310,50 @@ export const useChatSessions = ({ chatAccounts, selectedAccount, realtimeEnabled
|
|||||||
|
|
||||||
isLoadingContacts.value = true
|
isLoadingContacts.value = true
|
||||||
contactsError.value = ''
|
contactsError.value = ''
|
||||||
|
const trace = createPerfTrace('chat-sessions', {
|
||||||
|
account: String(selectedAccount.value || '').trim(),
|
||||||
|
action: 'loadContacts'
|
||||||
|
})
|
||||||
|
trace.log('loadContacts:start', {
|
||||||
|
cachedContacts: contacts.value.length
|
||||||
|
})
|
||||||
try {
|
try {
|
||||||
const hadLoadedAccountSnapshot = !!chatAccounts.loaded
|
const hadLoadedAccountSnapshot = !!chatAccounts.loaded
|
||||||
await chatAccounts.ensureLoaded()
|
await chatAccounts.ensureLoaded()
|
||||||
|
trace.log('loadContacts:accounts-ready', {
|
||||||
|
hadLoadedAccountSnapshot,
|
||||||
|
availableAccounts: Array.isArray(chatAccounts?.accounts) ? chatAccounts.accounts.length : 0
|
||||||
|
})
|
||||||
if (!selectedAccount.value && hadLoadedAccountSnapshot) {
|
if (!selectedAccount.value && hadLoadedAccountSnapshot) {
|
||||||
await chatAccounts.ensureLoaded({ force: true })
|
await chatAccounts.ensureLoaded({ force: true })
|
||||||
|
trace.log('loadContacts:accounts-refreshed')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!selectedAccount.value) {
|
if (!selectedAccount.value) {
|
||||||
clearContactsState(chatAccounts.error || '未检测到已解密账号,请先解密数据库。')
|
clearContactsState(chatAccounts.error || '未检测到已解密账号,请先解密数据库。')
|
||||||
|
trace.log('loadContacts:no-account', {
|
||||||
|
error: contactsError.value
|
||||||
|
})
|
||||||
return { usedPrefetched: false }
|
return { usedPrefetched: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
await loadSessionsForSelectedAccount()
|
await loadSessionsForSelectedAccount()
|
||||||
|
trace.log('loadContacts:end', {
|
||||||
|
contactCount: contacts.value.length
|
||||||
|
})
|
||||||
return { usedPrefetched: false }
|
return { usedPrefetched: false }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
clearContactsState(error?.message || '加载联系人失败')
|
clearContactsState(error?.message || '加载联系人失败')
|
||||||
|
trace.log('loadContacts:error', {
|
||||||
|
message: String(error?.message || '')
|
||||||
|
})
|
||||||
return { usedPrefetched: false }
|
return { usedPrefetched: false }
|
||||||
} finally {
|
} finally {
|
||||||
isLoadingContacts.value = false
|
isLoadingContacts.value = false
|
||||||
|
trace.log('loadContacts:exit', {
|
||||||
|
loading: isLoadingContacts.value,
|
||||||
|
error: contactsError.value
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user