• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2024 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import m from 'mithril';
16import {LONG, NUM, STR} from '../../trace_processor/query_result';
17import {Trace} from '../../public/trace';
18import {DatasetSliceTrack} from '../../components/tracks/dataset_slice_track';
19import {SourceDataset} from '../../trace_processor/dataset';
20import {makeColorScheme} from '../../components/colorizer';
21import {HSLColor} from '../../base/color';
22import {Section} from '../../widgets/section';
23import {Tree, TreeNode} from '../../widgets/tree';
24import {Timestamp} from '../../components/widgets/timestamp';
25import {Time} from '../../base/time';
26import {DetailsShell} from '../../widgets/details_shell';
27import {GridLayout, GridLayoutColumn} from '../../widgets/grid_layout';
28import {Spinner} from '../../widgets/spinner';
29
30const DEPTH_TO_COLOR = [
31  makeColorScheme(new HSLColor({h: 122, s: 39, l: 49})),
32  makeColorScheme(new HSLColor({h: 0, s: 0, l: 70})),
33  makeColorScheme(new HSLColor({h: 45, s: 100, l: 51})),
34  makeColorScheme(new HSLColor({h: 4, s: 90, l: 58})),
35  makeColorScheme(new HSLColor({h: 291, s: 64, l: 42})),
36];
37
38const EVT_PX = 6; // Width of an event tick in pixels.
39
40export function createAndroidLogTrack(trace: Trace, uri: string) {
41  return new DatasetSliceTrack({
42    trace,
43    uri,
44    rootTableName: 'android_logs',
45    dataset: new SourceDataset({
46      src: `
47        select
48          id,
49          ts,
50          prio,
51          utid,
52          tag,
53          CASE
54            WHEN prio <= 3 THEN 0
55            WHEN prio = 4 THEN 1
56            WHEN prio = 5 THEN 2
57            WHEN prio = 6 THEN 3
58            WHEN prio = 7 THEN 4
59            ELSE -1
60          END as depth
61        from android_logs
62        order by ts
63        -- android_logs aren't guaranteed to be ordered by ts, but this is a
64        -- requirements for DatasetSliceTrack's mipmap operator to work
65        -- correctly, so we must explicitly sort them above.
66      `,
67      schema: {
68        id: NUM,
69        ts: LONG,
70        prio: NUM,
71        utid: NUM,
72        depth: NUM,
73        tag: STR,
74      },
75    }),
76    initialMaxDepth: 4,
77    colorizer: (row) => DEPTH_TO_COLOR[row.depth],
78    // It would be nice to show the message on the tooltip too, but loading a
79    // message for each event may balloon memory, so we just show the tag.
80    tooltip: (row) => [row.tag],
81    // All log events are instant events, render them as a little box rather
82    // than the default chevron.
83    instantStyle: {
84      width: EVT_PX,
85      render: (ctx, r) => ctx.fillRect(r.x, r.y, r.width, r.height),
86    },
87    // Make rows a little more compact.
88    sliceLayout: {
89      padding: 2,
90      sliceHeight: 7,
91    },
92    detailsPanel: (row) => {
93      // The msg is initially undefined, it'll be filled in when it loads
94      let msg: string | undefined;
95
96      // Quickly load the log message
97      trace.engine
98        .query(`select msg from android_logs where id = ${row.id}`)
99        .then((result) => {
100          const resultRow = result.maybeFirstRow({msg: STR});
101          msg = resultRow?.msg;
102        });
103
104      return {
105        render() {
106          return m(
107            DetailsShell,
108            {
109              title: `Android Log`,
110            },
111            m(
112              GridLayout,
113              m(
114                GridLayoutColumn,
115                m(
116                  Section,
117                  {title: 'Details'},
118                  m(
119                    Tree,
120                    m(TreeNode, {
121                      left: 'ID',
122                      right: row.id,
123                    }),
124                    m(TreeNode, {
125                      left: 'Timestamp',
126                      right: m(Timestamp, {ts: Time.fromRaw(row.ts)}),
127                    }),
128                    m(TreeNode, {
129                      left: 'Priority',
130                      right: row.prio,
131                    }),
132                    m(TreeNode, {
133                      left: 'Tag',
134                      right: row.tag,
135                    }),
136                    m(TreeNode, {
137                      left: 'Utid',
138                      right: row.utid,
139                    }),
140                    m(TreeNode, {
141                      left: 'Message',
142                      right: msg ? msg : m(Spinner),
143                    }),
144                  ),
145                ),
146              ),
147            ),
148          );
149        },
150      };
151    },
152  });
153}
154