Skip to content

Commit

Permalink
feat: Enhance search logging (#2280)
Browse files Browse the repository at this point in the history
* Support custom fields in logging.

Signed-off-by: Jackson Goerner <jgoerner@squareup.com>

* Add search logSearchEvent function.

Signed-off-by: Jackson Goerner <jgoerner@squareup.com>

* Add utility for retrieving search state elements.

Signed-off-by: Jackson Goerner <jgoerner@squareup.com>

* Call logSearchEvent in search item classes.

Signed-off-by: Jackson Goerner <jgoerner@squareup.com>

* Fix issue where search_term not being updated for inline results.

Signed-off-by: Jackson Goerner <jgoerner@squareup.com>

* Add tests for log ducks.

Signed-off-by: Jackson Goerner <jgoerner@squareup.com>

* Add header to new scripts.

Signed-off-by: Jackson Goerner <jgoerner@squareup.com>

* Be explicit with kwargs for log generic action.

Signed-off-by: Jackson Goerner <jgoerner@squareup.com>

* Provide default case and forced return for getResults.

Signed-off-by: Jackson Goerner <jgoerner@squareup.com>

* Fix eslint error default case.

Signed-off-by: Jackson Goerner <jgoerner@squareup.com>

* Use python 3.9 type annotations.

Signed-off-by: Jackson Goerner <jgoerner@squareup.com>

* Update betterer results file.

Signed-off-by: Jackson Goerner <jgoerner@squareup.com>

* Fix tests related to tests using the connect wrapper.

Signed-off-by: Jackson Goerner <jgoerner@squareup.com>

* Fix test related to inlineresults fix.

Signed-off-by: Jackson Goerner <jgoerner@squareup.com>

* Fix + Add log tests.

Signed-off-by: Jackson Goerner <jgoerner@squareup.com>

---------

Signed-off-by: Jackson Goerner <jgoerner@squareup.com>
  • Loading branch information
glipR authored Dec 19, 2024
1 parent 2ea2f83 commit 1d01f19
Show file tree
Hide file tree
Showing 21 changed files with 600 additions and 70 deletions.
15 changes: 13 additions & 2 deletions frontend/amundsen_application/api/log/v0.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import logging

from typing import List
from http import HTTPStatus

from flask import Response, jsonify, make_response, request
Expand Down Expand Up @@ -38,7 +39,12 @@ def _log_generic_action(*,
label: str,
location: str,
value: str,
position: str) -> None:
position: str,
resource_href: str,
resource_type: str,
search_term: str,
search_page_index: int,
search_results: List[str]) -> None:
pass # pragma: no cover

try:
Expand All @@ -52,7 +58,12 @@ def _log_generic_action(*,
label=args.get('label', None),
location=args.get('location', None),
value=args.get('value', None),
position=args.get('position', None)
position=args.get('position', None),
resource_href=args.get('resource_href', None),
resource_type=args.get('resource_type', None),
search_term=args.get('search_term', None),
search_page_index=args.get('search_page_index', None),
search_results=args.get('search_results', None),
)
message = 'Logging of {} action successful'.format(command)
return make_response(jsonify({'msg': message}), HTTPStatus.OK)
Expand Down
8 changes: 3 additions & 5 deletions frontend/amundsen_application/static/.betterer.results
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,13 @@ exports[`eslint`] = {
[112, 6, 191, "Unexpected lexical declaration in case block.", "1433271452"],
[118, 6, 59, "Unexpected lexical declaration in case block.", "3993269111"]
],
"js/ducks/search/reducer.ts:1964208432": [
"js/ducks/search/reducer.ts:4202738843": [
[310, 6, 27, "Unexpected lexical declaration in case block.", "3336779920"],
[364, 6, 53, "Unexpected lexical declaration in case block.", "2684420572"],
[387, 6, 66, "Unexpected lexical declaration in case block.", "2160263677"],
[402, 6, 123, "Unexpected lexical declaration in case block.", "2271601490"],
[417, 6, 61, "Unexpected lexical declaration in case block.", "2053236172"]
],
"js/ducks/search/utils.ts:923002554": [
[20, 2, 248, "Expected a default case.", "1034339850"]
[417, 6, 61, "Unexpected lexical declaration in case block.", "2053236172"],
[444, 6, 60, "Unexpected lexical declaration in case block.", "3101482005"]
],
"js/ducks/tableMetadata/api/v0.ts:3333048528": [
[141, 23, 2, "Expected to return a value at the end of arrow function.", "5859494"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { dashboardSummary } from 'fixtures/metadata/dashboard';
import { NO_TIMESTAMP_TEXT } from '../../../constants';

import * as Constants from './constants';
import DashboardListItem, { DashboardListItemProps } from './index';
import { DashboardListItem, DashboardListItemProps } from './index';

const MOCK_DISPLAY_NAME = 'displayName';
const MOCK_ICON_CLASS = 'test-class';
Expand All @@ -37,6 +37,7 @@ const setup = (propOverrides?: Partial<DashboardListItemProps>) => {
name: dashboardSummary.name,
description: dashboardSummary.description,
},
logSearchEvent: jest.fn(),
...propOverrides,
};
const wrapper = shallow<DashboardListItem>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,45 @@ import { Link } from 'react-router-dom';
import BookmarkIcon from 'components/Bookmark/BookmarkIcon';

import { getSourceDisplayName, getSourceIconClass } from 'config/config-utils';
import { logClick } from 'utils/analytics';
import { buildDashboardURL } from 'utils/navigation';
import { formatDate } from 'utils/date';

import { ResourceType, DashboardResource } from 'interfaces';

import { LogSearchEventRequest } from 'ducks/log/types';
import { connect } from 'react-redux';
import { logSearchEvent } from 'ducks/log/reducer';
import { bindActionCreators } from 'redux';
import { NO_TIMESTAMP_TEXT } from '../../../constants';
import { LoggingParams } from '../types';
import { HighlightedDashboard } from '../MetadataHighlightList/utils';
import MetadataHighlightList from '../MetadataHighlightList';
import * as Constants from './constants';

export interface DashboardListItemProps {
export interface OwnProps {
dashboard: DashboardResource;
logging: LoggingParams;
dashboardHighlights: HighlightedDashboard;
}

class DashboardListItem extends React.Component<DashboardListItemProps, {}> {
export interface DispatchFromProps {
logSearchEvent: (
resourceLink: string,
resourceType: ResourceType,
source: string,
index: number,
event: any,
inline: boolean,
extra?: { [key: string]: any }
) => LogSearchEventRequest;
}

export type DashboardListItemProps = OwnProps & DispatchFromProps;

export class DashboardListItem extends React.Component<
DashboardListItemProps,
{}
> {
getLink = () => {
const { dashboard, logging } = this.props;

Expand All @@ -41,19 +61,23 @@ class DashboardListItem extends React.Component<DashboardListItemProps, {}> {
`icon resource-icon ${getSourceIconClass(dashboardId, dashboardType)}`;

render() {
const { dashboard, logging, dashboardHighlights } = this.props;
const { dashboard, logging, dashboardHighlights, logSearchEvent } =
this.props;

return (
<li className="list-group-item clickable">
<Link
className="resource-list-item table-list-item"
to={this.getLink()}
onClick={(e) =>
logClick(e, {
target_id: 'dashboard_list_item',
value: logging.source,
position: logging.index.toString(),
})
logSearchEvent(
this.getLink(),
ResourceType.dashboard,
logging.source,
logging.index,
e,
false
)
}
>
<div className="resource-info">
Expand Down Expand Up @@ -120,4 +144,17 @@ class DashboardListItem extends React.Component<DashboardListItemProps, {}> {
}
}

export default DashboardListItem;
export const mapDispatchToProps = (dispatch: any): DispatchFromProps => {
const dispatchableActions: DispatchFromProps = bindActionCreators(
{
logSearchEvent,
},
dispatch
);

return dispatchableActions;
};
export default connect<{}, DispatchFromProps, OwnProps>(
null,
mapDispatchToProps
)(DashboardListItem);
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import * as ConfigUtils from 'config/config-utils';

import { featureSummary } from 'fixtures/metadata/feature';

import FeatureListItem, {
import {
FeatureListItem,
FeatureListItemProps,
} from 'components/ResourceListItem/FeatureListItem';
import { RightIcon } from 'components/SVGIcons';
Expand All @@ -33,6 +34,7 @@ describe('FeatureListItem', () => {
name: MOCK_DISPLAY_NAME,
description: 'I am an ML <em>feature</em>',
},
logSearchEvent: jest.fn(),
...propOverrides,
};
const wrapper = shallow<typeof FeatureListItem>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,38 @@ import * as React from 'react';
import { Link } from 'react-router-dom';

import { getSourceDisplayName, getSourceIconClass } from 'config/config-utils';
import { logClick } from 'utils/analytics';

import BadgeList from 'features/BadgeList';
import { ResourceType, FeatureResource } from 'interfaces';

import { RightIcon } from 'components/SVGIcons';
import { LoggingParams } from '../types';
import { LogSearchEventRequest } from 'ducks/log/types';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { logSearchEvent } from 'ducks/log/reducer';
import { HighlightedResource } from '../MetadataHighlightList/utils';
import { LoggingParams } from '../types';

export interface FeatureListItemProps {
export interface OwnProps {
feature: FeatureResource;
logging: LoggingParams;
featureHighlights: HighlightedResource;
}

export interface DispatchFromProps {
logSearchEvent: (
resourceLink: string,
resourceType: ResourceType,
source: string,
index: number,
event: any,
inline: boolean,
extra?: { [key: string]: any }
) => LogSearchEventRequest;
}

export type FeatureListItemProps = OwnProps & DispatchFromProps;

const getLink = (feature: FeatureResource, logging: LoggingParams) =>
`/feature/${feature.key}?index=${logging.index}&source=${logging.source}`;

Expand All @@ -28,10 +45,11 @@ const generateResourceIconClass = (
featureType: ResourceType
): string => `icon resource-icon ${getSourceIconClass(featureId, featureType)}`;

const FeatureListItem: React.FC<FeatureListItemProps> = ({
export const FeatureListItem: React.FC<FeatureListItemProps> = ({
feature,
logging,
featureHighlights,
logSearchEvent,
}: FeatureListItemProps) => {
const source =
feature.availability?.length > 0 ? feature.availability[0] : '';
Expand All @@ -43,11 +61,14 @@ const FeatureListItem: React.FC<FeatureListItemProps> = ({
to={getLink(feature, logging)}
data-type="feature_list_item"
onClick={(e: React.MouseEvent<HTMLAnchorElement>) =>
logClick(e, {
target_id: 'feature_list_item',
value: logging.source,
position: logging.index.toString(),
})
logSearchEvent(
getLink(feature, logging),
ResourceType.feature,
logging.source,
logging.index,
e,
false
)
}
>
<div className="resource-info">
Expand Down Expand Up @@ -87,4 +108,17 @@ const FeatureListItem: React.FC<FeatureListItemProps> = ({
);
};

export default FeatureListItem;
export const mapDispatchToProps = (dispatch: any): DispatchFromProps => {
const dispatchableActions: DispatchFromProps = bindActionCreators(
{
logSearchEvent,
},
dispatch
);

return dispatchableActions;
};
export default connect<{}, DispatchFromProps, OwnProps>(
null,
mapDispatchToProps
)(FeatureListItem);
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import { ResourceType } from 'interfaces';

import * as ConfigUtils from 'config/config-utils';
import BadgeList from 'features/BadgeList';
import TableListItem, {
import {
TableListItem,
TableListItemProps,
getLink,
generateResourceIconClass,
Expand Down Expand Up @@ -56,6 +57,7 @@ describe('TableListItem', () => {
name: 'tableName',
description: 'I am the description',
},
logSearchEvent: jest.fn(),
...propOverrides,
};
// eslint-disable-next-line react/jsx-props-no-spreading
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,34 @@ import { getSourceDisplayName, getSourceIconClass } from 'config/config-utils';

import BadgeList from 'features/BadgeList';
import SchemaInfo from 'components/ResourceListItem/SchemaInfo';
import { logClick } from 'utils/analytics';
import { LoggingParams } from '../types';
import MetadataHighlightList from '../MetadataHighlightList';
import { LogSearchEventRequest } from 'ducks/log/types';
import { bindActionCreators } from 'redux';
import { logSearchEvent } from 'ducks/log/reducer';
import { connect } from 'react-redux';
import { HighlightedTable } from '../MetadataHighlightList/utils';
import MetadataHighlightList from '../MetadataHighlightList';
import { LoggingParams } from '../types';

export interface TableListItemProps {
export interface OwnProps {
table: TableResource;
logging: LoggingParams;
tableHighlights: HighlightedTable;
disabled?: boolean;
}

export interface DispatchFromProps {
logSearchEvent: (
resourceLink: string,
resourceType: ResourceType,
source: string,
index: number,
event: any,
inline: boolean,
extra?: { [key: string]: any }
) => LogSearchEventRequest;
}

export type TableListItemProps = OwnProps & DispatchFromProps;
/*
this function get's the table name from the key to preserve original
capitalization since search needs the names to be lowercase for analysis
Expand Down Expand Up @@ -53,11 +69,12 @@ export const getLink = (table, logging) => {
export const generateResourceIconClass = (databaseId: string): string =>
`icon resource-icon ${getSourceIconClass(databaseId, ResourceType.table)}`;

const TableListItem: React.FC<TableListItemProps> = ({
export const TableListItem: React.FC<TableListItemProps> = ({
table,
logging,
tableHighlights,
disabled,
logSearchEvent,
}) => (
<li className="list-group-item">
<Link
Expand All @@ -66,11 +83,14 @@ const TableListItem: React.FC<TableListItemProps> = ({
}`}
to={getLink(table, logging)}
onClick={(e) =>
logClick(e, {
target_id: 'table_list_item',
value: logging.source,
position: logging.index.toString(),
})
logSearchEvent(
getLink(table, logging),
ResourceType.table,
logging.source,
logging.index,
e,
false
)
}
>
<div className="resource-info">
Expand Down Expand Up @@ -132,4 +152,18 @@ const TableListItem: React.FC<TableListItemProps> = ({
</Link>
</li>
);
export default TableListItem;

export const mapDispatchToProps = (dispatch: any): DispatchFromProps => {
const dispatchableActions: DispatchFromProps = bindActionCreators(
{
logSearchEvent,
},
dispatch
);

return dispatchableActions;
};
export default connect<{}, DispatchFromProps, OwnProps>(
null,
mapDispatchToProps
)(TableListItem);
Loading

0 comments on commit 1d01f19

Please sign in to comment.