xref: /aosp_15_r20/development/tools/winscope/src/viewers/viewer_protolog/presenter.ts (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
1/*
2 * Copyright (C) 2022 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
17import {assertDefined} from 'common/assert_utils';
18import {Store} from 'common/store';
19import {Trace} from 'trace/trace';
20import {PropertyTreeNode} from 'trace/tree_node/property_tree_node';
21import {
22  AbstractLogViewerPresenter,
23  NotifyLogViewCallbackType,
24} from 'viewers/common/abstract_log_viewer_presenter';
25import {LogSelectFilter, LogTextFilter} from 'viewers/common/log_filters';
26import {LogPresenter} from 'viewers/common/log_presenter';
27import {TextFilter} from 'viewers/common/text_filter';
28import {LogEntry, LogField, LogHeader} from 'viewers/common/ui_data_log';
29import {ProtologEntry, UiData} from './ui_data';
30
31export class Presenter extends AbstractLogViewerPresenter<
32  UiData,
33  PropertyTreeNode
34> {
35  private static readonly COLUMNS = {
36    logLevel: {
37      name: 'Log Level',
38      cssClass: 'log-level',
39    },
40    tag: {
41      name: 'Tag',
42      cssClass: 'tag',
43    },
44    sourceFile: {
45      name: 'Source files',
46      cssClass: 'source-file',
47    },
48    text: {
49      name: 'Search text',
50      cssClass: 'text',
51    },
52  };
53  protected override logPresenter = new LogPresenter<LogEntry>();
54
55  constructor(
56    trace: Trace<PropertyTreeNode>,
57    notifyViewCallback: NotifyLogViewCallbackType<UiData>,
58    private storage: Store,
59  ) {
60    super(trace, notifyViewCallback, UiData.createEmpty());
61  }
62
63  protected override makeHeaders(): LogHeader[] {
64    return [
65      new LogHeader(Presenter.COLUMNS.logLevel, new LogSelectFilter([])),
66      new LogHeader(
67        Presenter.COLUMNS.tag,
68        new LogSelectFilter([], false, '150'),
69      ),
70      new LogHeader(
71        Presenter.COLUMNS.sourceFile,
72        new LogSelectFilter([], false, '300'),
73      ),
74      new LogHeader(
75        Presenter.COLUMNS.text,
76        new LogTextFilter(new TextFilter()),
77      ),
78    ];
79  }
80
81  protected override async makeUiDataEntries(): Promise<ProtologEntry[]> {
82    const messages: ProtologEntry[] = [];
83
84    for (
85      let traceIndex = 0;
86      traceIndex < this.trace.lengthEntries;
87      ++traceIndex
88    ) {
89      const entry = assertDefined(this.trace.getEntry(traceIndex));
90      const messageNode = await entry.getValue();
91      const fields: LogField[] = [
92        {
93          spec: Presenter.COLUMNS.logLevel,
94          value: assertDefined(
95            messageNode.getChildByName('level'),
96          ).formattedValue(),
97        },
98        {
99          spec: Presenter.COLUMNS.tag,
100          value: assertDefined(
101            messageNode.getChildByName('tag'),
102          ).formattedValue(),
103        },
104        {
105          spec: Presenter.COLUMNS.sourceFile,
106          value: assertDefined(
107            messageNode.getChildByName('at'),
108          ).formattedValue(),
109        },
110        {
111          spec: Presenter.COLUMNS.text,
112          value: assertDefined(
113            messageNode.getChildByName('text'),
114          ).formattedValue(),
115        },
116      ];
117      messages.push(new ProtologEntry(entry, fields));
118    }
119
120    return messages;
121  }
122
123  protected override updateFiltersInHeaders(
124    headers: LogHeader[],
125    allEntries: ProtologEntry[],
126  ) {
127    for (const header of headers) {
128      if (header.filter instanceof LogSelectFilter) {
129        assertDefined(header.filter).options = this.getUniqueMessageValues(
130          allEntries,
131          (entry: ProtologEntry) =>
132            assertDefined(
133              entry.fields.find((f) => f.spec === header.spec),
134            ).value.toString(),
135        );
136      }
137    }
138  }
139
140  private getUniqueMessageValues(
141    allMessages: ProtologEntry[],
142    getValue: (message: ProtologEntry) => string,
143  ): string[] {
144    const uniqueValues = new Set<string>();
145    allMessages.forEach((message) => {
146      uniqueValues.add(getValue(message));
147    });
148    const result = [...uniqueValues];
149    result.sort();
150    return result;
151  }
152}
153