1 /*
<lambda>null2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.tools.traces.parsers.perfetto
18 
19 import android.tools.Timestamp
20 import android.tools.parsers.AbstractTraceParser
21 import android.tools.traces.protolog.ProtoLogMessage
22 import android.tools.traces.protolog.ProtoLogTrace
23 import com.android.internal.protolog.common.LogLevel
24 
25 class ProtoLogTraceParser :
26     AbstractTraceParser<TraceProcessorSession, ProtoLogMessage, ProtoLogMessage, ProtoLogTrace>() {
27 
28     override val traceName = "Transitions Trace"
29 
30     override fun createTrace(entries: Collection<ProtoLogMessage>): ProtoLogTrace {
31         return ProtoLogTrace(entries)
32     }
33 
34     override fun doDecodeByteArray(bytes: ByteArray): TraceProcessorSession {
35         error("This parser can only read from perfetto trace processor")
36     }
37 
38     override fun shouldParseEntry(entry: ProtoLogMessage) = true
39 
40     override fun getEntries(input: TraceProcessorSession): List<ProtoLogMessage> {
41         val messages: List<ProtoLogMessage> =
42             mutableListOf<ProtoLogMessage>().apply {
43                 input.query(getSqlQueryProtoLogMessages()) { rows ->
44                     this.addAll(
45                         rows.map {
46                             val entryDebugString =
47                                 it.entries.joinToString { entry -> "${entry.key}: ${entry.value}" }
48                             requireNotNull(it["ts"]) {
49                                 "Timestamp was null. Entry: $entryDebugString"
50                             }
51                             requireNotNull(it["level"]) {
52                                 "Level was null. Entry: $entryDebugString"
53                             }
54                             requireNotNull(it["tag"]) { "Tag was null. Entry: $entryDebugString" }
55                             requireNotNull(it["message"]) {
56                                 "Message was null. Entry: $entryDebugString"
57                             }
58 
59                             ProtoLogMessage(
60                                 it["ts"] as Long,
61                                 LogLevel.entries.firstOrNull { entry ->
62                                     it["level"] == entry.toString()
63                                 } ?: error("Failed to convert ${it["level"]} to LogLevel enum"),
64                                 it["tag"] as String,
65                                 it["message"] as String,
66                                 it["stacktrace"]?.let { it as String },
67                                 it["location"]?.let { it as String },
68                             )
69                         }
70                     )
71                 }
72             }
73 
74         return messages
75     }
76 
77     override fun getTimestamp(entry: ProtoLogMessage): Timestamp = entry.timestamp
78 
79     override fun doParseEntry(entry: ProtoLogMessage) = entry
80 
81     companion object {
82         private fun getSqlQueryProtoLogMessages() =
83             "SELECT ts, level, tag, message, stacktrace, location FROM protolog;"
84     }
85 }
86