diff --git a/.babelrc b/.babelrc
new file mode 100644
index 0000000000..e21b3f2f2b
--- /dev/null
+++ b/.babelrc
@@ -0,0 +1,18 @@
+{
+ "presets": [
+ [
+ "@babel/preset-env",
+ {
+ "targets": { "node": "10" }
+ }
+ ],
+ "@babel/preset-react",
+ "@babel/preset-typescript"
+ ],
+ "plugins": [
+ "@babel/plugin-transform-modules-commonjs",
+ ["@babel/plugin-transform-runtime", { "regenerator": true }],
+ "@babel/plugin-proposal-class-properties",
+ "@babel/plugin-proposal-object-rest-spread"
+ ]
+}
\ No newline at end of file
diff --git a/.cypress/CYPRESS_TESTS.md b/.cypress/CYPRESS_TESTS.md
new file mode 100644
index 0000000000..bba2db259d
--- /dev/null
+++ b/.cypress/CYPRESS_TESTS.md
@@ -0,0 +1,146 @@
+# Observability Cypress Test Cases
+The observability plugin currently has 4 modules in it. Each of the modules have their own cypress tests [here](./integration).
+
+## 1. Event Analytics
+
+### Home
+
+* Query Search
+ * Type query in search bar then click ‘refresh’ button on date range picker to search would redirect user to explorer page, and display searching results in that page
+ * Click ‘refresh’ button directly without having a query in search bar would redirect user to explorer page with a new empty tab
+* Actions - Event Explorer
+ * Click ‘Event explorer’ in the dropdown list of actions would redirect user to explorer page
+* Actions - Delete
+ * Check saved queries and(or) saved visualizations then click delete in dropdown list of actions is expected to delete selected saved objects’
+* Actions - Add Samples
+ * Click ‘add samples’ in the dropdown list of actions is expected to add 9 sample saved queries and visualizations, the newly added samples is expected to shop up in Queries and Visualizations table
+
+### Explorer
+
+* Add new tabs
+
+ * Click ’add new‘ button is expected to add top level tabs
+ * Redirections from clicking history links is expected to
+ * create new tab if there’s already tab with searched data
+ * populate the the first empty tab
+ * Redirections from clicking ‘new query’ in home page would always create new tab
+
+* Close tabs
+
+ * Close unselected tab should close that tab only, and not change the current selected tab
+ * Click ‘add new’ to add new tabs and click on any tab before the last created tab, then close that tab. It is expected to close the current tab properly, and newly selected tab is expected to be one tab before it if there’s any existing tabs or the immediate tab comes after the deleted one
+ * It is expected to be not able to close a tab when there’s only one tab left, and user will be prompt with a toast message
+
+* Query Saving
+
+ * Saves a query on event tab of explorer page is expected to create a new saved query. The user should see this new saved query in Queries and Visualizations table.
+ * Saves a visualization on visualization tab of explorer page is expected to create a new saved visualization. The user should see this new saved Visualization Queries and Visualizations table on event home should display this new saved visualization
+ * Saves a visualization to existing panels
+* Sidebar
+ * Search fields
+ * Toggle fields between selected and available fields categories
+ * Override timestamp
+ * Click on a timestamp field to override timestamp is expected to create a new saved, default timestamp for this index
+* Count distribution
+ * Change time interval
+ * Display event counts
+* Visualization tab
+ * Switch visualizations from dropdown list
+* Data Grid
+ * Expand/collapse a data entry
+
+## 2. Custom panels
+
+### Home Table
+
+* Check panel name validity
+* Create and open a new panel
+* Duplicate and rename a panel
+* Search an existing panel
+* Delete panels
+
+### Create Visualization
+
+* Create two visualizations in events explorer
+
+### Panel View
+
+* Move to test panel
+* Duplicate using panel action
+* Rename using panel action
+* Change date filter
+* Add existing visualizations
+* Add ppl filter to the panel
+* Drag and Drop Visualization in edit mode
+* Resize a Visualization in edit mode
+* Delete a Visualization in edit mode
+* Duplicate a Visualization
+* Replace a Visualization
+* Create a new Visualization and directly add to an existing panel
+* Edit a Visualization and check the change in panels
+
+### Clean Up
+
+* Add Samples
+* Verify sample visualization names in sample panel
+* Delete All Visualization from event analytics
+* Delete all Panels
+
+## 3. Notebooks
+
+* Displays error toast for invalid notebook name
+* Creates a notebook and redirects to the notebook
+* Duplicates and renames a notebook
+* Searches existing notebooks
+* Deletes notebooks
+* Create in-context PDF report from notebook
+* Create in-context PNG report from notebook
+* Create on-demand report definition from context menu
+* Goes into a notebook and creates paragraphs
+* Renders markdown
+* Shows output message
+* Renders input only mode
+* Renders output only mode
+* Duplicates paragraphs
+* Adds a dashboards visualization paragraph
+* Adds an observability visualization paragraph
+* Adds a SQL query paragraph
+* Adds a PPL query paragraph
+* Clears outputs
+* Runs all paragraphs
+* Adds paragraph to top and bottom
+* Moves paragraphs
+* Duplicates and renames the notebook
+* Deletes paragraphs
+* Deletes notebook
+
+## 4. Trace analytics
+
+### Dashboard
+
+* Indexes test data
+* Renders empty state
+* Renders the dashboard table
+* Adds the percentile filters
+* Opens latency trend popover
+* Redirects to traces table with filter
+* Renders service map
+* Renders plots
+
+### Service
+
+* Renders empty state
+* Renders the services table
+* Searches correctly
+* Renders service view empty state
+* Renders service view
+* Renders spans data grid, flyout, filters
+
+### Trace
+
+* Renders empty state
+* Renders the traces table
+* Searches correctly
+* Renders the trace view
+* Renders data grid, flyout and filters
+
diff --git a/.cypress/integration/1_event_analytics.spec.js b/.cypress/integration/1_event_analytics.spec.js
new file mode 100644
index 0000000000..02e79b33f6
--- /dev/null
+++ b/.cypress/integration/1_event_analytics.spec.js
@@ -0,0 +1,460 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+///
+import {
+ delay,
+ TEST_QUERIES,
+ TESTING_PANEL,
+ SAVE_QUERY1,
+ SAVE_QUERY2,
+ SAVE_QUERY3,
+ SAVE_QUERY4,
+} from '../utils/constants';
+import { supressResizeObserverIssue } from '../utils/constants';
+
+const landOnEventHome = () => {
+ cy.visit(`${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/event_analytics`);
+ cy.wait(delay);
+};
+
+const landOnEventExplorer = () => {
+ cy.visit(
+ `${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/event_analytics/explorer`
+ );
+ cy.wait(delay * 2);
+};
+
+const landOnPanels = () => {
+ cy.visit(
+ `${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/operational_panels`
+ );
+ cy.wait(delay);
+};
+
+const querySearch = (query) => {
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').type(query);
+ cy.get('[data-test-subj="superDatePickerToggleQuickMenuButton"]').click();
+ cy.get('[data-test-subj="superDatePickerCommonlyUsed_This_year"]').click();
+ cy.get('[data-test-subj="superDatePickerApplyTimeButton"]').contains('Refresh').click();
+};
+
+describe('Adding sample data and visualization', () => {
+ it('Adds sample flights data for event analytics', () => {
+ cy.visit(`${Cypress.env('opensearchDashboards')}/app/home#/tutorial_directory/sampleData`);
+ cy.get('div[data-test-subj="sampleDataSetCardflights"]')
+ .contains(/(Add|View) data/)
+ .click();
+ cy.wait(delay);
+ });
+});
+
+describe('Has working breadcrumbs', () => {
+ it('Redirect to correct page on breadcrumb click', () => {
+ landOnEventExplorer();
+ cy.wait(delay * 3);
+ cy.get('.euiBreadcrumb[href="#/event_analytics/explorer"]').contains('Explorer').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('exist');
+ cy.get('.euiBreadcrumb[href="#/event_analytics"]').contains('Event analytics').click();
+ cy.wait(delay);
+ cy.get('.euiTitle').contains('Event analytics').should('exist');
+ cy.get('.euiBreadcrumb[href="observability-dashboards#/"]').contains('Observability').click();
+ cy.wait(delay);
+ cy.get('.euiTitle').contains('Event analytics').should('exist');
+ });
+});
+
+describe('Open flyout for a data row to see details', () => {
+ beforeEach(() => {
+ landOnEventExplorer();
+ });
+
+ it('Should be able to open flyout and see data, json and traces', () => {
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').type(TEST_QUERIES[0].query);
+ cy.get('[data-test-subj="superDatePickerApplyTimeButton"]').contains('Refresh').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="docTable"] tbody tr button.euiButtonIcon').first().click();
+ cy.get('.observability-flyout').should('exist');
+ cy.get('.observability-flyout .osdDocViewer .euiTabs span.euiTab__content').contains('JSON').click();
+ cy.get('.observability-flyout .osdDocViewer .euiTabs span.euiTab__content').contains('Traces').click();
+ cy.get('.observability-flyout .osdDocViewer .euiTabs span.euiTab__content').contains('Table').click();
+ });
+
+ it('Should be able to see srrounding docs', () => {
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').type(TEST_QUERIES[0].query);
+ cy.get('[data-test-subj="superDatePickerApplyTimeButton"]').contains('Refresh').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="docTable"] tbody tr button.euiButtonIcon').first().click();
+ cy.get('.observability-flyout').should('exist');
+ cy.get('.observability-flyout span.euiButton__text').contains('View surrounding events').click();
+ cy.get('.observability-flyout #surroundingFyout').contains('View surrounding events').should('exist');
+ });
+});
+
+describe('Search a query on event home', () => {
+ it('Search a query and redirect to explorer to display result data', () => {
+ landOnEventHome();
+
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').type(TEST_QUERIES[0].query);
+ cy.get('[data-test-subj="superDatePickerApplyTimeButton"]').contains('Refresh').click();
+ cy.wait(delay);
+
+ cy.url().should('contain', '#/event_analytics/explorer');
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').contains(TEST_QUERIES[0].query);
+ });
+});
+
+describe('Add/delete/switch explorer top level tabs', () => {
+ beforeEach(() => {
+ landOnEventExplorer();
+ });
+
+ it('Add a new tab', () => {
+ cy.get('[data-test-subj="eventExplorer__topLevelTabbing"]')
+ .find('button.euiTab')
+ .then((lists) => {
+ const initialLength = Cypress.$(lists).length;
+ cy.get('[data-test-subj="eventExplorer__addNewTab"]').click();
+ cy.get('[data-test-subj="eventExplorer__topLevelTabbing"]')
+ .find('button.euiTab')
+ .should('have.length', initialLength + 1);
+ });
+ });
+
+ it('Click to switch to anther tab', () => {
+ cy.get('[data-test-subj="eventExplorer__addNewTab"]').click();
+ cy.get('[data-test-subj="eventExplorer__topLevelTabbing"]')
+ .find('button.euiTab')
+ .first()
+ .click();
+ cy.wait(delay);
+
+ cy.get('[data-test-subj="eventExplorer__topLevelTabbing"]')
+ .find('button.euiTab')
+ .first()
+ .should('have.class', 'euiTab-isSelected');
+ });
+
+ it('Close a tab', () => {
+ cy.get('[data-test-subj="eventExplorer__addNewTab"]').click();
+ cy.get('[data-test-subj="eventExplorer__topLevelTabbing"]')
+ .find('button.euiTab')
+ .then((lists) => {
+ const initialLength = Cypress.$(lists).length;
+ cy.get('[data-test-subj="eventExplorer__topLevelTabbing"] button.euiTab')
+ .first()
+ .find('[data-test-subj="eventExplorer__tabClose"]')
+ .click();
+ cy.get('[data-test-subj="eventExplorer__topLevelTabbing"]')
+ .find('button.euiTab')
+ .should('have.length', initialLength - 1);
+ });
+ });
+
+ it('Close current selected tab', () => {
+ cy.get('[data-test-subj="eventExplorer__addNewTab"]').click();
+ cy.get('[data-test-subj="eventExplorer__addNewTab"]').click();
+ cy.get('[data-test-subj="eventExplorer__topLevelTabbing"]')
+ .find('button.euiTab')
+ .then((lists) => {
+ const initialLength = Cypress.$(lists).length;
+ cy.get('[data-test-subj="eventExplorer__topLevelTabbing"] button.euiTab').eq(1).click();
+ cy.get('button.euiTab-isSelected [data-test-subj="eventExplorer__tabClose"]').click();
+ cy.get('[data-test-subj="eventExplorer__topLevelTabbing"]')
+ .find('button.euiTab')
+ .should('have.length', initialLength - 1);
+ });
+ });
+
+ it('Close another unselected tab', () => {
+ cy.get('[data-test-subj="eventExplorer__addNewTab"]').click();
+ cy.get('[data-test-subj="eventExplorer__addNewTab"]').click();
+ cy.get('[data-test-subj="eventExplorer__topLevelTabbing"]')
+ .find('button.euiTab')
+ .then((lists) => {
+ const initialLength = Cypress.$(lists).length;
+ cy.get('button.euiTab').first().find('[data-test-subj="eventExplorer__tabClose"]').click();
+ cy.get('[data-test-subj="eventExplorer__topLevelTabbing"]')
+ .find('button.euiTab')
+ .should('have.length', initialLength - 1);
+ });
+ });
+});
+
+describe('Load a saved query from event home', () => {
+ it('Click on a saved query and redirect to explorer', () => {
+ landOnEventExplorer();
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').type(TEST_QUERIES[0].query);
+ cy.get('[data-test-subj="superDatePickerApplyTimeButton"]').contains('Refresh').click();
+ cy.wait(delay);
+
+ cy.get('.tab-title').contains('Events').click();
+ cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click();
+ cy.get('[data-test-subj="eventExplorer__querySaveName"]').type(SAVE_QUERY4);
+ cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click();
+ cy.wait(delay);
+
+ cy.get('.euiToastHeader__title').contains('successfully').should('exist');
+
+ landOnEventHome();
+
+ cy.get('[data-test-subj="eventHome__savedQueryTableName"]')
+ .first()
+ .contains(SAVE_QUERY4)
+ .click();
+ cy.wait(delay);
+
+ cy.url().should('contain', '#/event_analytics/explorer');
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').contains(TEST_QUERIES[0].query);
+ });
+});
+
+describe('Click actions', () => {
+ beforeEach(() => {
+ landOnEventHome();
+ });
+
+ it('Actions - click event explorer', () => {
+ cy.get('[data-test-subj="eventHomeAction"]').click();
+ cy.get('[data-test-subj="eventHomeAction__explorer"]').click();
+ cy.wait(delay);
+ cy.url().should('contain', '#/event_analytics/explorer');
+ });
+
+ it('Actions - add sample data', () => {
+ cy.get('[data-test-subj="eventHomeAction"]').click();
+ cy.get('[data-test-subj="eventHomeAction__addSamples"]').click();
+ cy.get('[data-test-subj="confirmModalConfirmButton"]').click();
+ cy.wait(delay * 2);
+ cy.get('.euiToastHeader__title').contains('successfully').should('exist');
+ });
+
+ it('Actions - delete saved queries', () => {
+ cy.get('[data-test-subj^="checkboxSelectRow"]').first().check();
+ cy.get('[data-test-subj="eventHomeAction"]').click();
+ cy.get('[data-test-subj="eventHomeAction__delete"]').click();
+ cy.get('[data-test-subj="popoverModal__deleteTextInput"]').type('delete');
+ cy.get('[data-test-subj="popoverModal__deleteButton"').click();
+ cy.wait(delay);
+ cy.get('.euiToastHeader__title').contains('successfully').should('exist');
+ });
+});
+
+describe('Saves a query on explorer page', () => {
+ it('Saves a query on event tab of explorer page', () => {
+ landOnEventExplorer();
+
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').type(TEST_QUERIES[0].query);
+ cy.get('[data-test-subj="superDatePickerApplyTimeButton"]').contains('Refresh').click();
+ cy.wait(delay);
+
+ cy.get('.tab-title').contains('Events').click();
+ cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="eventExplorer__querySaveName"]').type(SAVE_QUERY1);
+ cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click();
+ cy.wait(delay);
+
+ cy.get('.euiToastHeader__title').contains('successfully').should('exist');
+
+ landOnEventHome();
+
+ cy.get('[data-test-subj="eventHome__savedQueryTableName"]').first().contains(SAVE_QUERY1);
+ });
+
+ it('Saves a visualization on visualization tab of explorer page', () => {
+ landOnEventExplorer();
+
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').type(TEST_QUERIES[1].query);
+ cy.get('[data-test-subj="superDatePickerApplyTimeButton"]').contains('Refresh').click();
+ cy.wait(delay);
+ supressResizeObserverIssue();
+ cy.get('button[id="main-content-vis"]').contains('Visualizations').click();
+ cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click();
+ cy.get('[data-test-subj="eventExplorer__querySaveName"]').type(SAVE_QUERY2);
+ cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click();
+ cy.wait(delay);
+
+ cy.get('.euiToastHeader__title').contains('successfully').should('exist');
+
+ landOnEventHome();
+
+ cy.get('[data-test-subj="eventHome__savedQueryTableName"]').first().contains(SAVE_QUERY2);
+ });
+
+ it('Saves a visualization to an existing panel', () => {
+ landOnPanels();
+
+ cy.get('[data-test-subj="customPanels__createNewPanels"]').click();
+ cy.get('input.euiFieldText').type(TESTING_PANEL);
+ cy.get('.euiButton__text')
+ .contains(/^Create$/)
+ .click();
+ cy.wait(delay);
+
+ landOnEventExplorer();
+
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').type(TEST_QUERIES[1].query);
+ cy.get('[data-test-subj="superDatePickerApplyTimeButton"]').contains('Refresh').click();
+ cy.wait(delay);
+
+ supressResizeObserverIssue();
+ cy.get('button[id="main-content-vis"]').contains('Visualizations').click();
+ cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click();
+ cy.get('[data-test-subj="eventExplorer__querySaveName"]').type(SAVE_QUERY3);
+ cy.get('[data-test-subj="eventExplorer__querySaveComboBox"]').type(TESTING_PANEL);
+ cy.get(`input[value="${TESTING_PANEL}"]`).click();
+ cy.get('[data-test-subj="eventExplorer__querySaveComboBox"] [data-test-subj="comboBoxToggleListButton"]').click();
+ cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click();
+ cy.wait(delay);
+
+ cy.get('.euiToastHeader__title').contains('successfully').should('exist');
+ });
+});
+
+describe('Override default timestamp for an index', () => {
+ it('Click override button to override default timestamp', () => {
+ landOnEventExplorer();
+
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').type(TEST_QUERIES[2].query);
+ cy.get('[data-test-subj="superDatePickerApplyTimeButton"]').contains('Refresh').click();
+ cy.get('.tab-title').contains('Events').click();
+ cy.get('[data-test-subj="eventExplorer__overrideDefaultTimestamp"]').click();
+ cy.wait(delay);
+
+ cy.get('[data-attr-field="utc_time"] [data-test-subj="eventFields__default-timestamp-mark"')
+ .contains('Default Timestamp').should('exist');
+ cy.get('[data-attr-field="timestamp"] [data-test-subj="eventFields__default-timestamp-mark"').should('not.exist');
+ });
+});
+
+describe('Toggle sidebar fields', () => {
+ it('Toggle fields between available and selected section', () => {
+ landOnEventExplorer();
+ querySearch(TEST_QUERIES[0].query);
+ cy.wait(delay);
+
+ cy.get('[data-test-subj="fieldToggle-AvgTicketPrice"]').click();
+ cy.get('[data-test-subj="field-AvgTicketPrice"]').should('exist');
+ cy.get('[data-test-subj="docTable"]').find('th').contains('_source').should('not.exist');
+ cy.get('[data-test-subj="fieldToggle-AvgTicketPrice"]').click();
+ cy.get('[data-test-subj="field-AvgTicketPrice"]').should('exist');
+ cy.get('[data-test-subj="docTable"]').find('th').contains('_source').should('exist');
+ });
+});
+
+describe('Search fields in sidebar', () => {
+ it('Search a field', () => {
+ landOnEventExplorer();
+ querySearch(TEST_QUERIES[0].query);
+ cy.wait(delay);
+
+ cy.get('[data-test-subj="eventExplorer__sidebarSearch"]').type('A');
+ cy.get('[data-test-subj="field-Cancelled"]').should('not.exist');
+ cy.get('[data-test-subj="field-AvgTicketPrice"]').should('exist');
+ cy.get('[data-test-subj="field-DestAirportID"]').should('exist');
+ cy.get('[data-test-subj="field-OriginAirportID"]').should('exist');
+ });
+});
+
+describe('Delete saved objects', () => {
+ it('Delete visualizations/querys from event analytics', () => {
+ landOnEventHome();
+ cy.get('[data-test-subj="tablePaginationPopoverButton"]').click();
+ cy.get('.euiContextMenuItem__text').contains('50 rows').click();
+ cy.get('.euiCheckbox__input[data-test-subj="checkboxSelectAll"]').click();
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Actions').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Delete').click();
+ cy.wait(delay);
+
+ cy.get('button.euiButton--danger').should('be.disabled');
+
+ cy.get('input.euiFieldText[placeholder="delete"]').type('delete');
+ cy.get('button.euiButton--danger').should('not.be.disabled');
+ cy.get('.euiButton__text').contains('Delete').click();
+ cy.wait(delay);
+ cy.get('.euiTextAlign').contains('No Queries or Visualizations').should('exist');
+ });
+});
+
+describe('Switch on and off livetail', () => {
+ it('Switch on and off in live tail', () => {
+ landOnEventExplorer();
+ cy.wait(delay);
+
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').type(TEST_QUERIES[1].query);
+
+ cy.get('[data-test-subj=eventLiveTail]').click();
+ cy.get('[data-test-subj=eventLiveTail__delay10s]').click();
+ cy.wait(delay * 2);
+ cy.get('.euiToastHeader__title').contains('On').should('exist');
+
+ cy.get('[data-test-subj=eventLiveTail__off').click();
+ cy.wait(delay * 2);
+ cy.get('.euiToastHeader__title').contains('Off').should('exist');
+ });
+});
+
+describe('Live tail stop automatically', () => {
+ it('Moving to other tab should stop live tail automatically', () => {
+ landOnEventExplorer();
+ cy.wait(delay);
+
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').type(TEST_QUERIES[1].query);
+
+ cy.get('[data-test-subj=eventLiveTail]').click();
+ cy.get('[data-test-subj=eventLiveTail__delay10s]').click();
+ cy.wait(delay * 2);
+ cy.get('.euiToastHeader__title').contains('On').should('exist');
+ });
+
+ it('Add a new tab', () => {
+ cy.get('[data-test-subj="eventExplorer__topLevelTabbing"]')
+ .find('button.euiTab')
+ .then((lists) => {
+ const initialLength = Cypress.$(lists).length;
+ cy.get('[data-test-subj="eventExplorer__addNewTab"]').click();
+ cy.get('[data-test-subj="eventExplorer__topLevelTabbing"]')
+ .find('button.euiTab')
+ .should('have.length', initialLength + 1);
+ });
+});
+
+ it('Click to switch to another tab', () => {
+ cy.get('[data-test-subj="eventExplorer__addNewTab"]').click();
+ cy.get('[data-test-subj="eventExplorer__topLevelTabbing"]')
+ .find('button.euiTab')
+ .first()
+ .click();
+ cy.wait(delay);
+
+ cy.get('[data-test-subj="eventExplorer__topLevelTabbing"]')
+ .find('button.euiTab')
+ .first()
+ .should('have.class', 'euiTab-isSelected');
+});
+
+ it('Close current selected tab', () => {
+ cy.get('[data-test-subj="eventExplorer__addNewTab"]').click();
+ cy.get('[data-test-subj="eventExplorer__addNewTab"]').click();
+ cy.get('[data-test-subj="eventExplorer__topLevelTabbing"]')
+ .find('button.euiTab')
+ .then((lists) => {
+ const initialLength = Cypress.$(lists).length;
+ cy.get('[data-test-subj="eventExplorer__topLevelTabbing"] button.euiTab').eq(1).click();
+ cy.get('button.euiTab-isSelected [data-test-subj="eventExplorer__tabClose"]').click();
+ cy.get('[data-test-subj="eventExplorer__topLevelTabbing"]')
+ .find('button.euiTab')
+ .should('have.length', initialLength - 1);
+ });
+ });
+
+ it('Live tail should be stopped', () => {
+ cy.get('.euiButton__text').contains('Live');
+ });
+});
\ No newline at end of file
diff --git a/.cypress/integration/2_notebooks.spec.js b/.cypress/integration/2_notebooks.spec.js
new file mode 100644
index 0000000000..d15b922a7c
--- /dev/null
+++ b/.cypress/integration/2_notebooks.spec.js
@@ -0,0 +1,463 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+///
+
+import {
+ delay,
+ TEST_NOTEBOOK,
+ MARKDOWN_TEXT,
+ SAMPLE_URL,
+ SQL_QUERY_TEXT,
+ PPL_QUERY_TEXT,
+} from '../utils/constants';
+
+import { SAMPLE_PANEL } from '../utils/panel_constants';
+
+import { skipOn } from '@cypress/skip-test';
+
+describe('Adding sample data and visualization', () => {
+ it('Adds sample flights data for visualization paragraph', () => {
+ cy.visit(`${Cypress.env('opensearchDashboards')}/app/home#/tutorial_directory/sampleData`);
+ cy.get('div[data-test-subj="sampleDataSetCardflights"]')
+ .contains(/(Add|View) data/)
+ .click();
+ });
+
+ it('Add sample observability data', () => {
+ cy.visit(
+ `${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/operational_panels/`
+ );
+ cy.get('.euiButton__text').contains('Actions').click();
+ cy.get('.euiContextMenuItem__text').contains('Add samples').click();
+ cy.get('.euiModalHeader__title[data-test-subj="confirmModalTitleText"]')
+ .contains('Add samples')
+ .should('exist');
+ cy.get('.euiButton__text').contains('Yes').click();
+ cy.wait(delay * 5);
+ cy.get('.euiTableCellContent').contains(SAMPLE_PANEL).should('exist');
+ });
+});
+
+describe('Testing notebooks table', () => {
+ beforeEach(() => {
+ cy.visit(`${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/notebooks`);
+ });
+
+ it('Displays error toast for invalid notebook name', () => {
+ cy.get('.euiButton__text').contains('Create notebook').click();
+ cy.wait(delay);
+ cy.get('.euiButton__text')
+ .contains(/^Create$/)
+ .click();
+ cy.wait(delay);
+
+ cy.get('.euiToastHeader__title').contains('Invalid notebook name').should('exist');
+ });
+
+ it('Creates a notebook and redirects to the notebook', () => {
+ cy.get('.euiButton__text').contains('Create notebook').click();
+ cy.wait(delay);
+ cy.get('input.euiFieldText').type(TEST_NOTEBOOK);
+ cy.get('.euiButton__text')
+ .contains(/^Create$/)
+ .click();
+ cy.wait(delay);
+
+ cy.contains(TEST_NOTEBOOK).should('exist');
+ });
+
+ it('Duplicates and renames a notebook', () => {
+ cy.get('.euiCheckbox__input[title="Select this row"]').eq(0).click();
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Actions').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Duplicate').click();
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Duplicate').click();
+ cy.wait(delay);
+
+ cy.get('.euiCheckbox__input[title="Select this row"]').eq(1).click();
+ cy.wait(delay);
+ cy.get('.euiCheckbox__input[title="Select this row"]').eq(0).click();
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Actions').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Rename').click();
+ cy.wait(delay);
+ cy.get('input.euiFieldText').type(' (rename)');
+ cy.get('.euiButton__text').contains('Rename').click();
+ cy.wait(delay);
+ });
+
+ it('Searches existing notebooks', () => {
+ cy.get('input.euiFieldSearch').type('this notebook should not exist');
+ cy.wait(delay);
+
+ cy.get('.euiTableCellContent__text').contains('No items found').should('exist');
+
+ cy.get('.euiFormControlLayoutClearButton').click();
+ cy.wait(delay);
+ cy.get('input.euiFieldSearch').type(TEST_NOTEBOOK + ' (copy) (rename)');
+ cy.wait(delay);
+
+ cy.get('a.euiLink')
+ .contains(TEST_NOTEBOOK + ' (copy) (rename)')
+ .should('exist');
+ });
+
+ it('Deletes notebooks', () => {
+ cy.get('.euiCheckbox__input[data-test-subj="checkboxSelectAll"]').click();
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Actions').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Delete').click();
+ cy.wait(delay);
+
+ cy.get('button.euiButton--danger').should('be.disabled');
+
+ cy.get('input.euiFieldText[placeholder="delete"]').type('delete');
+ cy.get('button.euiButton--danger').should('not.be.disabled');
+ cy.get('.euiButton__text').contains('Delete').click();
+
+ cy.get('.euiTextAlign').contains('No notebooks').should('exist');
+
+ // keep a notebook for testing
+ cy.get('.euiButton__text').contains('Create notebook').click();
+ cy.wait(delay);
+ cy.get('input.euiFieldText').type(TEST_NOTEBOOK);
+ cy.get('.euiButton__text')
+ .contains(/^Create$/)
+ .click();
+ cy.wait(delay * 2);
+ });
+});
+
+describe('Test reporting integration if plugin installed', () => {
+ beforeEach(() => {
+ cy.visit(`${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/notebooks`);
+ cy.get('.euiTableCellContent').contains(TEST_NOTEBOOK).click();
+ cy.wait(delay * 3);
+ cy.get('body').then(($body) => {
+ skipOn($body.find('#reportingActionsButton').length <= 0);
+ });
+ });
+
+ it('Create in-context PDF report from notebook', () => {
+ cy.get('#reportingActionsButton').click();
+ cy.wait(delay);
+ cy.get('button.euiContextMenuItem:nth-child(1)').contains('Download PDF').click();
+ cy.get('#downloadInProgressLoadingModal').should('exist');
+ });
+
+ it('Create in-context PNG report from notebook', () => {
+ cy.get('#reportingActionsButton').click();
+ cy.wait(delay);
+ cy.get('button.euiContextMenuItem:nth-child(2)').contains('Download PNG').click();
+ cy.get('#downloadInProgressLoadingModal').should('exist');
+ });
+
+ it('Create on-demand report definition from context menu', () => {
+ cy.get('#reportingActionsButton').click();
+ cy.wait(delay);
+ cy.get('button.euiContextMenuItem:nth-child(3)').contains('Create report definition').click();
+ cy.wait(delay);
+ cy.location('pathname', { timeout: 60000 }).should('include', '/reports-dashboards');
+ cy.wait(delay);
+ cy.get('#reportSettingsName').type('Create notebook on-demand report');
+ cy.get('#createNewReportDefinition').click({ force: true });
+ });
+
+ it('View reports homepage from context menu', () => {
+ cy.get('#reportingActionsButton').click();
+ cy.wait(delay);
+ cy.get('button.euiContextMenuItem:nth-child(4)').contains('View reports').click();
+ cy.wait(delay);
+ cy.location('pathname', { timeout: 60000 }).should('include', '/reports-dashboards');
+ });
+});
+
+describe('Testing paragraphs', () => {
+ beforeEach(() => {
+ cy.visit(`${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/notebooks`);
+ cy.get('.euiTableCellContent').contains(TEST_NOTEBOOK).click();
+ });
+
+ it('Goes into a notebook and creates paragraphs', () => {
+ cy.get('.euiButton__text').contains('Add').click();
+ cy.wait(delay);
+
+ cy.get('.euiTextArea').should('exist');
+
+ cy.get('.euiButton__text').contains('Run').click();
+ cy.wait(delay);
+ cy.get('.euiTextColor').contains('Input is required.').should('exist');
+ cy.get('.euiTextArea').clear();
+ cy.get('.euiTextArea').type(MARKDOWN_TEXT);
+ cy.wait(delay);
+
+ cy.get('.euiButton__text').contains('Run').click();
+ cy.wait(delay);
+ });
+
+ it('Has working breadcrumbs', () => {
+ cy.get('.euiBreadcrumb').contains(TEST_NOTEBOOK).click();
+ cy.wait(delay);
+ cy.get('.euiTitle').contains(TEST_NOTEBOOK).should('exist');
+ cy.get('.euiBreadcrumb').contains('Notebooks').click();
+ cy.wait(delay);
+ cy.get('.euiTitle').contains('Notebooks').should('exist');
+ cy.get('.euiBreadcrumb').contains('Observability').click();
+ cy.wait(delay);
+ cy.get('.euiTitle').contains('Event analytics').should('exist');
+ });
+
+ it('Renders markdown', () => {
+ cy.get('.euiTextArea').should('not.exist');
+ cy.get(`a[href="${SAMPLE_URL}"]`).should('exist');
+ cy.get('code').contains('POST').should('exist');
+ cy.get('td').contains('b2').should('exist');
+ });
+
+ it('Shows output message', () => {
+ cy.get('button[aria-label="Toggle show input"]').click();
+ cy.wait(delay);
+ cy.get('.euiTextColor').contains('Last successful run').should('exist');
+
+ cy.get('pre.input').eq(0).click();
+ cy.wait(delay);
+ cy.get('.euiTextArea').type('Another text');
+ cy.wait(delay);
+
+ cy.get('.euiTextColor').contains('Last successful run').should('exist');
+ });
+
+ it('Renders input only mode', () => {
+ cy.get('.euiToggle__input[title="Input only"]').click();
+ cy.wait(delay);
+
+ cy.get('div.markdown-body').should('not.exist');
+ cy.get('.euiLink').contains('View both').should('exist');
+ cy.get('.euiLink').contains('View both').click();
+ cy.wait(delay);
+
+ cy.get('code').contains('POST').should('exist');
+ cy.get('.euiLink').contains('View both').should('not.exist');
+ });
+
+ it('Renders output only mode', () => {
+ cy.get('.euiToggle__input[title="Output only"]').click();
+ cy.wait(delay);
+
+ cy.get('button[aria-label="Open paragraph menu"]').should('not.exist');
+ cy.get('button[aria-label="Toggle show input"]').should('not.exist');
+ cy.get('code').contains('POST').should('exist');
+ });
+
+ it('Duplicates paragraphs', () => {
+ cy.get('.euiButtonIcon[aria-label="Open paragraph menu"]').eq(0).click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Duplicate').eq(0).click();
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Run').click();
+ cy.wait(delay);
+
+ cy.get(`a[href="${SAMPLE_URL}"]`).should('have.length.gte', 2);
+ });
+
+ it('Adds a dashboards visualization paragraph', () => {
+ cy.contains('Add paragraph').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Visualization').click();
+ cy.wait(delay);
+
+ cy.get('.euiButton__text').contains('Run').click();
+ cy.wait(delay);
+ cy.get('.euiTextColor').contains('Visualization is required.').should('exist');
+
+ cy.get('.euiButton__text').contains('Browse').click();
+ cy.wait(delay);
+ cy.get('.euiFieldSearch').focus().type('[Flights] Flight Count and Average Ticket Price{enter}');
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Select').click();
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Run').click();
+ cy.wait(delay);
+ cy.get('div.visualization').should('exist');
+ });
+
+ it('Adds a SQL query paragraph', () => {
+ cy.contains('Add paragraph').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Code block').click();
+ cy.wait(delay);
+
+ cy.get('.euiTextArea').type(SQL_QUERY_TEXT);
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Run').click();
+ cy.wait(delay * 5);
+
+ cy.get('b').contains('select * from opensearch_dashboards_sample_data_flights limit 20');
+
+ cy.get('.euiDataGrid__overflow').should('exist');
+ });
+
+ it('Adds an observability visualization paragraph', () => {
+ cy.contains('Add paragraph').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Visualization').click();
+ cy.wait(delay);
+
+ cy.get('.euiButton__text').contains('Run').click();
+ cy.wait(delay);
+ cy.get('.euiTextColor').contains('Visualization is required.').should('exist');
+
+ cy.get('.euiButton__text').contains('Browse').click();
+ cy.wait(delay);
+ cy.get('.euiFieldSearch').focus().type('[Logs] Count total requests by tags{enter}');
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Select').click();
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Run').click();
+ cy.wait(delay);
+ cy.get('h5').contains('[Logs] Count total requests by tags').should('exist');
+ });
+
+ it('Adds a PPL query paragraph', () => {
+ cy.contains('Add paragraph').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Code block').click();
+ cy.wait(delay);
+
+ cy.get('.euiTextArea').type(PPL_QUERY_TEXT);
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Run').click();
+ cy.wait(delay * 5);
+
+ cy.get('b').contains('source=opensearch_dashboards_sample_data_flights');
+
+ cy.get('.euiDataGrid__overflow').should('exist');
+ });
+
+ it('Clears outputs', () => {
+ cy.wait(delay * 3); // need to wait for paragraphs to load first
+ cy.get('[data-test-subj="notebook-paragraph-actions-button"]').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Clear all outputs').click();
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Clear').click();
+ cy.wait(delay);
+
+ cy.get(`a[href="${SAMPLE_URL}"]`).should('not.exist');
+ });
+
+ it('Runs all paragraphs', () => {
+ cy.wait(delay * 3); // need to wait for paragraphs to load first
+ cy.get('[data-test-subj="notebook-paragraph-actions-button"]').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Run all paragraphs').click();
+ cy.wait(delay);
+
+ cy.get(`a[href="${SAMPLE_URL}"]`).should('exist');
+ });
+
+ it('Adds paragraph to top and bottom', () => {
+ cy.wait(delay * 3); // need to wait for paragraphs to load first
+ cy.get('[data-test-subj="notebook-paragraph-actions-button"]').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Add paragraph to top').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Code block').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="notebook-paragraph-actions-button"]').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Add paragraph to bottom').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Code block').click();
+ cy.wait(delay);
+
+ cy.get('.euiText').contains('[4] Visualization').should('exist');
+ cy.get('.euiText').contains('[5] Code block').should('exist');
+ });
+
+ it('Moves paragraphs', () => {
+ cy.get('.euiButtonIcon[aria-label="Open paragraph menu"').eq(0).click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem-isDisabled').should('have.length.gte', 2);
+ cy.get('.euiContextMenuItem__text').contains('Move to bottom').click();
+ cy.wait(delay);
+
+ cy.get('.euiText').contains('[3] Visualization').should('exist');
+ });
+
+ it('Duplicates and renames the notebook', () => {
+ cy.get('[data-test-subj="notebook-notebook-actions-button"]').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Duplicate notebook').click();
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Duplicate').click();
+ cy.wait(delay * 3);
+
+ cy.get('[data-test-subj="notebook-notebook-actions-button"]').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Rename notebook').click();
+ cy.wait(delay);
+ cy.get('input.euiFieldText[data-autofocus="true"]').type(' (rename)');
+ cy.wait(delay);
+ cy.get('.euiButton__text').last().contains('Rename').click();
+ cy.wait(delay);
+ cy.reload();
+ cy.wait(delay * 3);
+
+ cy.get('.euiTitle')
+ .contains(TEST_NOTEBOOK + ' (copy) (rename)')
+ .should('exist');
+ cy.get(`a[href="${SAMPLE_URL}"]`).should('have.length.gte', 2);
+ });
+
+ it('Deletes paragraphs', () => {
+ cy.wait(delay * 3);
+ cy.get('[data-test-subj="notebook-paragraph-actions-button"]').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Delete all paragraphs').click();
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Delete').click();
+ cy.wait(delay);
+
+ cy.get('.euiTextAlign').contains('No paragraphs').should('exist');
+ });
+
+ it('Deletes notebook', () => {
+ cy.get('[data-test-subj="notebook-notebook-actions-button"]').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Delete notebook').click();
+ cy.wait(delay);
+
+ cy.get('button.euiButton--danger').should('be.disabled');
+
+ cy.get('input.euiFieldText[placeholder="delete"]').type('delete');
+ cy.get('button.euiButton--danger').should('not.be.disabled');
+ cy.get('.euiButton__text').contains('Delete').click();
+ cy.wait(delay * 3);
+
+ cy.get('.euiButton__text').contains('Create notebook').should('exist');
+ });
+
+ it('Cleans up test notebooks', () => {
+ cy.get('[data-test-subj="notebook-notebook-actions-button"]').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Delete notebook').click();
+ cy.wait(delay);
+
+ cy.get('button.euiButton--danger').should('be.disabled');
+
+ cy.get('input.euiFieldText[placeholder="delete"]').type('delete');
+ cy.get('button.euiButton--danger').should('not.be.disabled');
+ cy.get('.euiButton__text').contains('Delete').click();
+ cy.wait(delay * 3);
+
+ cy.get('.euiText').contains('No notebooks').should('exist');
+ });
+});
diff --git a/.cypress/integration/3_panels.spec.js b/.cypress/integration/3_panels.spec.js
new file mode 100644
index 0000000000..1c3ed1cb6b
--- /dev/null
+++ b/.cypress/integration/3_panels.spec.js
@@ -0,0 +1,493 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+///
+
+import {
+ delay,
+ TEST_PANEL,
+ PPL_VISUALIZATIONS,
+ PPL_VISUALIZATIONS_NAMES,
+ NEW_VISUALIZATION_NAME,
+ PPL_FILTER,
+ SAMPLE_PANEL,
+ SAMPLE_VISUALIZATIONS_NAMES,
+} from '../utils/panel_constants';
+
+import { supressResizeObserverIssue } from '../utils/constants';
+
+const moveToEventsHome = () => {
+ cy.visit(`${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/event_analytics/`);
+ cy.wait(delay * 3);
+};
+
+const moveToPanelHome = () => {
+ cy.visit(
+ `${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/operational_panels/`
+ );
+ cy.wait(delay * 3);
+};
+
+const moveToTestPanel = () => {
+ moveToPanelHome();
+ cy.get('.euiTableCellContent').contains(TEST_PANEL).click();
+ cy.wait(delay * 3);
+ cy.get('h1').contains(TEST_PANEL).should('exist');
+ cy.wait(delay);
+};
+
+describe('Adding sample data and visualization', () => {
+ it('Adds sample flights data for visualization paragraph', () => {
+ cy.visit(`${Cypress.env('opensearchDashboards')}/app/home#/tutorial_directory/sampleData`);
+ cy.get('div[data-test-subj="sampleDataSetCardflights"]')
+ .contains(/(Add|View) data/)
+ .click();
+ cy.wait(delay * 3);
+ });
+});
+
+describe('Creating visualizations', () => {
+ beforeEach(() => {
+ moveToEventsHome();
+ });
+
+ it('Create first visualization in event analytics', () => {
+ cy.get('[id^=autocomplete-textarea]').type(PPL_VISUALIZATIONS[0]);
+ cy.get('.euiButton__text').contains('Refresh').click();
+ cy.wait(delay);
+ supressResizeObserverIssue();
+ cy.get('button[id="main-content-vis"]').contains('Visualizations').click();
+ cy.wait(delay * 2);
+ cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click();
+ cy.wait(delay * 2);
+ cy.get('[data-test-subj="eventExplorer__querySaveName"]').type(PPL_VISUALIZATIONS_NAMES[0]);
+ cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click();
+ cy.wait(delay);
+ cy.get('.euiToastHeader__title').contains('successfully').should('exist');
+ });
+
+ it('Create second visualization in event analytics', () => {
+ cy.get('[id^=autocomplete-textarea]').type(PPL_VISUALIZATIONS[1]);
+ cy.get('.euiButton__text').contains('Refresh').click();
+ cy.wait(delay);
+ supressResizeObserverIssue();
+ cy.get('button[id="main-content-vis"]').contains('Visualizations').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="eventExplorer__querySaveName"]').type(PPL_VISUALIZATIONS_NAMES[1]);
+ cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click();
+ cy.wait(delay);
+ cy.get('.euiToastHeader__title').contains('successfully').should('exist');
+ });
+});
+
+describe('Testing panels table', () => {
+ beforeEach(() => {
+ moveToPanelHome();
+ });
+
+ it('Displays error toast for invalid panel name', () => {
+ cy.get('.euiButton__text').contains('Create panel').click();
+ cy.wait(delay);
+ cy.get('.euiButton__text')
+ .contains(/^Create$/)
+ .click();
+ cy.wait(delay);
+
+ cy.get('.euiToastHeader__title').contains('Invalid Operational Panel name').should('exist');
+ });
+
+ it('Creates a panel and redirects to the panel', () => {
+ cy.get('.euiButton__text').contains('Create panel').click();
+ cy.wait(delay);
+ cy.get('input.euiFieldText').type(TEST_PANEL);
+ cy.get('.euiButton__text')
+ .contains(/^Create$/)
+ .click();
+ cy.wait(delay);
+
+ cy.contains(TEST_PANEL).should('exist');
+ });
+
+ it('Duplicates and renames a panel', () => {
+ cy.get('.euiCheckbox__input[title="Select this row"]').eq(0).click();
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Actions').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Duplicate').click();
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Duplicate').click();
+ cy.wait(delay);
+
+ cy.get('.euiCheckbox__input[title="Select this row"]').eq(1).click();
+ cy.wait(delay);
+ cy.get('.euiCheckbox__input[title="Select this row"]').eq(0).click();
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Actions').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Rename').click();
+ cy.wait(delay);
+ cy.get('input.euiFieldText').type(' (rename)');
+ cy.get('.euiButton__text').contains('Rename').click();
+ cy.wait(delay);
+ });
+
+ it('Searches existing panel', () => {
+ cy.get('input.euiFieldSearch').type('this panel should not exist');
+ cy.wait(delay);
+
+ cy.get('.euiTableCellContent__text').contains('No items found').should('exist');
+
+ cy.get('.euiFormControlLayoutClearButton').click();
+ cy.wait(delay);
+ cy.get('input.euiFieldSearch').type(TEST_PANEL + ' (copy) (rename)');
+ cy.wait(delay);
+
+ cy.get('a.euiLink')
+ .contains(TEST_PANEL + ' (copy) (rename)')
+ .should('exist');
+ });
+
+ it('Deletes panels', () => {
+ cy.get('.euiCheckbox__input[data-test-subj="checkboxSelectAll"]').click();
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Actions').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Delete').click();
+ cy.wait(delay);
+
+ cy.get('button.euiButton--danger').should('be.disabled');
+
+ cy.get('input.euiFieldText[placeholder="delete"]').type('delete');
+ cy.get('button.euiButton--danger').should('not.be.disabled');
+ cy.get('.euiButton__text').contains('Delete').click();
+
+ cy.get('.euiTextAlign').contains('No Operational Panels').should('exist');
+
+ // keep a panel for testing
+ cy.get('.euiButton__text').contains('Create panel').click();
+ cy.wait(delay);
+ cy.get('input.euiFieldText').type(TEST_PANEL);
+ cy.get('.euiButton__text')
+ .contains(/^Create$/)
+ .click();
+ cy.wait(delay * 2);
+ });
+});
+
+describe('Testing a panel', () => {
+ it('Move to test panel', () => {
+ moveToTestPanel();
+ });
+
+ it('Opens visualization flyout from empty panel', () => {
+ cy.get('.euiButton').eq(4).contains('Add visualization').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Select existing visualization').click();
+ cy.wait(delay);
+ cy.get('.euiButton').contains('Cancel').click();
+ cy.get('.euiButton').eq(2).contains('Add visualization').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Select existing visualization').click();
+ cy.wait(delay);
+ cy.get('.euiButton').contains('Cancel').click();
+ cy.get('.euiButton').contains('Add visualization').first().click();
+ cy.get('.euiContextMenuItem__text').contains('Create new visualization').click();
+ cy.wait(delay);
+ cy.get('.euiBreadcrumb').contains('Explorer').should('exist');
+ cy.get('.euiCallOut').contains('No results match your search criteria').should('exist');
+ });
+
+ it('Redirects to correct page on breadcrumb click', () => {
+ moveToTestPanel();
+ cy.get('.euiBreadcrumb').contains(TEST_PANEL).click();
+ cy.wait(delay);
+ cy.get('.euiTitle').contains(TEST_PANEL).should('exist');
+ cy.get('.euiBreadcrumb').contains('Operational panels').click();
+ cy.wait(delay);
+ cy.get('.euiTitle').contains('Operational panels').should('exist');
+ cy.get('.euiBreadcrumb').contains('Observability').click();
+ cy.wait(delay);
+ cy.get('.euiTitle').contains('Event analytics').should('exist');
+ });
+
+ it('Duplicate the open panel', () => {
+ moveToTestPanel();
+ cy.get('.euiButton__text').contains('Panel actions').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Duplicate panel').click();
+ cy.wait(delay);
+ cy.get(`input.euiFieldText[value="${TEST_PANEL} (copy)"]`).should('exist');
+ cy.get('.euiButton__text').contains('Duplicate').click();
+ cy.wait(delay * 3);
+ cy.get('.euiToastHeader__title').contains('successfully').should('exist');
+ cy.get('h1')
+ .contains(TEST_PANEL + ' (copy)')
+ .should('exist');
+ cy.wait(delay);
+ });
+
+ it('Rename the open panel', () => {
+ cy.get('.euiButton__text').contains('Panel actions').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Rename panel').click();
+ cy.wait(delay);
+ cy.get(`input.euiFieldText[value="${TEST_PANEL} (copy)"]`)
+ .focus()
+ .clear()
+ .type('Renamed Panel');
+ cy.get('.euiButton__text').contains('Rename').click();
+ cy.wait(delay * 3);
+ cy.get('.euiToastHeader__title').contains('successfully').should('exist');
+ cy.get('h1').contains('Renamed Panel').should('exist');
+ cy.wait(delay);
+ });
+
+ it('Change date filter of the panel', () => {
+ moveToTestPanel();
+ cy.get('.euiButtonEmpty[data-test-subj="superDatePickerToggleQuickMenuButton"]').click();
+ cy.get('.euiLink').contains('This year').click();
+ cy.wait(delay * 2);
+ cy.get('.euiSuperDatePicker__prettyFormat[data-test-subj="superDatePickerShowDatesButton"]')
+ .contains('This year')
+ .should('exist');
+ cy.wait(delay);
+ });
+
+ it('Add existing visualization #1', () => {
+ cy.get('.euiButton__text').contains('Add visualization').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Select existing visualization').click();
+ cy.wait(delay);
+ cy.get('select').select(PPL_VISUALIZATIONS_NAMES[0]);
+ cy.get('button[aria-label="refreshPreview"]').click();
+ cy.wait(delay * 2);
+ cy.get('.plot-container').should('exist');
+ cy.get('.euiButton__text').contains(new RegExp('^Add$', 'g')).click();
+ cy.wait(delay);
+ cy.get('.euiToastHeader__title').contains('successfully').should('exist');
+ });
+
+ it('Add existing visualization #2', () => {
+ cy.get('.euiButton__text').contains('Add visualization').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Select existing visualization').click();
+ cy.wait(delay);
+ cy.get('select').select(PPL_VISUALIZATIONS_NAMES[1]);
+ cy.get('button[aria-label="refreshPreview"]').click();
+ cy.wait(delay * 2);
+ cy.get('.plot-container').should('exist');
+ cy.get('.euiButton__text').contains(new RegExp('^Add$', 'g')).click();
+ cy.wait(delay);
+ cy.get('.euiToastHeader__title').contains('successfully').should('exist');
+ });
+
+ it('Add ppl filter to panel', () => {
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]')
+ .click()
+ .wait(1500)
+ .type("where Carrier = 'OpenSearch-Air'| where Dest = 'Munich Airport'", {delay: 500});
+ cy.get('.euiButton__text').contains('Refresh').click();
+ cy.wait(delay * 3);
+ cy.get('.xtick').should('contain', 'OpenSearch-Air');
+ cy.get('.xtick').should('contain', 'Munich Airport');
+ cy.get('.xtick').contains('Zurich Airport').should('not.exist');
+ cy.get('.xtick').contains('BeatsWest').should('not.exist');
+ cy.get('.xtick').contains('Logstash Airways').should('not.exist');
+ cy.get('.xtick').contains('OpenSearch Dashboards Airlines').should('not.exist');
+ cy.wait(delay);
+ });
+
+ it('Drag and drop a visualization', () => {
+ cy.get('.euiButton__text').contains('Edit').click();
+ cy.wait(delay);
+ cy.get('h5')
+ .contains(PPL_VISUALIZATIONS_NAMES[1])
+ .trigger('mousedown', { which: 1 })
+ .trigger('mousemove', { clientX: 1100, clientY: 0 })
+ .trigger('mouseup', { force: true });
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Save').click();
+ cy.wait(delay * 3);
+ cy.get('div.react-grid-layout>div')
+ .eq(1)
+ .invoke('attr', 'style')
+ .should('match', new RegExp('(.*)transform: translate((.*)10px)(.*)'));
+ cy.wait(delay);
+ });
+
+ it('Resize a visualization', () => {
+ cy.get('.euiButton__text').contains('Edit').click();
+ cy.wait(delay);
+ cy.get('.react-resizable-handle')
+ .eq(1)
+ .trigger('mousedown', { which: 1 })
+ .trigger('mousemove', { clientX: 2000, clientY: 800 })
+ .trigger('mouseup', { force: true });
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Save').click();
+ cy.wait(delay * 3);
+ cy.get('div.react-grid-layout>div').eq(1).invoke('height').should('match', new RegExp('470'));
+ cy.wait(delay);
+ });
+
+ it('Delete a visualization', () => {
+ cy.get('h5').contains(PPL_VISUALIZATIONS_NAMES[1]).should('exist');
+ cy.get('.euiButton__text').contains('Edit').click();
+ cy.wait(delay);
+ cy.get('.visualization-action-button').eq(1).click();
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Save').click();
+ cy.wait(delay * 3);
+ cy.get('h5').contains(PPL_VISUALIZATIONS_NAMES[1]).should('not.exist');
+ cy.wait(delay);
+ });
+
+ it('Duplicate a visualization', () => {
+ cy.get('h5').contains(PPL_VISUALIZATIONS_NAMES[0]).should('exist');
+ cy.get('button[aria-label="actionMenuButton"]').click();
+ cy.get('.euiContextMenu__itemLayout > .euiContextMenuItem__text').contains('Duplicate').click();
+ cy.wait(delay * 2);
+ cy.get('.euiToastHeader__title').contains('successfully').should('exist');
+ cy.wait(delay);
+ cy.get('h5').eq(0).contains(PPL_VISUALIZATIONS_NAMES[0]).should('exist');
+ cy.get('h5').eq(1).contains(PPL_VISUALIZATIONS_NAMES[0]).should('exist');
+ cy.wait(delay);
+ });
+
+ it('Replace a visualization', () => {
+ cy.get('.visualization-action-button').eq(1).click();
+ cy.get('.euiContextMenu__itemLayout > .euiContextMenuItem__text').contains('Replace').click();
+ cy.get('select').select(PPL_VISUALIZATIONS_NAMES[1]);
+ cy.get('button[aria-label="refreshPreview"]').click();
+ cy.wait(delay * 3);
+ cy.get('.plot-container').should('exist');
+ cy.get('.euiButton__text').contains(new RegExp('^Add$', 'g')).click();
+ cy.wait(delay);
+ cy.get('.euiToastHeader__title').contains('successfully').should('exist');
+ cy.wait(delay);
+ cy.get('h5').eq(0).contains(PPL_VISUALIZATIONS_NAMES[0]).should('exist');
+ cy.get('h5').eq(1).contains(PPL_VISUALIZATIONS_NAMES[1]).should('exist');
+ cy.wait(delay);
+ });
+
+ it('Create new visualization and add to panel', () => {
+ cy.get('.euiButton__text').contains('Add visualization').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Create new visualization').click();
+ cy.wait(delay * 3);
+ cy.url().should('match', new RegExp('(.*)#/event_analytics/explorer'));
+ cy.get('[id^=autocomplete-textarea]').type(PPL_VISUALIZATIONS[2]);
+ cy.get('.euiButton__text').contains('Refresh').click();
+
+ supressResizeObserverIssue();
+ cy.get('button[id="main-content-vis"]').contains('Visualizations').click();
+ cy.wait(delay * 2);
+ cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click();
+ cy.get('[data-test-subj="eventExplorer__querySaveComboBox"]').type(TEST_PANEL);
+ cy.get(`input[value="${TEST_PANEL}"]`).click();
+ cy.get('[data-test-subj="eventExplorer__querySaveName"]').type(PPL_VISUALIZATIONS_NAMES[2]);
+ cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click();
+ cy.wait(delay);
+ cy.get('.euiToastHeader__title').contains('successfully').should('exist');
+ moveToTestPanel();
+ cy.get('h5').contains(PPL_VISUALIZATIONS_NAMES[0]).should('exist');
+ cy.get('h5').contains(PPL_VISUALIZATIONS_NAMES[1]).should('exist');
+ cy.get('h5').contains(PPL_VISUALIZATIONS_NAMES[2]).should('exist');
+ });
+
+ it('Move to test panel and check visualization edit button', () => {
+ moveToTestPanel();
+ cy.get('h5').contains(PPL_VISUALIZATIONS_NAMES[0]).should('exist');
+ cy.get('button[aria-label="actionMenuButton"]').eq(0).click();
+ supressResizeObserverIssue();
+ cy.get('.euiContextMenu__itemLayout > .euiContextMenuItem__text').contains('Edit').click();
+ cy.wait(delay * 3);
+ cy.url().should('match', new RegExp('(.*)#/event_analytics/explorer'));
+ cy.wait(delay);
+ cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="eventExplorer__querySaveName"]')
+ .focus()
+ .clear()
+ .type(NEW_VISUALIZATION_NAME);
+ cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click();
+ cy.wait(delay);
+ cy.get('.euiToastHeader__title').contains('successfully').should('exist');
+ moveToTestPanel();
+ cy.get('h5').contains(NEW_VISUALIZATION_NAME).should('exist');
+ cy.get('h5').contains(PPL_VISUALIZATIONS_NAMES[1]).should('exist');
+ cy.get('h5').contains(PPL_VISUALIZATIONS_NAMES[2]).should('exist');
+ });
+});
+
+describe('Add samples and clean up all test data', () => {
+ it('Add sample data', () => {
+ moveToPanelHome();
+ cy.get('.euiButton__text').contains('Actions').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Add samples').click();
+ cy.wait(delay);
+ cy.get('.euiModalHeader__title[data-test-subj="confirmModalTitleText"]')
+ .contains('Add samples')
+ .should('exist');
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Yes').click();
+ cy.wait(delay * 5);
+ cy.get('.euiTableCellContent').contains(SAMPLE_PANEL).should('exist');
+ cy.wait(delay);
+ });
+
+ it('Validate sample data', () => {
+ moveToPanelHome();
+ cy.get('.euiTableCellContent').contains(SAMPLE_PANEL).click();
+ cy.wait(delay * 3);
+ cy.get('h1').contains(SAMPLE_PANEL).should('exist');
+ cy.wait(delay);
+ SAMPLE_VISUALIZATIONS_NAMES.forEach((vizName) =>
+ cy.get('h5').contains(vizName).should('exist')
+ );
+ cy.wait(delay);
+ });
+
+ it('Delete visualizations from event analytics', () => {
+ moveToEventsHome();
+ cy.get('[data-test-subj="tablePaginationPopoverButton"]').click();
+ cy.get('.euiContextMenuItem__text').contains('50 rows').click();
+ cy.get('.euiCheckbox__input[data-test-subj="checkboxSelectAll"]').click();
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Actions').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Delete').click();
+ cy.wait(delay);
+
+ cy.get('button.euiButton--danger').should('be.disabled');
+
+ cy.get('input.euiFieldText[placeholder="delete"]').type('delete');
+ cy.get('button.euiButton--danger').should('not.be.disabled');
+ cy.get('.euiButton__text').contains('Delete').click();
+ cy.wait(delay);
+ cy.get('.euiTextAlign').contains('No Queries or Visualizations').should('exist');
+ });
+
+ it('Deletes test panel', () => {
+ moveToPanelHome();
+ cy.get('.euiCheckbox__input[data-test-subj="checkboxSelectAll"]').click();
+ cy.wait(delay);
+ cy.get('.euiButton__text').contains('Actions').click();
+ cy.wait(delay);
+ cy.get('.euiContextMenuItem__text').contains('Delete').click();
+ cy.wait(delay);
+
+ cy.get('button.euiButton--danger').should('be.disabled');
+
+ cy.get('input.euiFieldText[placeholder="delete"]').type('delete');
+ cy.get('button.euiButton--danger').should('not.be.disabled');
+ cy.get('.euiButton__text').contains('Delete').click();
+
+ cy.get('.euiTextAlign').contains('No Operational Panels').should('exist');
+ });
+});
diff --git a/.cypress/integration/4_trace_analytics_dashboard.spec.js b/.cypress/integration/4_trace_analytics_dashboard.spec.js
new file mode 100644
index 0000000000..5512635cac
--- /dev/null
+++ b/.cypress/integration/4_trace_analytics_dashboard.spec.js
@@ -0,0 +1,188 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+///
+
+import { testDataSet, delay, setTimeFilter } from '../utils/constants';
+
+describe('Dump test data', () => {
+ it('Indexes test data', () => {
+ const dumpDataSet = (mapping_url, data_url, index) => {
+ cy.request({
+ method: 'POST',
+ failOnStatusCode: false,
+ url: 'api/console/proxy',
+ headers: {
+ 'content-type': 'application/json;charset=UTF-8',
+ 'osd-xsrf': true,
+ },
+ qs: {
+ path: `${index}`,
+ method: 'PUT',
+ },
+ });
+
+ cy.request(mapping_url).then((response) => {
+ cy.request({
+ method: 'POST',
+ form: true,
+ url: 'api/console/proxy',
+ headers: {
+ 'content-type': 'application/json;charset=UTF-8',
+ 'osd-xsrf': true,
+ },
+ qs: {
+ path: `${index}/_mapping`,
+ method: 'POST',
+ },
+ body: response.body,
+ });
+ });
+
+ cy.request(data_url).then((response) => {
+ cy.request({
+ method: 'POST',
+ form: true,
+ url: 'api/console/proxy',
+ headers: {
+ 'content-type': 'application/json;charset=UTF-8',
+ 'osd-xsrf': true,
+ },
+ qs: {
+ path: `${index}/_bulk`,
+ method: 'POST',
+ },
+ body: response.body,
+ });
+ });
+ };
+
+ testDataSet.forEach(({ mapping_url, data_url, index }) =>
+ dumpDataSet(mapping_url, data_url, index)
+ );
+ });
+});
+
+describe('Testing dashboard table empty state', () => {
+ beforeEach(() => {
+ cy.visit('app/observability-dashboards#/trace_analytics/home', {
+ onBeforeLoad: (win) => {
+ win.sessionStorage.clear();
+ },
+ });
+ cy.wait(delay * 3);
+ });
+
+ it('Renders empty state', () => {
+ cy.contains(' (0)').should('exist');
+ cy.get('h2.euiTitle').contains('No matches').should('exist');
+ });
+});
+
+describe('Testing dashboard table', () => {
+ beforeEach(() => {
+ cy.visit('app/observability-dashboards#/trace_analytics/home', {
+ onBeforeLoad: (win) => {
+ win.sessionStorage.clear();
+ },
+ });
+ setTimeFilter();
+ });
+
+ it('Renders the dashboard table', () => {
+ cy.contains(' (10)').should('exist');
+ cy.contains('client_cancel_order').should('exist');
+ cy.contains('166.44').should('exist');
+ cy.contains('7.14%').should('exist');
+ });
+
+ it('Has working breadcrumbs', () => {
+ cy.get('.euiBreadcrumb').contains('Dashboard').click();
+ cy.wait(delay);
+ cy.get('.euiTitle').contains('Dashboard').should('exist');
+ cy.get('.euiBreadcrumb').contains('Trace analytics').click();
+ cy.wait(delay);
+ cy.get('.euiTitle').contains('Dashboard').should('exist');
+ cy.get('.euiBreadcrumb').contains('Observability').click();
+ cy.wait(delay);
+ cy.get('.euiTitle').contains('Event analytics').should('exist');
+ });
+
+ it('Adds the percentile filters', () => {
+ cy.contains(' >= 95 percentile').click({ force: true });
+ cy.wait(delay);
+ cy.contains(' >= 95 percentile').click({ force: true });
+ cy.wait(delay);
+
+ cy.contains('Latency percentile within trace group: >= 95th').should('exist');
+ cy.contains(' (7)').should('exist');
+ cy.contains('318.69').should('exist');
+
+ cy.contains(' < 95 percentile').click({ force: true });
+ cy.wait(delay);
+ cy.contains(' < 95 percentile').click({ force: true });
+ cy.wait(delay);
+
+ cy.contains('Latency percentile within trace group: < 95th').should('exist');
+ cy.contains(' (8)').should('exist');
+ cy.contains('383.05').should('exist');
+ });
+
+ it('Opens latency trend popover', () => {
+ setTimeFilter(true);
+ cy.get('.euiButtonIcon[aria-label="Open popover"]').first().click();
+ cy.get('text.ytitle[data-unformatted="Hourly latency (ms)"]').should('exist');
+ });
+
+ it('Redirects to traces table with filter', () => {
+ cy.wait(delay * 5);
+ cy.get('.euiLink').contains('13').click();
+ cy.wait(delay);
+
+ cy.get('h2.euiTitle').contains('Traces').should('exist');
+ cy.contains(' (13)').should('exist');
+ cy.contains('client_create_order').should('exist');
+
+ cy.get('.euiSideNavItemButton__label').contains('Trace analytics').click();
+ cy.wait(delay);
+
+ cy.contains('client_create_order').should('exist');
+ });
+});
+
+describe('Testing plots', () => {
+ beforeEach(() => {
+ cy.visit('app/observability-dashboards#/trace_analytics/home', {
+ onBeforeLoad: (win) => {
+ win.sessionStorage.clear();
+ },
+ });
+ setTimeFilter();
+ });
+
+ it('Renders service map', () => {
+ cy.get('text.ytitle[data-unformatted="Latency (ms)"]').should('exist');
+ cy.get('text[data-unformatted="200"]').should('exist');
+ cy.get('.vis-network').should('exist');
+
+ cy.get('.euiToggle__input[title="Error rate"]').click();
+ cy.get('text.ytitle[data-unformatted="Error rate"]').should('exist');
+ cy.get('text[data-unformatted="10%"]').should('exist');
+
+ cy.get('.euiToggle__input[title="Throughput"]').click();
+ cy.get('text.ytitle[data-unformatted="Throughput"]').should('exist');
+ cy.get('text[data-unformatted="60"]').should('exist');
+
+ cy.get('input[type="search"]').eq(1).focus().type('payment{enter}');
+ cy.wait(delay);
+ });
+
+ it('Renders plots', () => {
+ cy.get('text.ytitle[data-unformatted="Error rate (%)"]').should('exist');
+ cy.get('text.annotation-text[data-unformatted="Now: 0%"]').should('exist');
+ cy.get('text.ytitle[data-unformatted="Throughput (n)"]').should('exist');
+ cy.get('text.annotation-text[data-unformatted="Now: 62"]').should('exist');
+ });
+});
diff --git a/.cypress/integration/5_trace_analytics_services.spec.js b/.cypress/integration/5_trace_analytics_services.spec.js
new file mode 100644
index 0000000000..638eac65f6
--- /dev/null
+++ b/.cypress/integration/5_trace_analytics_services.spec.js
@@ -0,0 +1,124 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+///
+
+import { delay, SERVICE_NAME, setTimeFilter } from '../utils/constants';
+
+describe('Testing services table empty state', () => {
+ beforeEach(() => {
+ cy.visit('app/observability-dashboards#/trace_analytics/services', {
+ onBeforeLoad: (win) => {
+ win.sessionStorage.clear();
+ },
+ });
+ cy.wait(delay * 3);
+ });
+
+ it('Renders empty state', () => {
+ cy.contains(' (0)').should('exist');
+ cy.get('h2.euiTitle').contains('No matches').should('exist');
+ });
+});
+
+describe('Testing services table', () => {
+ beforeEach(() => {
+ cy.visit('app/observability-dashboards#/trace_analytics/services', {
+ onBeforeLoad: (win) => {
+ win.sessionStorage.clear();
+ },
+ });
+ setTimeFilter();
+ });
+
+ it('Renders the services table', () => {
+ cy.contains(' (8)').should('exist');
+ cy.contains('analytics-service, frontend-client, recommendation').should('exist');
+ cy.contains('186.95').should('exist');
+ cy.contains('14.29%').should('exist');
+ });
+
+ it('Searches correctly', () => {
+ cy.get('input[type="search"]').first().focus().type(`${SERVICE_NAME}{enter}`);
+ cy.get('.euiButton__text').contains('Refresh').click();
+ cy.wait(delay);
+ cy.contains(' (1)').should('exist');
+ cy.contains('3.57%').should('exist');
+ });
+});
+
+describe('Testing service view empty state', () => {
+ beforeEach(() => {
+ // exception is thrown on loading EuiDataGrid in cypress only, ignore for now
+ cy.on('uncaught:exception', (err, runnable) => {
+ if (err.message.includes('ResizeObserver loop'))
+ return false;
+ });
+ cy.visit(`app/observability-dashboards#/trace_analytics/services/${SERVICE_NAME}`, {
+ onBeforeLoad: (win) => {
+ win.sessionStorage.clear();
+ },
+ });
+ cy.wait(delay * 3);
+ });
+
+ it('Renders service view empty state', () => {
+ cy.get('h2.euiTitle').contains('frontend-client').should('exist');
+ cy.get('.euiText').contains('0').should('exist');
+ cy.get('.euiText').contains('-').should('exist');
+ });
+});
+
+describe('Testing service view', () => {
+ beforeEach(() => {
+ // exception is thrown on loading EuiDataGrid in cypress only, ignore for now
+ cy.on('uncaught:exception', (err, runnable) => {
+ if (err.message.includes('ResizeObserver loop'))
+ return false;
+ });
+ cy.visit(`app/observability-dashboards#/trace_analytics/services/${SERVICE_NAME}`, {
+ onBeforeLoad: (win) => {
+ win.sessionStorage.clear();
+ },
+ });
+ setTimeFilter(undefined, false);
+ });
+
+ it('Renders service view', () => {
+ cy.get('h2.euiTitle').contains(SERVICE_NAME).should('exist');
+ cy.contains('178.6').should('exist');
+ cy.contains('3.57%').should('exist');
+ cy.get('div.vis-network').should('exist');
+ });
+
+ it('Has working breadcrumbs', () => {
+ cy.get('.euiBreadcrumb').contains(SERVICE_NAME).click();
+ cy.wait(delay);
+ cy.get('h2.euiTitle').contains(SERVICE_NAME).should('exist');
+ cy.get('.euiBreadcrumb').contains('Services').click();
+ cy.wait(delay);
+ cy.get('.euiTitle').contains('Services').should('exist');
+ cy.get('.euiBreadcrumb').contains('Trace analytics').click();
+ cy.wait(delay);
+ cy.get('.euiTitle').contains('Dashboard').should('exist');
+ cy.get('.euiBreadcrumb').contains('Observability').click();
+ cy.wait(delay);
+ cy.get('.euiTitle').contains('Event analytics').should('exist');
+ });
+
+ it('Renders spans data grid, flyout, filters', () => {
+ cy.get('button[data-datagrid-interactable="true"]').eq(0).click({ force: true });
+ cy.wait(delay);
+ cy.contains('Span detail').should('exist');
+ cy.contains('Span attributes').should('exist');
+ cy.get('.euiTextColor').contains('Span ID').trigger('mouseover');
+ cy.get('.euiButtonIcon[aria-label="span-flyout-filter-icon"').click({ force: true });
+ cy.wait(delay);
+
+ cy.get('.euiBadge__text').contains('spanId: ').should('exist');
+ cy.get('[data-test-subj="euiFlyoutCloseButton"]').click({ force: true });
+ cy.contains('Spans (1)').should('exist');
+ });
+});
diff --git a/.cypress/integration/6_trace_analytics_traces.spec.js b/.cypress/integration/6_trace_analytics_traces.spec.js
new file mode 100644
index 0000000000..2f96fab549
--- /dev/null
+++ b/.cypress/integration/6_trace_analytics_traces.spec.js
@@ -0,0 +1,114 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+///
+
+import { delay, setTimeFilter, SPAN_ID, TRACE_ID } from '../utils/constants';
+
+describe('Testing traces table empty state', () => {
+ beforeEach(() => {
+ cy.visit('app/observability-dashboards#/trace_analytics/traces', {
+ onBeforeLoad: (win) => {
+ win.sessionStorage.clear();
+ },
+ });
+ cy.wait(delay * 3);
+ });
+
+ it('Renders empty state', () => {
+ cy.contains(' (0)').should('exist');
+ cy.get('h2.euiTitle').contains('No matches').should('exist');
+ });
+});
+
+describe('Testing traces table', () => {
+ beforeEach(() => {
+ cy.visit('app/observability-dashboards#/trace_analytics/traces', {
+ onBeforeLoad: (win) => {
+ win.sessionStorage.clear();
+ },
+ });
+ setTimeFilter();
+ });
+
+ it('Renders the traces table', () => {
+ cy.contains(' (108)').should('exist');
+ cy.contains('03/25/2021 10:23:45').should('exist');
+ cy.contains('03f9c770db5ee2f1caac0...').should('exist');
+ cy.contains('224.99').should('exist');
+
+ // test data contains output from data-prepper 0.8, which doesn't have fields denormalized
+ // Trace Analytics should be able to handle the discrepancy if some fields cannot be parsed
+ cy.contains('Invalid date').should('exist');
+ cy.contains('-').should('exist');
+ });
+
+ it('Sorts the traces table', () => {
+ cy.get('.euiTableRow').first().contains('-').should('exist');
+ cy.get('.euiTableCellContent').contains('Trace group').click();
+ cy.get('.euiTableRow').first().contains('/%2A%2A').should('exist');
+ });
+
+ it('Searches correctly', () => {
+ cy.get('input[type="search"]').focus().type(`${TRACE_ID}{enter}`);
+ cy.get('.euiButton__text').contains('Refresh').click();
+ cy.wait(delay);
+ cy.contains(' (1)').should('exist');
+ cy.contains('03/25/2021 10:21:22').should('exist');
+ });
+});
+
+describe('Testing trace view', () => {
+ beforeEach(() => {
+ cy.visit(`app/observability-dashboards#/trace_analytics/traces/${TRACE_ID}`, {
+ onBeforeLoad: (win) => {
+ win.sessionStorage.clear();
+ },
+ });
+ cy.wait(delay * 3);
+ });
+
+ it('Renders the trace view', () => {
+ cy.contains('43.75%').should('exist');
+ cy.contains('42.58%').should('exist');
+ cy.contains('03/25/2021 10:21:22').should('exist');
+ cy.get('h2.euiTitle').contains(TRACE_ID).should('exist');
+
+ cy.get('div.js-plotly-plot').should('have.length.gte', 2);
+ cy.get('text[data-unformatted="database mysql.APM "]').should('exist');
+ cy.contains(`"${SPAN_ID}"`).should('exist');
+ });
+
+ it('Has working breadcrumbs', () => {
+ cy.get('.euiBreadcrumb').contains(TRACE_ID).click();
+ cy.wait(delay);
+ cy.get('h2.euiTitle').contains(TRACE_ID).should('exist');
+ cy.get('.euiBreadcrumb').contains('Traces').click();
+ cy.wait(delay);
+ cy.get('.euiTitle').contains('Traces').should('exist');
+ cy.get('.euiBreadcrumb').contains('Trace analytics').click();
+ cy.wait(delay);
+ cy.get('.euiTitle').contains('Dashboard').should('exist');
+ cy.get('.euiBreadcrumb').contains('Observability').click();
+ cy.wait(delay);
+ cy.get('.euiTitle').contains('Event analytics').should('exist');
+ });
+
+ it('Renders data grid, flyout and filters', () => {
+ cy.get('.euiToggle__input[title="Span list"]').click({ force: true });
+ cy.contains('2 columns hidden').should('exist');
+
+ cy.get('button[data-datagrid-interactable="true"]').eq(0).click({ force: true });
+ cy.wait(delay);
+ cy.contains('Span detail').should('exist');
+ cy.contains('Span attributes').should('exist');
+ cy.get('.euiTextColor').contains('Span ID').trigger('mouseover');
+ cy.get('.euiButtonIcon[aria-label="span-flyout-filter-icon"').click({ force: true });
+ cy.wait(delay);
+
+ cy.get('.euiBadge__text').contains('spanId: ').should('exist');
+ cy.contains('Spans (1)').should('exist');
+ });
+});
diff --git a/.cypress/integration/7_app_analytics.spec.js b/.cypress/integration/7_app_analytics.spec.js
new file mode 100644
index 0000000000..1e8ef7c954
--- /dev/null
+++ b/.cypress/integration/7_app_analytics.spec.js
@@ -0,0 +1,597 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+///
+
+import {
+ delay,
+ moveToHomePage,
+ moveToCreatePage,
+ moveToApplication,
+ moveToEditPage,
+ changeTimeTo24,
+ expectMessageOnHover,
+ baseQuery,
+ nameOne,
+ nameTwo,
+ nameThree,
+ description,
+ service_one,
+ service_two,
+ trace_one,
+ trace_two,
+ trace_three,
+ query_one,
+ query_two,
+ availability_default,
+ visOneName,
+ visTwoName,
+ composition,
+ newName,
+ TYPING_DELAY,
+ timeoutDelay
+} from '../utils/app_constants';
+import { supressResizeObserverIssue } from '../utils/constants';
+
+describe('Creating application', () => {
+ beforeEach(() => {
+ moveToCreatePage();
+ });
+
+ it('Suggests correct autocompletion', () => {
+ cy.get('[data-test-subj="logSourceAccordion"]').trigger('mouseover').click();
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').click();
+ cy.get('.aa-List').find('.aa-Item').should('have.length', 1);
+ cy.get('.aa-Item').contains('source').should('exist');
+ cy.focused().type('{enter}');
+ cy.get('.aa-List').find('.aa-Item').should('have.length', 1);
+ cy.get('.aa-Item').contains('=').should('exist');
+ cy.focused().type('{enter}');
+ cy.focused().type('opensearch');
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').click();
+ cy.get('.aa-Item').contains('opensearch_dashboards_sample_data_flights').click();
+ cy.focused().clear();
+ cy.get('.aa-List').find('.aa-Item').should('have.length', 1);
+ cy.focused().type('{enter}');
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain', 'source ');
+ cy.focused().type('{enter}');
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain', 'source = ');
+ cy.focused().type('opensearch');
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').click();
+ cy.get('.aa-Item').contains('opensearch_dashboards_sample_data_flights').click();
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain', 'source = opensearch_dashboards_sample_data_flights ');
+ cy.focused().type('{downArrow}');
+ cy.focused().type('{enter}');
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain', 'source = opensearch_dashboards_sample_data_flights, ');
+ cy.focused().type('opensearch');
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').click();
+ cy.get('.aa-Item').contains('opensearch_dashboards_sample_data_logs').click();
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain', 'source = opensearch_dashboards_sample_data_flights,opensearch_dashboards_sample_data_logs ');
+ });
+
+ it('Creates an application and redirects to application', () => {
+ expectMessageOnHover('createButton', 'Name is required.');
+ cy.get('[data-test-subj="nameFormRow"]').type(nameOne);
+ cy.get('[data-test-subj="descriptionFormRow"]').type('This application is for testing.');
+ expectMessageOnHover('createButton', 'Provide at least one log source, service, entity or trace group.');
+ cy.get('[data-test-subj="servicesEntitiesAccordion"]').trigger('mouseover').click();
+ cy.get('[data-test-subj="servicesEntitiesComboBox"]').click();
+ cy.focused().type('{downArrow}');
+ cy.focused().type('{enter}');
+ cy.get('[data-test-subj="servicesEntitiesCountBadge"]').should('contain', '1');
+ cy.get('[data-test-subj="logSourceAccordion"]').trigger('mouseover').click();
+ cy.get('[data-test-subj="createButton"]').should('not.be.disabled');
+ cy.get('[data-test-subj="createAndSetButton"]').should('be.disabled');
+ expectMessageOnHover('createAndSetButton', 'Log source is required to set availability.');
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').focus().type(baseQuery, {delay: TYPING_DELAY});
+ cy.get('[data-test-subj="traceGroupsAccordion"]').trigger('mouseover').click();
+ cy.get('[data-test-subj="traceGroupsComboBox"]').scrollIntoView().type('http');
+ cy.get('.euiFilterSelectItem').contains(trace_one).trigger('click');
+ cy.get('.euiFilterSelectItem').contains(trace_two).trigger('click');
+ cy.get('[data-test-subj="traceGroupsCountBadge"]').should('contain', '2');
+ cy.get('[data-test-subj="createButton"]').should('not.be.disabled');
+ cy.get('[data-test-subj="createButton"]').click();
+ cy.wait(delay * 3);
+ cy.get('[data-test-subj="applicationTitle"]').should('contain', nameOne);
+ cy.get('[data-test-subj="app-analytics-panelTab"]').click();
+ cy.get('[data-test-subj="addFirstVisualizationText"]').should('exist');
+ });
+
+ it('Redirects to home page on cancel', () => {
+ cy.get('[data-test-subj="cancelCreateButton"]').contains('Cancel').click();
+ cy.get('[data-test-subj="applicationHomePageTitle"]').should('exist');
+ });
+
+ it('Saves current input on reload', () => {
+ cy.get('[data-test-subj="nameFormRow"]').type(nameOne);
+ cy.get('[data-test-subj="descriptionFormRow"]').type(description);
+ cy.get('[data-test-subj="logSourceAccordion"]').trigger('mouseover').click();
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').click();
+ cy
+ .get('[data-test-subj="searchAutocompleteTextArea"]')
+ .focus()
+ .type(baseQuery, {delay: TYPING_DELAY});
+ cy.get('[data-test-subj="servicesEntitiesAccordion"]').trigger('mouseover').click();
+ cy.get('[data-test-subj="servicesEntitiesComboBox"]').scrollIntoView();
+ cy.get('[data-test-subj="servicesEntitiesComboBox"]').trigger('mouseover').click();
+ cy.get('.euiFilterSelectItem').contains(service_one).click({ force: true });
+ cy.get('[data-test-subj="servicesEntitiesCountBadge"]').should('contain', '1');
+ cy.get('[data-test-subj="traceGroupsAccordion"]').trigger('mouseover').click();
+ cy.get('[data-test-subj="traceGroupsComboBox"]').scrollIntoView().type('http');
+ cy.get('.euiFilterSelectItem').contains(trace_one).trigger('click');
+ cy.get('.euiFilterSelectItem').contains(trace_two).trigger('click');
+ cy.get('[data-test-subj="traceGroupsCountBadge"]').should('contain', '2');
+ cy.reload();
+ cy.wait(delay);
+ cy.get('[data-test-subj="nameFormRow"]').find('.euiFieldText').should('contain.value', nameOne);
+ cy.get('[data-test-subj="descriptionFormRow"]').find('.euiFieldText').should('contain.value', description);
+ cy.get('[data-test-subj="logSourceAccordion"]').trigger('mouseover').click();
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain.value', baseQuery);
+ cy.get('[data-test-subj="servicesEntitiesCountBadge"]').should('contain', '1');
+ cy.get('[data-test-subj="traceGroupsCountBadge"]').should('contain', '2');
+ });
+
+ it('Shows clear modals before clearing', () => {
+ cy.get('[data-test-subj="logSourceAccordion"]').trigger('mouseover').click();
+ cy.get('[data-test-subj="clearLogSourceButton"]').should('be.disabled');
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').focus().type(baseQuery, {delay: TYPING_DELAY});
+ cy.get('[data-test-subj="clearLogSourceButton"]').click();
+ cy.get('.euiButton--danger').contains('Clear').click();
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain.value', '');
+ cy.get('[data-test-subj="servicesEntitiesAccordion"]').trigger('mouseover').click();
+ cy.get('[data-test-subj="servicesEntitiesComboBox"]').trigger('mouseover').click();
+ cy.get('.euiFilterSelectItem').contains(service_one).trigger('click');
+ cy.get('[data-test-subj="servicesEntitiesCountBadge"]').should('contain', '1');
+ cy.get('[data-test-subj="clearServicesEntitiesButton"]').click();
+ cy.get('.euiButton--danger').contains('Clear all').click();
+ cy.get('[data-test-subj="servicesEntitiesCountBadge"]').should('contain', '0');
+ cy.get('[data-test-subj="servicesEntitiesAccordion"]').trigger('mouseover').click();
+ cy.get('[data-test-subj="traceGroupsAccordion"]').trigger('mouseover').click();
+ cy.get('[data-test-subj="traceGroupsComboBox"]').scrollIntoView().type('http');
+ cy.get('.euiFilterSelectItem').contains(trace_one).trigger('click');
+ cy.get('.euiFilterSelectItem').contains(trace_two).trigger('click');
+ cy.get('[data-test-subj="traceGroupsCountBadge"]').should('contain', '2');
+ cy.get('[data-test-subj="clearTraceGroupsButton"]').click();
+ cy.get('.euiButton--danger').contains('Clear all').click();
+ cy.get('[data-test-subj="traceGroupsCountBadge"]').should('contain', '0');
+ });
+
+ it('Saves time range for each application', () => {
+ cy.get('[data-test-subj="nameFormRow"]').type(nameTwo);
+ cy.get('[data-test-subj="logSourceAccordion"]').trigger('mouseover').click();
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').focus().type(baseQuery, {delay: TYPING_DELAY});
+ cy.get('[data-test-subj="createButton"]').should('not.be.disabled');
+ cy.get('[data-test-subj="createButton"]').click();
+ cy.get('[data-test-subj="applicationTitle"]').should('contain', nameTwo);
+ changeTimeTo24('weeks');
+ cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 weeks');
+ cy.get('.euiBreadcrumb[href="#/application_analytics"]').click();
+ cy.wait(delay);
+ cy.get(`[data-test-subj="${nameOne}ApplicationLink"]`).click();
+ cy.get('[data-test-subj="applicationTitle"]').should('contain', nameOne);
+ changeTimeTo24('months');
+ cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months');
+ cy.get('.euiBreadcrumb[href="#/application_analytics"]').click();
+ cy.get(`[data-test-subj="${nameTwo}ApplicationLink"]`).click();
+ cy.get('[data-test-subj="applicationTitle"]').should('contain', nameTwo);
+ cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 weeks');
+ cy.get('.euiBreadcrumb[href="#/application_analytics"]').click();
+ cy.get(`[data-test-subj="${nameOne}ApplicationLink"]`).click();
+ cy.get('[data-test-subj="applicationTitle"]').should('contain', nameOne);
+ cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months');
+ });
+});
+
+describe('Setting availability', () => {
+ it('Redirects to set availability at three entry points', () => {
+ moveToCreatePage();
+ cy.get('[data-test-subj="nameFormRow"]').type(nameThree);
+ cy.get('[data-test-subj="logSourceAccordion"]').trigger('mouseover').click();
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').focus();
+ cy.focused().type('source = ', { delay: TYPING_DELAY });
+ cy.focused().type('{enter}');
+ cy.get('[data-test-subj="createAndSetButton"]').click();
+ cy.get('[data-test-subj="applicationTitle"]').should('contain', nameThree);
+ cy.get('.euiBreadcrumb[href="#/application_analytics"]').click();
+ cy.get('[data-test-subj="setAvailabilityHomePageLink"]').first().click();
+ cy.get('[data-test-subj="applicationTitle"]').should('contain', nameThree);
+ cy.get('.euiTab-isSelected[id="app-analytics-log"]').should('exist', { timeout: timeoutDelay });
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain.value', availability_default);
+ cy.get('[id="explorerPlotComponent"]').should('exist');
+ cy.get('.euiTab-isSelected[id="availability-panel"]').should('exist');
+ cy.get('.euiBreadcrumb[href="#/application_analytics"]').click();
+ cy.get(`[data-test-subj="${nameThree}ApplicationLink"]`).click();
+ cy.get('[data-test-subj="applicationTitle"]').should('contain', nameThree);
+ cy.get('[data-test-subj="app-analytics-configTab"]').click();
+ cy.get('[data-test-subj="setAvailabilityConfigLink"]').click();
+ cy.get('.euiTab-isSelected[id="app-analytics-log"]').should('exist', { timeout: timeoutDelay });
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('contain.value', availability_default);
+ cy.get('[id="explorerPlotComponent"]').should('exist');
+ cy.get('.euiTab-isSelected[id="availability-panel"]').should('exist');
+ });
+});
+
+describe('Viewing application', () => {
+ beforeEach(() => {
+ moveToApplication(nameOne);
+ });
+
+ it('Has working breadcrumbs', () => {
+ cy.get('.euiBreadcrumb').contains(nameOne).click();
+ cy.get('[data-test-subj="applicationTitle"]').should('contain', nameOne);
+ cy.get('.euiBreadcrumb[href="#/application_analytics"]').click();
+ cy.get('[data-test-subj="applicationHomePageTitle"]').should('contain', 'Applications');
+ cy.get('.euiBreadcrumb[href="observability-dashboards#/"]').click();
+ cy.get('[data-test-subj="eventHomePageTitle"]').should('contain', 'Event analytics');
+ });
+
+ it('Shares time range among tabs', () => {
+ changeTimeTo24('months');
+ cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months');
+ cy.get('[data-test-subj="app-analytics-serviceTab"]').click();
+ cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months');
+ cy.get('[data-test-subj="app-analytics-traceTab"]').click();
+ supressResizeObserverIssue();
+ cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months');
+ cy.get('[data-test-subj="app-analytics-logTab"]').click();
+ cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months');
+ cy.get('[data-test-subj="app-analytics-panelTab"]').click();
+ cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months');
+ });
+
+ it('Shows latency variance in dashboards table', () => {
+ changeTimeTo24('months');
+ cy.get('[data-test-subj="dashboardTable"]').first().within(($table) => {
+ cy.get('.plot-container').should('have.length.at.least', 1);
+ })
+ });
+
+ it('Adds filter when Trace group name is clicked', () => {
+ cy.get('[data-test-subj="app-analytics-overviewTab"]').click();
+ cy.get('[data-test-subj="dashboard-table-trace-group-name-button"]').contains('client_create_order').click();
+ cy.get('.euiTableRow').should('have.length', 1, { timeout: timeoutDelay });
+ cy.get('[data-test-subj="client_create_orderFilterBadge"]').should('exist');
+ cy.get('[data-test-subj="filterBadge"]').click();
+ cy.get('[data-test-subj="deleteFilterIcon"]').click();
+ cy.get('[data-test-subj="client_create_orderFilterBadge"]').should('not.exist');
+ });
+
+ it('Opens service detail flyout when Service Name is clicked', () => {
+ cy.get('[data-test-subj="app-analytics-serviceTab"]').click();
+ cy.wait(delay);
+ cy.get('.euiLink').contains('authentication').click();
+ supressResizeObserverIssue();
+ cy.get('[data-test-subj="serviceDetailFlyoutTitle"]').should('be.visible');
+ cy.get('[data-test-subj="serviceDetailFlyout"]').within(($flyout) => {
+ cy.get('[data-test-subj="Number of connected servicesDescriptionList"]').should('contain', '3');
+ cy.get('[data-text="Error rate"]').click();
+ cy.get('.ytitle').contains('Error rate').should('exist');
+ });
+ cy.get('[data-test-subj="dataGridRowCell"] button').contains('718dc32a693c8a17').click();
+ cy.get('[data-test-subj="spanDetailFlyout"]').contains('Span detail').should('be.visible');
+ cy.get('[data-test-subj="ServiceDescriptionList"]').should('contain', 'authentication');
+ cy.get('[data-test-subj="euiFlyoutCloseButton"]').click();
+ cy.get('[data-test-subj="serviceDetailFlyout"]').should('not.be.visible');
+ cy.get('[data-test-subj="spanDetailFlyout"]').should('not.be.visible');
+ });
+
+ it('Opens trace detail flyout when Trace ID is clicked', () => {
+ cy.get('[data-test-subj="app-analytics-traceTab"]').click();
+ supressResizeObserverIssue();
+ cy.wait(delay);
+ cy.get('[title="03f9c770db5ee2f1caac0afc36db49ba"]').click();
+ cy.get('[data-test-subj="traceDetailFlyoutTitle"]').should('be.visible');
+ cy.get('[data-test-subj="traceDetailFlyout"]').within(($flyout) => {
+ cy.get('[data-test-subj="LatencyDescriptionList"]').should('contain', '224.99');
+ });
+ cy.get('[data-test-subj="euiFlyoutCloseButton"]').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="traceDetailFlyout"]').should('not.be.visible');
+ cy.get('[title="03f9c770db5ee2f1caac0afc36db49ba"]').click();
+ cy.get('[aria-label="Span list"]').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="dataGridRowCell"] button').contains('d67c5bb617ba9203').click();
+ cy.get('[data-test-subj="spanDetailFlyout"]').should('be.visible');
+ cy.get('[data-test-subj="euiFlyoutCloseButton"]').click();
+ cy.get('[data-test-subj="spanDetailFlyout"]').should('not.be.visible');
+ });
+
+ it('Opens span detail flyout when Span ID is clicked', () => {
+ cy.get('[data-test-subj="app-analytics-traceTab"]').click();
+ supressResizeObserverIssue();
+ cy.wait(delay);
+ cy.get('[data-test-subj="dataGridRowCell"]').contains('5ff3516909562c60').click();
+ cy.get('[data-test-subj="spanDetailFlyout"]').should('be.visible');
+ cy.get('[data-test-subj="spanDetailFlyout"]').within(($flyout) => {
+ cy.get('[data-test-subj="OperationDescriptionList"]').should('contain', 'HTTP GET');
+ });
+ cy.get('.euiText').contains('order').click();
+ cy.get('[aria-label="span-flyout-filter-icon"]').click();
+ cy.focused().blur();
+ cy.get('[data-test-subj="euiFlyoutCloseButton"]').click();
+ cy.get('[data-test-subj="filterBadge"][title="serviceName: order"]').should('exist');
+ cy.get('[aria-label="Remove filter"]').click();
+ cy.get('[data-test-subj="filterBadge"][title="serviceName: order"]').should('not.exist');
+ });
+
+ it('Shows base query', () => {
+ cy.get('[data-test-subj="app-analytics-logTab"]').click();
+ cy.get('.euiBadge[title="Base Query"]').should('exist');
+ cy.get('.euiBadge[title="Base Query"]').trigger('mouseover');
+ cy.get('.euiToolTipPopover').contains('source = opensearch_dashboards_sample_data_flights').should('exist');
+ });
+
+ it('Saves visualization #1 to panel', () => {
+ cy.get('[data-test-subj="app-analytics-panelTab"]').click();
+ cy.get('[data-test-subj="addVisualizationButton"]').first().click();
+ cy.wait(delay);
+ cy.get('[id="explorerPlotComponent"]').should('exist');
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').click();
+ cy.get('.aa-List').find('.aa-Item').should('have.length', 11);
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').focus().type(query_one, {delay: TYPING_DELAY});
+ changeTimeTo24('months');
+ cy.wait(delay * 2);
+ cy.get('[data-test-subj="main-content-visTab"]').click();
+ supressResizeObserverIssue();
+ cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click();
+ cy.get('[data-test-subj="eventExplorer__querySaveName"]').click().type(visOneName);
+ cy.wait(delay);
+ cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="app-analytics-panelTab"]').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="Flights to VeniceVisualizationPanel"]').should('exist');
+ cy.get('[id="explorerPlotComponent"]').should('exist');
+ cy.get('[class="trace bars"]').should('exist');
+ });
+
+ it('Adds availability level to visualization #1', () => {
+ cy.get('[data-test-subj="app-analytics-panelTab"]').click();
+ cy.get('[aria-label="actionMenuButton"]').click();
+ cy.get('[data-test-subj="editVizContextMenuItem"]').click();
+ supressResizeObserverIssue();
+ cy.get('[data-test-subj="superDatePickerShowDatesButton"]').should('contain', 'Last 24 months');
+ cy.get('.euiTab[id="availability-panel"]').click();
+ cy.get('[title="Bar"]').click();
+ cy.focused().type('{downArrow}');
+ cy.focused().type('{enter}');
+ cy.get('[data-test-subj="addAvailabilityButton"]').click();
+ cy.get('[data-test-subj="colorPickerAnchor"]').click();
+ cy.get('[aria-label="Select #54B399 as the color"]').click();
+ cy.get('[data-test-subj="nameFieldText"]').click().type('Available');
+ cy.get('option').contains('≥').should('exist');
+ cy.get('option').contains('≤').should('exist');
+ cy.get('option').contains('>').should('exist');
+ cy.get('option').contains('<').should('exist');
+ cy.get('option').contains('=').should('exist');
+ cy.get('option').contains('≠').should('exist');
+ cy.get('[data-test-subj="expressionSelect"]').select('>');
+ cy.get('[data-test-subj="valueFieldNumber"]').clear().type('0.5');
+ cy.get('[data-test-subj="visualizeEditorRenderButton"]').click();
+ cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click();
+ cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click();
+ cy.get('[data-test-subj="app-analytics-panelTab"]').click();
+ cy.get('[id="explorerPlotComponent"]').should('exist');
+ cy.get('[class="lines"]').should('exist');
+ cy.get('.textpoint').contains('Available').should('exist');
+ cy.get('.euiBreadcrumb[href="#/application_analytics"]').click();
+ cy.get('[data-test-subj="AvailableAvailabilityBadge"]').should('contain', 'Available');
+ cy.get('[data-test-subj="AvailableAvailabilityBadge"][style="background-color: rgb(84, 179, 153); color: rgb(0, 0, 0);"]').should('exist');
+ });
+
+ it('Saves visualization #2 to panel with availability level', () => {
+ changeTimeTo24('months');
+ cy.get('[data-test-subj="app-analytics-logTab"]').click();
+ cy.get('[id="explorerPlotComponent"]', { timeout: timeoutDelay }).should('exist');
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').focus().type(query_two, {delay: TYPING_DELAY});
+ cy.get('[data-test-subj="superDatePickerApplyTimeButton"]').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="main-content-visTab"]').click();
+ supressResizeObserverIssue();
+ cy.get('.euiTab[id="availability-panel"]').click();
+ cy.get('[title="Bar"]').click();
+ cy.focused().type('{downArrow}');
+ cy.focused().type('{enter}');
+ cy.wait(delay);
+ cy.get('[data-test-subj="addAvailabilityButton"]').click();
+ cy.get('[data-test-subj="colorPickerAnchor"]').click();
+ cy.get('[aria-label="Select #9170B8 as the color"]').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="nameFieldText"]').click().type('Super');
+ cy.get('[data-test-subj="expressionSelect"]').select('<');
+ cy.get('[data-test-subj="valueFieldNumber"]').clear().type('5.5');
+ cy.get('[data-test-subj="visualizeEditorRenderButton"]').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="addAvailabilityButton"]').click();
+ cy.get('[data-test-subj="colorPickerAnchor"]').first().click();
+ cy.get('[aria-label="Select #CA8EAE as the color"]').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="nameFieldText"]').first().click().type('Cool');
+ cy.get('[data-test-subj="expressionSelect"]').first().select('>');
+ cy.get('[data-test-subj="valueFieldNumber"]').first().clear().type('0');
+ cy.get('[data-test-subj="visualizeEditorRenderButton"]').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]').click();
+ cy.get('[data-test-subj="eventExplorer__querySaveName"]').click().type(visTwoName);
+ cy.wait(delay);
+ cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="app-analytics-panelTab"]').click();
+ cy.wait(delay);
+ cy.get('[id="explorerPlotComponent"]').should('have.length', 2);
+ moveToHomePage();
+ cy.get('[data-test-subj="SuperAvailabilityBadge"][style="background-color: rgb(145, 112, 184); color: rgb(0, 0, 0);"]').should('contain', 'Super');
+ });
+
+ it('Configuration tab shows details', () => {
+ cy.get('[data-test-subj="app-analytics-configTab"]').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="configBaseQueryCode"]').should('contain', baseQuery);
+ cy.get('[aria-label="List of services and entities"]').find('li').should('have.length', 1);
+ cy.get('[aria-label="List of trace groups"]').find('li').should('have.length', 2);
+ cy.get('option').should('have.length', 2);
+ });
+
+
+ it('Changes availability visualization', () => {
+ cy.get('[data-test-subj="app-analytics-configTab"]').click();
+ cy.wait(delay);
+ cy.get('select').select(visOneName);
+ cy.wait(delay);
+ moveToHomePage();
+ cy.get('[data-test-subj="AvailableAvailabilityBadge"][style="background-color: rgb(84, 179, 153); color: rgb(0, 0, 0);"]').should('contain', 'Available');
+ moveToApplication(nameOne);
+ cy.get('[data-test-subj="app-analytics-configTab"]').click();
+ cy.wait(delay);
+ cy.get('select').find('option:selected').should('have.text', visOneName);
+ })
+});
+
+describe('Separate from other plugins', () => {
+ it('Hides application visualizations in Event Analytics', () => {
+ cy.visit(`${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/event_analytics`);
+ cy.wait(delay * 3);
+ // When there are saved queries or visualizations there are two buttons
+ cy.get('body').then(($body) => {
+ if ($body.find('.euiButton').length == 2) {
+ cy.get('input.euiFieldSearch').type(visOneName, {delay: TYPING_DELAY});
+ cy.wait(delay);
+ cy.get('.euiTableCellContent__text').contains('No items found').should('exist');
+ cy.get('input.euiFieldSearch').clear().type(visTwoName, {delay: TYPING_DELAY});
+ cy.wait(delay);
+ cy.get('.euiTableCellContent__text').contains('No items found').should('exist');
+ cy.get('[class="euiFormControlLayoutClearButton"]').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="tablePaginationPopoverButton"]').click();
+ cy.get('.euiContextMenuItem__text').contains('50 rows').click();
+ cy.get('.euiCheckbox__input[data-test-subj="checkboxSelectAll"]').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="eventHomeAction"]').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="eventHomeAction__delete"]').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="popoverModal__deleteButton"]').should('be.disabled');
+ cy.get('[data-test-subj="popoverModal__deleteTextInput"]').type('delete');
+ cy.get('[data-test-subj="popoverModal__deleteButton"]').should('not.be.disabled');
+ cy.get('[data-test-subj="popoverModal__deleteButton"]').click();
+ cy.wait(delay);
+ }
+ })
+ });
+
+ it('Hides application visualizations in Operational Panels', () => {
+ cy.visit(
+ `${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/operational_panels/`
+ );
+ cy.get('[data-test-subj="operationalPanelsActionsButton"]', { timeout: timeoutDelay }).click();
+ cy.get('[data-test-subj="addSampleContextMenuItem"]', { timeout: timeoutDelay }).click();
+ cy.get('[data-test-subj="confirmModalConfirmButton"]', { timeout: timeoutDelay }).click();
+ cy.wait(delay * 2);
+ cy.get('.euiLink').contains('[Logs] Web traffic Panel').first().click();
+ cy.wait(delay * 2);
+ cy.get('[data-test-subj="addVisualizationButton"]').click();
+ cy.get('.euiContextMenuItem__text').contains('Select existing visualization').click();
+ cy.get('option').contains(visOneName).should('not.exist');
+ cy.get('option').contains(visTwoName).should('not.exist');
+ });
+
+ it('Hides application panels in Operational Panels', () => {
+ cy.visit(
+ `${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/operational_panels/`
+ );
+ cy.get('[data-test-subj="operationalPanelSearchBar"]', { timeout: timeoutDelay }).type(`${nameOne}'s Panel`, {delay: TYPING_DELAY});
+ cy.get('.euiTableCellContent__text').contains('No items found').should('exist');
+ cy.get('.euiFormControlLayoutClearButton').click();
+ cy.get('[data-test-subj="operationalPanelSearchBar"]').type('[Logs] Web traffic Panel', {delay: TYPING_DELAY});
+ cy.get('.euiTableRow').first().within(($row) => {
+ cy.get('.euiCheckbox').click();
+ });
+ cy.get('[data-test-subj="operationalPanelsActionsButton"]', { timeout: timeoutDelay }).click();
+ cy.get('[data-test-subj="deleteContextMenuItem"]', { timeout: timeoutDelay }).click();
+ cy.get('[data-test-subj="popoverModal__deleteTextInput"]', { timeout: timeoutDelay }).type('delete');
+ cy.get('[data-test-subj="popoverModal__deleteButton"]', { timeout: timeoutDelay }).should('not.be.disabled');
+ cy.get('[data-test-subj="popoverModal__deleteButton"]', { timeout: timeoutDelay }).click();
+ });
+});
+
+describe('Editing application', () => {
+ beforeEach(() => {
+ moveToEditPage();
+ });
+
+ it('Redirects to application after saving changes', () => {
+ cy.get('[data-test-subj="logSourceAccordion"]').trigger('mouseover').click();
+ cy.get('[data-test-subj="searchAutocompleteTextArea"]').should('be.disabled');
+ cy.get('[data-test-subj="servicesEntitiesAccordion"]').trigger('mouseover').click();
+ cy.get('[data-test-subj="servicesEntitiesComboBox"]').click();
+ cy.get('.euiFilterSelectItem').contains(service_two).click();
+ cy.get('[data-test-subj="servicesEntitiesCountBadge"]').should('contain', '2');
+ cy.get('[data-test-subj="traceGroupsAccordion"]').trigger('mouseover').click();
+ cy.get('[data-test-subj="comboBoxToggleListButton"]').eq(1).click();
+ cy.get('.euiFilterSelectItem').contains(trace_three).trigger('click');
+ cy.get('[data-test-subj="traceGroupsCountBadge"]').should('contain', '3');
+ cy.get('[data-test-subj="traceGroupsAccordion"]').trigger('mouseover').click();
+ cy.get('[data-test-subj="createButton"]').click();
+ cy.get('[data-test-subj="app-analytics-configTab"]').click();
+ cy.get('[data-test-subj="configBaseQueryCode"]').should('contain', baseQuery);
+ cy.get('[aria-label="List of services and entities"]').find('li').should('have.length', 2);
+ cy.get('[aria-label="List of trace groups"]').find('li').should('have.length', 3);
+ cy.get('[data-test-subj="applicationTitle"]').should('contain', nameOne);
+ });
+});
+
+describe('Application Analytics home page', () => {
+ beforeEach(() => {
+ moveToHomePage();
+ })
+
+ it('Show correct information in table', () => {
+ cy.get(`[data-test-subj="${nameOne}ApplicationLink"]`).should('exist');
+ cy.get('[data-test-subj="appAnalytics__compositionColumn"]').should('contain', composition);
+ cy.get('[data-test-subj="AvailableAvailabilityBadge"][style="background-color: rgb(84, 179, 153); color: rgb(0, 0, 0);"]').should('contain', 'Available')
+ });
+
+ it('Renames application', () => {
+ cy.get('[data-test-subj="appAnalyticsActionsButton"]').click();
+ cy.get('[data-test-subj="renameApplicationContextMenuItem"]').should('be.disabled');
+ cy.get('[data-test-subj="appAnalyticsActionsButton"]').click();
+ cy.get('.euiTableRow').first().within(($row) => {
+ cy.get('.euiCheckbox').click();
+ });
+ cy.wait(delay);
+ cy.get('[data-test-subj="appAnalyticsActionsButton"]').click();
+ cy.get('[data-test-subj="renameApplicationContextMenuItem"]').click();
+ cy.get('[data-test-subj="customModalFieldText"]').clear().focus().type(newName);
+ cy.get('[data-test-subj="runModalButton"]').click();
+ cy.wait(delay);
+ cy.get('.euiToast').contains(`Application successfully renamed to "${newName}"`);
+ cy.get('.euiTableRow').first().within(($row) => {
+ cy.get('.euiLink').contains(newName).should('exist');
+ });
+ });
+
+
+ it('Deletes application', () => {
+ cy.get('[data-test-subj="appAnalyticsActionsButton"]').click();
+ cy.get('[data-test-subj="deleteApplicationContextMenuItem"]').should('exist');
+ cy.get('[data-test-subj="appAnalyticsActionsButton"]').click();
+ cy.get('.euiTableRow').first().within(($row) => {
+ cy.get('.euiCheckbox').click();
+ });
+ cy.get('.euiTableRow').eq(1).within(($row) => {
+ cy.get('.euiCheckbox').click();
+ });
+ cy.get('.euiTableRow').eq(2).within(($row) => {
+ cy.get('.euiCheckbox').click();
+ });
+ cy.get('[data-test-subj="appAnalyticsActionsButton"]').click();
+ cy.get('[data-test-subj="deleteApplicationContextMenuItem"]').click();
+ cy.get('[data-test-subj="popoverModal__deleteTextInput"]').type('delete');
+ cy.get('[data-test-subj="popoverModal__deleteButton"').click();
+ cy.wait(delay);
+ cy.get('.euiToast').contains(`Applications successfully deleted!`);
+ cy.get(`[data-test-subj="${newName}ApplicationLink"]`).should('not.exist');
+ });
+});
diff --git a/.cypress/plugins/index.js b/.cypress/plugins/index.js
new file mode 100644
index 0000000000..8ac1f10667
--- /dev/null
+++ b/.cypress/plugins/index.js
@@ -0,0 +1,26 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+///
+// ***********************************************************
+// This example plugins/index.js can be used to load plugins
+//
+// You can change the location of this file or turn off loading
+// the plugins file with the 'pluginsFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/plugins-guide
+// ***********************************************************
+
+// This function is called when a project is opened or re-opened (e.g. due to
+// the project's config changing)
+
+/**
+ * @type {Cypress.PluginConfig}
+ */
+module.exports = (on, config) => {
+ // `on` is used to hook into various events Cypress emits
+ // `config` is the resolved Cypress config
+}
diff --git a/.cypress/support/commands.js b/.cypress/support/commands.js
new file mode 100644
index 0000000000..fd4a5a0632
--- /dev/null
+++ b/.cypress/support/commands.js
@@ -0,0 +1,71 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+// ***********************************************
+// This example commands.js shows you how to
+// create various custom commands and overwrite
+// existing commands.
+//
+// For more comprehensive examples of custom
+// commands please read more here:
+// https://on.cypress.io/custom-commands
+// ***********************************************
+//
+//
+// -- This is a parent command --
+// Cypress.Commands.add("login", (email, password) => { ... })
+//
+//
+// -- This is a child command --
+// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
+//
+//
+// -- This is a dual command --
+// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
+//
+//
+// -- This will overwrite an existing command --
+// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
+
+const { ADMIN_AUTH } = require('./constants');
+
+Cypress.Commands.overwrite('visit', (originalFn, url, options) => {
+ // Add the basic auth header when security enabled in the OpenSearch cluster
+ // https://github.com/cypress-io/cypress/issues/1288
+ if (Cypress.env('security_enabled')) {
+ if (options) {
+ options.auth = ADMIN_AUTH;
+ } else {
+ options = { auth: ADMIN_AUTH };
+ }
+ // Add query parameters - select the default OpenSearch Dashboards tenant
+ options.qs = { security_tenant: 'private' };
+ return originalFn(url, options);
+ } else {
+ return originalFn(url, options);
+ }
+});
+
+// Be able to add default options to cy.request(), https://github.com/cypress-io/cypress/issues/726
+Cypress.Commands.overwrite('request', (originalFn, ...args) => {
+ let defaults = {};
+ // Add the basic authentication header when security enabled in the OpenSearch cluster
+ if (Cypress.env('security_enabled')) {
+ defaults.auth = ADMIN_AUTH;
+ }
+
+ let options = {};
+ if (typeof args[0] === 'object' && args[0] !== null) {
+ options = Object.assign({}, args[0]);
+ } else if (args.length === 1) {
+ [options.url] = args;
+ } else if (args.length === 2) {
+ [options.method, options.url] = args;
+ } else if (args.length === 3) {
+ [options.method, options.url, options.body] = args;
+ }
+
+ return originalFn(Object.assign({}, defaults, options));
+});
diff --git a/.cypress/support/constants.js b/.cypress/support/constants.js
new file mode 100644
index 0000000000..d7978c222b
--- /dev/null
+++ b/.cypress/support/constants.js
@@ -0,0 +1,10 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const ADMIN_AUTH = {
+ username: 'admin',
+ password: 'admin',
+};
+
diff --git a/.cypress/support/index.js b/.cypress/support/index.js
new file mode 100644
index 0000000000..6b25b7b27e
--- /dev/null
+++ b/.cypress/support/index.js
@@ -0,0 +1,31 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+// ***********************************************************
+// This example support/index.js is processed and
+// loaded automatically before your test files.
+//
+// This is a great place to put global configuration and
+// behavior that modifies Cypress.
+//
+// You can change the location of this file or turn off
+// automatically serving support files with the
+// 'supportFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/configuration
+// ***********************************************************
+
+// Import commands.js using ES2015 syntax:
+import './commands';
+
+// Alternatively you can use CommonJS syntax:
+// require('./commands')
+
+// Switch the base URL of OpenSearch when security enabled in the cluster
+if (Cypress.env('security_enabled')) {
+ Cypress.env('opensearch', 'https://localhost:9200');
+}
+
diff --git a/.cypress/tsconfig.json b/.cypress/tsconfig.json
new file mode 100644
index 0000000000..36de33deef
--- /dev/null
+++ b/.cypress/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "compilerOptions": {
+ "allowJs": true,
+ "baseUrl": "../node_modules",
+ "types": ["cypress"]
+ },
+ "include": ["**/*.*"]
+}
diff --git a/.cypress/utils/app_constants.js b/.cypress/utils/app_constants.js
new file mode 100644
index 0000000000..f2a4e9c6a0
--- /dev/null
+++ b/.cypress/utils/app_constants.js
@@ -0,0 +1,88 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { supressResizeObserverIssue } from './constants';
+
+export const delay = 1000;
+export const timeoutDelay = 30000;
+export const TYPING_DELAY = 500;
+
+export const moveToHomePage = () => {
+ cy.visit(`${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/application_analytics/`);
+ cy.wait(delay * 3);
+ cy.get('.euiTitle').contains('Applications').should('exist');
+};
+
+export const moveToCreatePage = () => {
+ cy.visit(`${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/application_analytics/`);
+ cy.get('.euiButton[href="#/application_analytics/create"]').eq(0).click();
+ supressResizeObserverIssue();
+ cy.get('[data-test-subj="createPageTitle"]').should('contain', 'Create application');
+};
+
+export const moveToApplication = (name) => {
+ cy.visit(`${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/application_analytics/`);
+ cy.wait(delay * 6);
+ cy.get(`[data-test-subj="${name}ApplicationLink"]`).click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="applicationTitle"]').should('contain', name);
+ changeTimeTo24('years');
+};
+
+export const moveToEditPage = () => {
+ moveToApplication(nameOne);
+ cy.get('[data-test-subj="app-analytics-configTab"]').click();
+ cy.get('[data-test-subj="editApplicationButton"]').click();
+ supressResizeObserverIssue();
+ cy.wait(delay);
+ cy.get('[data-test-subj="createPageTitle"]').should('contain', 'Edit application');
+};
+
+export const changeTimeTo24 = (timeUnit) => {
+ cy.get('#QuickSelectPopover').click();
+ cy.get('[aria-label="Time unit"]').select(timeUnit);
+ cy.get('.euiButton').contains('Apply').click();
+ cy.wait(delay);
+ cy.get('[data-test-subj="superDatePickerApplyTimeButton"]').click();
+};
+
+export const expectMessageOnHover = (button, message) => {
+ cy.get(`[data-test-subj="${button}"]`).click({ force: true });
+ cy.get('.euiToolTipPopover').contains(message).should('exist');
+};
+
+export const moveToPanelHome = () => {
+ cy.visit(
+ `${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/operational_panels/`
+ );
+ cy.wait(delay * 3);
+};
+
+export const deleteAllSavedApplications = () => {
+ moveToHomePage();
+ cy.get('[data-test-subj="checkboxSelectAll"]').click();
+ cy.get('.euiPopover').contains('Actions').click();
+ cy.get('.euiContextMenuItem').contains('Delete').click();
+ cy.get('.euiButton__text').contains('Delete').click();
+};
+
+export const uniqueId = Date.now();
+export const baseQuery = 'source = opensearch_dashboards_sample_data_flights';
+export const nameOne = `Cypress-${uniqueId}`;
+export const nameTwo = `Pine-${uniqueId}`;
+export const nameThree = `Cedar-${uniqueId}`;
+export const description = 'This is my application for cypress testing.';
+export const service_one = 'order';
+export const service_two = 'payment';
+export const trace_one = 'HTTP POST';
+export const trace_two = 'HTTP GET';
+export const trace_three = 'client_pay_order';
+export const query_one = 'where DestCityName = "Venice" | stats count() by span( timestamp , 6h )';
+export const query_two = 'where OriginCityName = "Seoul" | stats count() by span( timestamp , 6h )';
+export const availability_default = 'stats count() by span( timestamp, 1h )';
+export const visOneName = 'Flights to Venice';
+export const visTwoName = 'Flights from Seoul';
+export const composition = 'order, payment, HTTP POST, HTTP GET, client_pay_order'
+export const newName = `Monterey Cypress-${uniqueId}`;
diff --git a/.cypress/utils/constants.js b/.cypress/utils/constants.js
new file mode 100644
index 0000000000..e99c97ddc9
--- /dev/null
+++ b/.cypress/utils/constants.js
@@ -0,0 +1,120 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const delay = 1500;
+
+// trace analytics
+export const TRACE_ID = '8832ed6abbb2a83516461960c89af49d';
+export const SPAN_ID = 'a673bc074b438374';
+export const SERVICE_NAME = 'frontend-client';
+
+export const testDataSet = [
+ {
+ mapping_url: 'https://raw.githubusercontent.com/opensearch-project/observability/main/dashboards-observability/.cypress/utils/otel-v1-apm-service-map-mappings.json',
+ data_url: 'https://raw.githubusercontent.com/opensearch-project/observability/main/dashboards-observability/.cypress/utils/otel-v1-apm-service-map.json',
+ index: 'otel-v1-apm-service-map',
+ },
+ {
+ mapping_url: 'https://raw.githubusercontent.com/opensearch-project/observability/main/dashboards-observability/.cypress/utils/otel-v1-apm-span-000001-mappings.json',
+ data_url: 'https://raw.githubusercontent.com/opensearch-project/observability/main/dashboards-observability/.cypress/utils/otel-v1-apm-span-000001.json',
+ index: 'otel-v1-apm-span-000001',
+ },
+ {
+ mapping_url: 'https://raw.githubusercontent.com/opensearch-project/observability/main/dashboards-observability/.cypress/utils/otel-v1-apm-span-000001-mappings.json',
+ data_url: 'https://raw.githubusercontent.com/opensearch-project/observability/main/dashboards-observability/.cypress/utils/otel-v1-apm-span-000002.json',
+ index: 'otel-v1-apm-span-000002',
+ },
+]
+
+export const setTimeFilter = (setEndTime = false, refresh = true) => {
+ const startTime = 'Mar 25, 2021 @ 10:00:00.000';
+ const endTime = 'Mar 25, 2021 @ 11:00:00.000';
+ cy.get('button.euiButtonEmpty[aria-label="Date quick select"]').click();
+ cy.get('.euiQuickSelect__applyButton').click();
+ cy.get('.euiSuperDatePicker__prettyFormatLink').click();
+ cy.get(
+ 'button.euiDatePopoverButton--start[data-test-subj="superDatePickerstartDatePopoverButton"]'
+ ).click();
+ cy.get('.euiTab__content').contains('Absolute').click();
+ cy.get('input[data-test-subj="superDatePickerAbsoluteDateInput"]')
+ .focus()
+ .type('{selectall}' + startTime);
+ if (setEndTime) {
+ cy.wait(delay);
+ cy.get(
+ 'button.euiDatePopoverButton--end[data-test-subj="superDatePickerendDatePopoverButton"]'
+ ).click();
+ cy.wait(delay);
+ cy.get('.euiTab__content').contains('Absolute').click();
+ cy.get('input[data-test-subj="superDatePickerAbsoluteDateInput"]')
+ .focus()
+ .type('{selectall}' + endTime);
+ }
+ if (refresh) cy.get('.euiButton__text').contains('Refresh').click();
+ cy.wait(delay);
+};
+
+// notebooks
+export const TEST_NOTEBOOK = 'Test Notebook';
+export const SAMPLE_URL = 'https://github.com/opensearch-project/sql/tree/main/sql-jdbc';
+export const MARKDOWN_TEXT = `%md
+# Heading 1
+
+#### List and links
+
+* 1
+* 2
+* [SQL JDBC](${SAMPLE_URL})
+
+---
+#### Code block
+* Explain SQL
+\`\`\`
+POST _plugins/_sql/_explain
+{
+ "query": "SELECT * FROM my-index LIMIT 50"
+}
+\`\`\`
+
+#### Table
+| a1 | b1 | c1 | d1 |
+|----|----|----|----|
+| a2 | b2 | c2 | d2 |
+| a3 | b3 | c3 | d3 |
+`
+
+export const SQL_QUERY_TEXT = `%sql
+select * from opensearch_dashboards_sample_data_flights limit 20
+`
+
+export const PPL_QUERY_TEXT = `%ppl
+source=opensearch_dashboards_sample_data_flights
+`
+
+// event analytics
+export const TEST_QUERIES = [
+ {
+ query: 'source = opensearch_dashboards_sample_data_flights'
+ },
+ {
+ query: 'source = opensearch_dashboards_sample_data_flights | stats avg(FlightDelayMin) by Carrier'
+ },
+ {
+ query: 'source = opensearch_dashboards_sample_data_logs'
+ },
+];
+
+export const TESTING_PANEL = 'Mock Testing Panels';
+export const SAVE_QUERY1 = 'Mock Flight Events Overview';
+export const SAVE_QUERY2 = 'Mock Flight count by destination';
+export const SAVE_QUERY3 = 'Mock Flight count by destination save to panel';
+export const SAVE_QUERY4 = 'Mock Flight peek';
+
+export const supressResizeObserverIssue = () => {
+ // exception is thrown on loading EuiDataGrid in cypress only, ignore for now
+ cy.on('uncaught:exception', (err, runnable) => {
+ if (err.message.includes('ResizeObserver loop')) return false;
+ });
+};
\ No newline at end of file
diff --git a/.cypress/utils/otel-v1-apm-service-map-mappings.json b/.cypress/utils/otel-v1-apm-service-map-mappings.json
new file mode 100644
index 0000000000..cd578eed49
--- /dev/null
+++ b/.cypress/utils/otel-v1-apm-service-map-mappings.json
@@ -0,0 +1,20 @@
+{
+ "properties": {
+ "destination": {
+ "properties": {
+ "domain": { "type": "keyword", "ignore_above": 1024 },
+ "resource": { "type": "keyword", "ignore_above": 1024 }
+ }
+ },
+ "hashId": { "type": "keyword", "ignore_above": 1024 },
+ "kind": { "type": "keyword", "ignore_above": 1024 },
+ "serviceName": { "type": "keyword", "ignore_above": 1024 },
+ "target": {
+ "properties": {
+ "domain": { "type": "keyword", "ignore_above": 1024 },
+ "resource": { "type": "keyword", "ignore_above": 1024 }
+ }
+ },
+ "traceGroupName": { "type": "keyword", "ignore_above": 1024 }
+ }
+}
diff --git a/.cypress/utils/otel-v1-apm-service-map.json b/.cypress/utils/otel-v1-apm-service-map.json
new file mode 100644
index 0000000000..72a7014024
--- /dev/null
+++ b/.cypress/utils/otel-v1-apm-service-map.json
@@ -0,0 +1,90 @@
+{"index":{"_id":"nHcC8xTV8traJL3W2zDPww=="}}
+{"serviceName":"authentication","kind":"SPAN_KIND_SERVER","destination":null,"target":{"resource":"server_request_login","domain":"authentication"},"traceGroupName":"load_main_screen","hashId":"nHcC8xTV8traJL3W2zDPww=="}
+{"index":{"_id":"6Rx2pb/AtLKLR4KnHh+Aog=="}}
+{"serviceName":"payment","kind":"SPAN_KIND_CLIENT","destination":{"resource":"/logs","domain":"analytics-service"},"target":null,"traceGroupName":"client_checkout","hashId":"6Rx2pb/AtLKLR4KnHh+Aog=="}
+{"index":{"_id":"tXEh3symNDTITnb/JtgUAQ=="}}
+{"serviceName":"analytics-service","kind":"SPAN_KIND_SERVER","destination":null,"target":{"resource":"/logs","domain":"analytics-service"},"traceGroupName":"client_create_order","hashId":"tXEh3symNDTITnb/JtgUAQ=="}
+{"index":{"_id":"kSY6gLrGOBh8YX3cEDCndg=="}}
+{"serviceName":"recommendation","kind":"SPAN_KIND_CLIENT","destination":{"resource":"/logs","domain":"analytics-service"},"target":null,"traceGroupName":"load_main_screen","hashId":"kSY6gLrGOBh8YX3cEDCndg=="}
+{"index":{"_id":"roX6tGXvCJeZW7SFJMBFKA=="}}
+{"serviceName":"analytics-service","kind":"SPAN_KIND_SERVER","destination":null,"target":{"resource":"/logs","domain":"analytics-service"},"traceGroupName":"load_main_screen","hashId":"roX6tGXvCJeZW7SFJMBFKA=="}
+{"index":{"_id":"md6PmbxmuV4WOmVVdqkP0w=="}}
+{"serviceName":"analytics-service","kind":"SPAN_KIND_SERVER","destination":null,"target":{"resource":"/logs","domain":"analytics-service"},"traceGroupName":"client_pay_order","hashId":"md6PmbxmuV4WOmVVdqkP0w=="}
+{"index":{"_id":"vVC4U6JrIz9uyZseTPb4YQ=="}}
+{"serviceName":"authentication","kind":"SPAN_KIND_CLIENT","destination":{"resource":"/logs","domain":"analytics-service"},"target":null,"traceGroupName":"load_main_screen","hashId":"vVC4U6JrIz9uyZseTPb4YQ=="}
+{"index":{"_id":"5aShvpERPjuk2dXmfYPeGw=="}}
+{"serviceName":"frontend-client","kind":"SPAN_KIND_CLIENT","destination":{"resource":"payment","domain":"payment"},"target":null,"traceGroupName":"client_checkout","hashId":"5aShvpERPjuk2dXmfYPeGw=="}
+{"index":{"_id":"5LTSGQfic2RYHvrURmIDew=="}}
+{"serviceName":"database","kind":"SPAN_KIND_SERVER","destination":null,"target":{"resource":"getIntentory","domain":"database"},"traceGroupName":"load_main_screen","hashId":"5LTSGQfic2RYHvrURmIDew=="}
+{"index":{"_id":"n+JXabfCcrIeMP691QwcpA=="}}
+{"serviceName":"payment","kind":"SPAN_KIND_CLIENT","destination":{"resource":"update_inventory","domain":"inventory"},"target":null,"traceGroupName":"client_checkout","hashId":"n+JXabfCcrIeMP691QwcpA=="}
+{"index":{"_id":"ftn94Oe1mZwUMyvg2+V8MA=="}}
+{"serviceName":"database","kind":"SPAN_KIND_SERVER","destination":null,"target":{"resource":"getCart","domain":"database"},"traceGroupName":"client_delivery_status","hashId":"ftn94Oe1mZwUMyvg2+V8MA=="}
+{"index":{"_id":"uXkISg6U505anMl1tck75Q=="}}
+{"serviceName":"inventory","kind":"SPAN_KIND_CLIENT","destination":{"resource":"/logs","domain":"analytics-service"},"target":null,"traceGroupName":"load_main_screen","hashId":"uXkISg6U505anMl1tck75Q=="}
+{"index":{"_id":"IBLMEZli7Q3BJTBMmjynDg=="}}
+{"serviceName":"analytics-service","kind":"SPAN_KIND_SERVER","destination":null,"target":{"resource":"/logs","domain":"analytics-service"},"traceGroupName":"client_delivery_status","hashId":"IBLMEZli7Q3BJTBMmjynDg=="}
+{"index":{"_id":"smEM+A4secOk8FOTDhrqOg=="}}
+{"serviceName":"order","kind":"SPAN_KIND_CLIENT","destination":{"resource":"cartEmpty","domain":"database"},"target":null,"traceGroupName":"client_cancel_order","hashId":"smEM+A4secOk8FOTDhrqOg=="}
+{"index":{"_id":"G92mlRHfmMvQD2lArmh0Zw=="}}
+{"serviceName":"order","kind":"SPAN_KIND_CLIENT","destination":{"resource":"/logs","domain":"analytics-service"},"target":null,"traceGroupName":"client_pay_order","hashId":"G92mlRHfmMvQD2lArmh0Zw=="}
+{"index":{"_id":"qEMd88Fa9974qME14b7Kow=="}}
+{"serviceName":"order","kind":"SPAN_KIND_CLIENT","destination":{"resource":"addItemToCart","domain":"database"},"target":null,"traceGroupName":"client_create_order","hashId":"qEMd88Fa9974qME14b7Kow=="}
+{"index":{"_id":"mpTVw7lUu8Up9GtBUSELzw=="}}
+{"serviceName":"frontend-client","kind":"SPAN_KIND_CLIENT","destination":{"resource":"get_order","domain":"order"},"target":null,"traceGroupName":"client_delivery_status","hashId":"mpTVw7lUu8Up9GtBUSELzw=="}
+{"index":{"_id":"vgoAV/423h26Su5VKVCrHA=="}}
+{"serviceName":"frontend-client","kind":"SPAN_KIND_CLIENT","destination":{"resource":"server_request_login","domain":"authentication"},"target":null,"traceGroupName":"load_main_screen","hashId":"vgoAV/423h26Su5VKVCrHA=="}
+{"index":{"_id":"tH75FnJ4hXfERLahbk67NA=="}}
+{"serviceName":"order","kind":"SPAN_KIND_CLIENT","destination":{"resource":"getCart","domain":"database"},"target":null,"traceGroupName":"client_delivery_status","hashId":"tH75FnJ4hXfERLahbk67NA=="}
+{"index":{"_id":"zA5g821XNTNVGjL2Re+T/w=="}}
+{"serviceName":"payment","kind":"SPAN_KIND_SERVER","destination":null,"target":{"resource":"payment","domain":"payment"},"traceGroupName":"client_checkout","hashId":"zA5g821XNTNVGjL2Re+T/w=="}
+{"index":{"_id":"JoFoNWxblmsk90V3KAC6Mw=="}}
+{"serviceName":"frontend-client","kind":"SPAN_KIND_CLIENT","destination":{"resource":"update_order","domain":"order"},"target":null,"traceGroupName":"client_create_order","hashId":"JoFoNWxblmsk90V3KAC6Mw=="}
+{"index":{"_id":"bG/EgRvp5yWM8S/ewA7CeA=="}}
+{"serviceName":"frontend-client","kind":"SPAN_KIND_CLIENT","destination":{"resource":"pay_order","domain":"order"},"target":null,"traceGroupName":"client_pay_order","hashId":"bG/EgRvp5yWM8S/ewA7CeA=="}
+{"index":{"_id":"82uLVoVcdLutBGhi8GcehQ=="}}
+{"serviceName":"database","kind":"SPAN_KIND_SERVER","destination":null,"target":{"resource":"cartSold","domain":"database"},"traceGroupName":"client_pay_order","hashId":"82uLVoVcdLutBGhi8GcehQ=="}
+{"index":{"_id":"+EtgSBZbmVZY9fAqD+mJVQ=="}}
+{"serviceName":"database","kind":"SPAN_KIND_SERVER","destination":null,"target":{"resource":"cartEmpty","domain":"database"},"traceGroupName":"client_cancel_order","hashId":"+EtgSBZbmVZY9fAqD+mJVQ=="}
+{"index":{"_id":"lZcUyuhGYfnaQqt+r73njA=="}}
+{"serviceName":"database","kind":"SPAN_KIND_SERVER","destination":null,"target":{"resource":"updateItem","domain":"database"},"traceGroupName":"client_checkout","hashId":"lZcUyuhGYfnaQqt+r73njA=="}
+{"index":{"_id":"4/dbUR9mx3HxFrBOZtP6Lw=="}}
+{"serviceName":"database","kind":"SPAN_KIND_SERVER","destination":null,"target":{"resource":"addItemToCart","domain":"database"},"traceGroupName":"client_create_order","hashId":"4/dbUR9mx3HxFrBOZtP6Lw=="}
+{"index":{"_id":"7/jRp2VF7544pBN6+mK2vw=="}}
+{"serviceName":"inventory","kind":"SPAN_KIND_CLIENT","destination":{"resource":"updateItem","domain":"database"},"target":null,"traceGroupName":"client_checkout","hashId":"7/jRp2VF7544pBN6+mK2vw=="}
+{"index":{"_id":"VGkxs9ySDsQKAaXlf7tFdg=="}}
+{"serviceName":"order","kind":"SPAN_KIND_SERVER","destination":null,"target":{"resource":"get_order","domain":"order"},"traceGroupName":"client_delivery_status","hashId":"VGkxs9ySDsQKAaXlf7tFdg=="}
+{"index":{"_id":"zT64jAt7FIedXfhiKIKNsg=="}}
+{"serviceName":"order","kind":"SPAN_KIND_SERVER","destination":null,"target":{"resource":"update_order","domain":"order"},"traceGroupName":"client_create_order","hashId":"zT64jAt7FIedXfhiKIKNsg=="}
+{"index":{"_id":"xw6RCawB/rzbZ6kv0D4x0w=="}}
+{"serviceName":"order","kind":"SPAN_KIND_SERVER","destination":null,"target":{"resource":"clear_order","domain":"order"},"traceGroupName":"client_cancel_order","hashId":"xw6RCawB/rzbZ6kv0D4x0w=="}
+{"index":{"_id":"Vp+wn6ysuN+c0dyioFZjRg=="}}
+{"serviceName":"order","kind":"SPAN_KIND_CLIENT","destination":{"resource":"/logs","domain":"analytics-service"},"target":null,"traceGroupName":"client_create_order","hashId":"Vp+wn6ysuN+c0dyioFZjRg=="}
+{"index":{"_id":"2/jQH927AMtF2WZMylDMDQ=="}}
+{"serviceName":"inventory","kind":"SPAN_KIND_CLIENT","destination":{"resource":"/logs","domain":"analytics-service"},"target":null,"traceGroupName":"client_checkout","hashId":"2/jQH927AMtF2WZMylDMDQ=="}
+{"index":{"_id":"mZYvSouwJIYzb/YHHR/0Mg=="}}
+{"serviceName":"inventory","kind":"SPAN_KIND_SERVER","destination":null,"target":{"resource":"update_inventory","domain":"inventory"},"traceGroupName":"client_checkout","hashId":"mZYvSouwJIYzb/YHHR/0Mg=="}
+{"index":{"_id":"AU3Kn8HEG52uXVpmo0IK2g=="}}
+{"serviceName":"inventory","kind":"SPAN_KIND_SERVER","destination":null,"target":{"resource":"read_inventory","domain":"inventory"},"traceGroupName":"load_main_screen","hashId":"AU3Kn8HEG52uXVpmo0IK2g=="}
+{"index":{"_id":"jVBZpblgxVXEDfBo0JQX6A=="}}
+{"serviceName":"order","kind":"SPAN_KIND_CLIENT","destination":{"resource":"/logs","domain":"analytics-service"},"target":null,"traceGroupName":"client_delivery_status","hashId":"jVBZpblgxVXEDfBo0JQX6A=="}
+{"index":{"_id":"LaIlCIqcSBujD6E7HP3PTQ=="}}
+{"serviceName":"order","kind":"SPAN_KIND_SERVER","destination":null,"target":{"resource":"pay_order","domain":"order"},"traceGroupName":"client_pay_order","hashId":"LaIlCIqcSBujD6E7HP3PTQ=="}
+{"index":{"_id":"yzLB0GSsao4dvqVkR2zmYA=="}}
+{"serviceName":"recommendation","kind":"SPAN_KIND_SERVER","destination":null,"target":{"resource":"recommend","domain":"recommendation"},"traceGroupName":"load_main_screen","hashId":"yzLB0GSsao4dvqVkR2zmYA=="}
+{"index":{"_id":"8JvOMXSL6Hvf9C2jhum5sA=="}}
+{"serviceName":"order","kind":"SPAN_KIND_CLIENT","destination":{"resource":"/logs","domain":"analytics-service"},"target":null,"traceGroupName":"client_cancel_order","hashId":"8JvOMXSL6Hvf9C2jhum5sA=="}
+{"index":{"_id":"k/XY09UW54o31tkx3+rCRw=="}}
+{"serviceName":"authentication","kind":"SPAN_KIND_CLIENT","destination":{"resource":"recommend","domain":"recommendation"},"target":null,"traceGroupName":"load_main_screen","hashId":"k/XY09UW54o31tkx3+rCRw=="}
+{"index":{"_id":"5zJU9hp/t1AdgblDfFDOXQ=="}}
+{"serviceName":"analytics-service","kind":"SPAN_KIND_SERVER","destination":null,"target":{"resource":"/logs","domain":"analytics-service"},"traceGroupName":"client_checkout","hashId":"5zJU9hp/t1AdgblDfFDOXQ=="}
+{"index":{"_id":"KIySJpq7dvvDj5nofZ7tqw=="}}
+{"serviceName":"analytics-service","kind":"SPAN_KIND_SERVER","destination":null,"target":{"resource":"/logs","domain":"analytics-service"},"traceGroupName":"client_cancel_order","hashId":"KIySJpq7dvvDj5nofZ7tqw=="}
+{"index":{"_id":"1MEZjF+x1T015XUk5Tjbuw=="}}
+{"serviceName":"inventory","kind":"SPAN_KIND_CLIENT","destination":{"resource":"getIntentory","domain":"database"},"target":null,"traceGroupName":"load_main_screen","hashId":"1MEZjF+x1T015XUk5Tjbuw=="}
+{"index":{"_id":"zIYLVbtNe1bnfLhCk3BbOw=="}}
+{"serviceName":"order","kind":"SPAN_KIND_CLIENT","destination":{"resource":"cartSold","domain":"database"},"target":null,"traceGroupName":"client_pay_order","hashId":"zIYLVbtNe1bnfLhCk3BbOw=="}
+{"index":{"_id":"00aTIGyGNbec9vfKsJkHMA=="}}
+{"serviceName":"frontend-client","kind":"SPAN_KIND_CLIENT","destination":{"resource":"clear_order","domain":"order"},"target":null,"traceGroupName":"client_cancel_order","hashId":"00aTIGyGNbec9vfKsJkHMA=="}
+{"index":{"_id":"2hnSYfBfhz/0R9wDYJsqUg=="}}
+{"serviceName":"recommendation","kind":"SPAN_KIND_CLIENT","destination":{"resource":"read_inventory","domain":"inventory"},"target":null,"traceGroupName":"load_main_screen","hashId":"2hnSYfBfhz/0R9wDYJsqUg=="}
diff --git a/.cypress/utils/otel-v1-apm-span-000001-mappings.json b/.cypress/utils/otel-v1-apm-span-000001-mappings.json
new file mode 100644
index 0000000000..1288c0f638
--- /dev/null
+++ b/.cypress/utils/otel-v1-apm-span-000001-mappings.json
@@ -0,0 +1,74 @@
+{
+ "properties": {
+ "traceId": {
+ "ignore_above": 256,
+ "type": "keyword"
+ },
+ "spanId": {
+ "ignore_above": 256,
+ "type": "keyword"
+ },
+ "parentSpanId": {
+ "ignore_above": 256,
+ "type": "keyword"
+ },
+ "name": {
+ "ignore_above": 1024,
+ "type": "keyword"
+ },
+ "traceGroup": {
+ "ignore_above": 1024,
+ "type": "keyword"
+ },
+ "traceGroupFields": {
+ "properties": {
+ "endTime": {
+ "type": "date_nanos"
+ },
+ "durationInNanos": {
+ "type": "long"
+ },
+ "statusCode": {
+ "type": "integer"
+ }
+ }
+ },
+ "kind": {
+ "ignore_above": 128,
+ "type": "keyword"
+ },
+ "startTime": {
+ "type": "date_nanos"
+ },
+ "endTime": {
+ "type": "date_nanos"
+ },
+ "status": {
+ "properties": {
+ "code": {
+ "type": "integer"
+ },
+ "message": {
+ "type": "keyword"
+ }
+ }
+ },
+ "serviceName": {
+ "type": "keyword"
+ },
+ "durationInNanos": {
+ "type": "long"
+ },
+ "events": {
+ "type": "nested",
+ "properties": {
+ "time": {
+ "type": "date_nanos"
+ }
+ }
+ },
+ "links": {
+ "type": "nested"
+ }
+ }
+}
diff --git a/.cypress/utils/otel-v1-apm-span-000001.json b/.cypress/utils/otel-v1-apm-span-000001.json
new file mode 100644
index 0000000000..1c6fcbbf71
--- /dev/null
+++ b/.cypress/utils/otel-v1-apm-span-000001.json
@@ -0,0 +1,1000 @@
+{"index":{"_id":"e275ac9d21929e9b"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"e275ac9d21929e9b","traceState":"","parentSpanId":"","name":"client_checkout","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:30.088478464Z","endTime":"2021-03-25T17:23:30.481628416Z","durationInNanos":393149952,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"77f5fa8273184c40"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"77f5fa8273184c40","traceState":"","parentSpanId":"927d2469efed5531","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:30.224065280Z","endTime":"2021-03-25T17:23:30.302305280Z","durationInNanos":78240000,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"span.attributes.http@url":"http://localhost:8083/update_item","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"fe059cf714e8e915"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"fe059cf714e8e915","traceState":"","parentSpanId":"0bc22062693f08eb","name":"updateItem","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:30.315486720Z","endTime":"2021-03-25T17:23:30.360892672Z","durationInNanos":45405952,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55868,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_item","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/update_item","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"1d4ac48e0dd1df50"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"1d4ac48e0dd1df50","traceState":"","parentSpanId":"fe059cf714e8e915","name":"update_item","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:30.316961280Z","endTime":"2021-03-25T17:23:30.353545728Z","durationInNanos":36584448,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"2a0f9f783ac62bc4"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"2a0f9f783ac62bc4","traceState":"","parentSpanId":"77f5fa8273184c40","name":"updateItem","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:30.227811584Z","endTime":"2021-03-25T17:23:30.283355136Z","durationInNanos":55543552,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55864,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_item","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/update_item","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"0de86f454dd43352"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"0de86f454dd43352","traceState":"","parentSpanId":"e275ac9d21929e9b","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:30.088787968Z","endTime":"2021-03-25T17:23:30.458000640Z","durationInNanos":369212672,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"span.attributes.http@url":"http://localhost:8084/checkout","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"59680d06f2fe59a9"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"59680d06f2fe59a9","traceState":"","parentSpanId":"dceae5ba953b44f8","name":"update_item","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:30.158086144Z","endTime":"2021-03-25T17:23:30.194613760Z","durationInNanos":36527616,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"3f579ac135ffee68"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"3f579ac135ffee68","traceState":"","parentSpanId":"0d67b27c714b026b","name":"checkout","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:30.092352256Z","endTime":"2021-03-25T17:23:30.441958144Z","durationInNanos":349605888,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"f6a14e0c8213862d"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"f6a14e0c8213862d","traceState":"","parentSpanId":"01c87a25f18fb004","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:30.096681472Z","endTime":"2021-03-25T17:23:30.110944768Z","durationInNanos":14263296,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"684e00b74392b8c6"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"684e00b74392b8c6","traceState":"","parentSpanId":"f6a14e0c8213862d","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:30.101003010Z","endTime":"2021-03-25T17:23:30.105259791Z","durationInNanos":4256781,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-4","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":131,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56574,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"c0b1d9dbb89786a2"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"c0b1d9dbb89786a2","traceState":"","parentSpanId":"38f1a1108569130d","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:30.254752Z","endTime":"2021-03-25T17:23:30.255640064Z","durationInNanos":888064,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'orange', 'Qty': 3}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"a178d4084436e2ba"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"a178d4084436e2ba","traceState":"","parentSpanId":"3f579ac135ffee68","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:30.092835072Z","endTime":"2021-03-25T17:23:30.415470336Z","durationInNanos":322635264,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"span.attributes.http@url":"http://localhost:8082/update_inventory","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"f224b7718d28dcb6"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"f224b7718d28dcb6","traceState":"","parentSpanId":"3f579ac135ffee68","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:30.422688512Z","endTime":"2021-03-25T17:23:30.433830656Z","durationInNanos":11142144,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"780ac0205eee0281"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"780ac0205eee0281","traceState":"","parentSpanId":"a28b32a24ed2b94a","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:30.384634213Z","endTime":"2021-03-25T17:23:30.386278811Z","durationInNanos":1644598,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"span.attributes.thread@name":"http-nio-8087-exec-6","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":133,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"ec11e2136b66d7a9"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"ec11e2136b66d7a9","traceState":"","parentSpanId":"a178d4084436e2ba","name":"update_inventory","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:30.149690368Z","endTime":"2021-03-25T17:23:30.403485184Z","durationInNanos":253794816,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8082,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":45724,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_inventory","span.attributes.http@host":"localhost:8082","span.attributes.http@target":"/update_inventory","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"dceae5ba953b44f8"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"dceae5ba953b44f8","traceState":"","parentSpanId":"5b7ebc3b9a56dd8e","name":"updateItem","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:30.156352768Z","endTime":"2021-03-25T17:23:30.202127616Z","durationInNanos":45774848,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55860,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_item","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/update_item","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"0d67b27c714b026b"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"0d67b27c714b026b","traceState":"","parentSpanId":"0de86f454dd43352","name":"payment","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:30.091403776Z","endTime":"2021-03-25T17:23:30.446498816Z","durationInNanos":355095040,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8084,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":50460,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/checkout","span.attributes.http@host":"localhost:8084","span.attributes.http@target":"/checkout","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"5b7ebc3b9a56dd8e"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"5b7ebc3b9a56dd8e","traceState":"","parentSpanId":"927d2469efed5531","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:30.151849984Z","endTime":"2021-03-25T17:23:30.215842816Z","durationInNanos":63992832,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"span.attributes.http@url":"http://localhost:8083/update_item","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"38f1a1108569130d"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"38f1a1108569130d","traceState":"","parentSpanId":"2a0f9f783ac62bc4","name":"update_item","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:30.228819968Z","endTime":"2021-03-25T17:23:30.274412544Z","durationInNanos":45592576,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"01c87a25f18fb004"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"01c87a25f18fb004","traceState":"","parentSpanId":"a178d4084436e2ba","name":"update_inventory","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:30.095432704Z","endTime":"2021-03-25T17:23:30.125712640Z","durationInNanos":30279936,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8082,"span.attributes.http@status_text":"SERVICE UNAVAILABLE","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":2,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":45720,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_inventory","span.attributes.http@host":"localhost:8082","span.attributes.http@target":"/update_inventory","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":503}
+{"index":{"_id":"a28b32a24ed2b94a"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"a28b32a24ed2b94a","traceState":"","parentSpanId":"e2901228ca3b80b6","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:30.384003598Z","endTime":"2021-03-25T17:23:30.386471230Z","durationInNanos":2467632,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-6","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":133,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56590,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"9043250a4d19bab2"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"9043250a4d19bab2","traceState":"","parentSpanId":"1d4ac48e0dd1df50","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:30.341936128Z","endTime":"2021-03-25T17:23:30.342908928Z","durationInNanos":972800,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'apple', 'Qty': 1}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"e2901228ca3b80b6"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"e2901228ca3b80b6","traceState":"","parentSpanId":"927d2469efed5531","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:30.381153024Z","endTime":"2021-03-25T17:23:30.388188416Z","durationInNanos":7035392,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"e5e29b75177318a4"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"e5e29b75177318a4","traceState":"","parentSpanId":"59680d06f2fe59a9","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:30.181832960Z","endTime":"2021-03-25T17:23:30.182824192Z","durationInNanos":991232,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'banana', 'Qty': 2}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"0bc22062693f08eb"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"0bc22062693f08eb","traceState":"","parentSpanId":"927d2469efed5531","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:30.312822784Z","endTime":"2021-03-25T17:23:30.372530176Z","durationInNanos":59707392,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"span.attributes.http@url":"http://localhost:8083/update_item","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"6f543d74cf9ab42f"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"6f543d74cf9ab42f","traceState":"","parentSpanId":"ee476840b78b6b64","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:30.430701513Z","endTime":"2021-03-25T17:23:30.431879792Z","durationInNanos":1178279,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"span.attributes.thread@name":"http-nio-8087-exec-8","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":135,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"ee476840b78b6b64"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"ee476840b78b6b64","traceState":"","parentSpanId":"f224b7718d28dcb6","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:30.430003216Z","endTime":"2021-03-25T17:23:30.432007390Z","durationInNanos":2004174,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-8","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":135,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56592,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"3d6c88ccfe463625"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"3d6c88ccfe463625","traceState":"","parentSpanId":"684e00b74392b8c6","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:30.101806858Z","endTime":"2021-03-25T17:23:30.105081805Z","durationInNanos":3274947,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"span.attributes.thread@name":"http-nio-8087-exec-4","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":131,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"927d2469efed5531"}}
+{"traceId":"4fa04f117be100f476b175e41096e736","spanId":"927d2469efed5531","traceState":"","parentSpanId":"ec11e2136b66d7a9","name":"update_inventory","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:30.151124480Z","endTime":"2021-03-25T17:23:30.394688768Z","durationInNanos":243564288,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:30.481628416Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":393149952,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"1d2c0f411e8ee2f8"}}
+{"traceId":"44e8643dd4b770a492e0556c3c3105e2","spanId":"1d2c0f411e8ee2f8","traceState":"","parentSpanId":"","name":"client_create_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:31.152335104Z","endTime":"2021-03-25T17:23:31.468260096Z","durationInNanos":315924992,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:31.468260096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":315924992,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"a91d84e8178f1fd8"}}
+{"traceId":"44e8643dd4b770a492e0556c3c3105e2","spanId":"a91d84e8178f1fd8","traceState":"","parentSpanId":"eeaa622f88fe207c","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:31.303123712Z","endTime":"2021-03-25T17:23:31.304368896Z","durationInNanos":1245184,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:31.468260096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":315924992,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'orange', 'Qty': '3'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"INSERT INTO User_Carts (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"4d1c65495ff29c6d"}}
+{"traceId":"44e8643dd4b770a492e0556c3c3105e2","spanId":"4d1c65495ff29c6d","traceState":"","parentSpanId":"7238b78b0ed71521","name":"addItemToCart","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:31.353071360Z","endTime":"2021-03-25T17:23:31.409542656Z","durationInNanos":56471296,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:31.468260096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":315924992,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55886,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/add_item_to_cart","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/add_item_to_cart","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"d9ee030e0d08690e"}}
+{"traceId":"44e8643dd4b770a492e0556c3c3105e2","spanId":"d9ee030e0d08690e","traceState":"","parentSpanId":"28262a4233f0588c","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:31.431002978Z","endTime":"2021-03-25T17:23:31.434517936Z","durationInNanos":3514958,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:31.468260096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":315924992,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-10","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":137,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56608,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"b3752b14ed618509"}}
+{"traceId":"44e8643dd4b770a492e0556c3c3105e2","spanId":"b3752b14ed618509","traceState":"","parentSpanId":"2bd2af19d4a54899","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:31.254661632Z","endTime":"2021-03-25T17:23:31.343596800Z","durationInNanos":88935168,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:31.468260096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":315924992,"span.attributes.http@url":"http://localhost:8083/add_item_to_cart","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"b445c2d1b93f0221"}}
+{"traceId":"44e8643dd4b770a492e0556c3c3105e2","spanId":"b445c2d1b93f0221","traceState":"","parentSpanId":"72c5af1d1df82890","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:31.377131776Z","endTime":"2021-03-25T17:23:31.378107648Z","durationInNanos":975872,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:31.468260096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":315924992,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'banana', 'Qty': '2'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"7238b78b0ed71521"}}
+{"traceId":"44e8643dd4b770a492e0556c3c3105e2","spanId":"7238b78b0ed71521","traceState":"","parentSpanId":"2bd2af19d4a54899","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:31.350046208Z","endTime":"2021-03-25T17:23:31.422569728Z","durationInNanos":72523520,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:31.468260096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":315924992,"span.attributes.http@url":"http://localhost:8083/add_item_to_cart","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"e6b4ab74f8b80f4e"}}
+{"traceId":"44e8643dd4b770a492e0556c3c3105e2","spanId":"e6b4ab74f8b80f4e","traceState":"","parentSpanId":"e241b0e785a3c575","name":"update_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:31.155295232Z","endTime":"2021-03-25T17:23:31.449997056Z","durationInNanos":294701824,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:31.468260096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":315924992,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56862,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/update_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"dcb75802cdd2df95"}}
+{"traceId":"44e8643dd4b770a492e0556c3c3105e2","spanId":"dcb75802cdd2df95","traceState":"","parentSpanId":"5a4c439943652ab5","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:31.203629568Z","endTime":"2021-03-25T17:23:31.209441792Z","durationInNanos":5812224,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:31.468260096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":315924992,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'apple', 'Qty': '1'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"INSERT INTO User_Carts (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"2bd2af19d4a54899"}}
+{"traceId":"44e8643dd4b770a492e0556c3c3105e2","spanId":"2bd2af19d4a54899","traceState":"","parentSpanId":"e6b4ab74f8b80f4e","name":"update_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:31.156228352Z","endTime":"2021-03-25T17:23:31.444213504Z","durationInNanos":287985152,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:31.468260096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":315924992,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"5a4c439943652ab5"}}
+{"traceId":"44e8643dd4b770a492e0556c3c3105e2","spanId":"5a4c439943652ab5","traceState":"","parentSpanId":"78043dd3210ad09c","name":"add_item_to_cart","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:31.160545792Z","endTime":"2021-03-25T17:23:31.219949056Z","durationInNanos":59403264,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:31.468260096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":315924992,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"eeaa622f88fe207c"}}
+{"traceId":"44e8643dd4b770a492e0556c3c3105e2","spanId":"eeaa622f88fe207c","traceState":"","parentSpanId":"474586f3bebe59ed","name":"add_item_to_cart","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:31.266703616Z","endTime":"2021-03-25T17:23:31.316477184Z","durationInNanos":49773568,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:31.468260096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":315924992,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"72c5af1d1df82890"}}
+{"traceId":"44e8643dd4b770a492e0556c3c3105e2","spanId":"72c5af1d1df82890","traceState":"","parentSpanId":"4d1c65495ff29c6d","name":"add_item_to_cart","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:31.353989888Z","endTime":"2021-03-25T17:23:31.399032832Z","durationInNanos":45042944,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:31.468260096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":315924992,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"474586f3bebe59ed"}}
+{"traceId":"44e8643dd4b770a492e0556c3c3105e2","spanId":"474586f3bebe59ed","traceState":"","parentSpanId":"b3752b14ed618509","name":"addItemToCart","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:31.265601280Z","endTime":"2021-03-25T17:23:31.324172544Z","durationInNanos":58571264,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:31.468260096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":315924992,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55882,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/add_item_to_cart","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/add_item_to_cart","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"1e468dfafa2cbf01"}}
+{"traceId":"44e8643dd4b770a492e0556c3c3105e2","spanId":"1e468dfafa2cbf01","traceState":"","parentSpanId":"2bd2af19d4a54899","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:31.156710912Z","endTime":"2021-03-25T17:23:31.242307072Z","durationInNanos":85596160,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:31.468260096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":315924992,"span.attributes.http@url":"http://localhost:8083/add_item_to_cart","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"51c30794d41a0e90"}}
+{"traceId":"44e8643dd4b770a492e0556c3c3105e2","spanId":"51c30794d41a0e90","traceState":"","parentSpanId":"5a4c439943652ab5","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:31.193952256Z","endTime":"2021-03-25T17:23:31.195421440Z","durationInNanos":1469184,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:31.468260096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":315924992,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'apple', 'Qty': '1'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"28262a4233f0588c"}}
+{"traceId":"44e8643dd4b770a492e0556c3c3105e2","spanId":"28262a4233f0588c","traceState":"","parentSpanId":"2bd2af19d4a54899","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:31.428226560Z","endTime":"2021-03-25T17:23:31.436708352Z","durationInNanos":8481792,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:31.468260096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":315924992,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"78043dd3210ad09c"}}
+{"traceId":"44e8643dd4b770a492e0556c3c3105e2","spanId":"78043dd3210ad09c","traceState":"","parentSpanId":"1e468dfafa2cbf01","name":"addItemToCart","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:31.159513088Z","endTime":"2021-03-25T17:23:31.228904448Z","durationInNanos":69391360,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:31.468260096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":315924992,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55878,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/add_item_to_cart","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/add_item_to_cart","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"f7e912b3aad7acba"}}
+{"traceId":"44e8643dd4b770a492e0556c3c3105e2","spanId":"f7e912b3aad7acba","traceState":"","parentSpanId":"d9ee030e0d08690e","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:31.431638466Z","endTime":"2021-03-25T17:23:31.434321227Z","durationInNanos":2682761,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:31.468260096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":315924992,"span.attributes.thread@name":"http-nio-8087-exec-10","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":137,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"965cedf647f21b1a"}}
+{"traceId":"44e8643dd4b770a492e0556c3c3105e2","spanId":"965cedf647f21b1a","traceState":"","parentSpanId":"eeaa622f88fe207c","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:31.294086656Z","endTime":"2021-03-25T17:23:31.295151104Z","durationInNanos":1064448,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:31.468260096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":315924992,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'orange', 'Qty': '3'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"917c94fc2ae3b411"}}
+{"traceId":"44e8643dd4b770a492e0556c3c3105e2","spanId":"917c94fc2ae3b411","traceState":"","parentSpanId":"72c5af1d1df82890","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:31.384803328Z","endTime":"2021-03-25T17:23:31.385842432Z","durationInNanos":1039104,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:31.468260096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":315924992,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'banana', 'Qty': '2'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"INSERT INTO User_Carts (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"e241b0e785a3c575"}}
+{"traceId":"44e8643dd4b770a492e0556c3c3105e2","spanId":"e241b0e785a3c575","traceState":"","parentSpanId":"1d2c0f411e8ee2f8","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:31.152645120Z","endTime":"2021-03-25T17:23:31.462845440Z","durationInNanos":310200320,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:31.468260096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":315924992,"span.attributes.http@url":"http://localhost:8088/update_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"dbc247c510f8fa6c"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"dbc247c510f8fa6c","traceState":"","parentSpanId":"","name":"client_checkout","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:47.606902016Z","endTime":"2021-03-25T17:21:47.984790016Z","durationInNanos":377888000,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"d5aaa3543c196a7a"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"d5aaa3543c196a7a","traceState":"","parentSpanId":"6860e98ae999b587","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:47.643833856Z","endTime":"2021-03-25T17:21:47.645221376Z","durationInNanos":1387520,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'banana', 'Qty': 2}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"2e6de774f1e5e5c7"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"2e6de774f1e5e5c7","traceState":"","parentSpanId":"b2c8e3bea8c0c6da","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:47.611379968Z","endTime":"2021-03-25T17:21:47.911320576Z","durationInNanos":299940608,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"span.attributes.http@url":"http://localhost:8082/update_inventory","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"b2c8e3bea8c0c6da"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"b2c8e3bea8c0c6da","traceState":"","parentSpanId":"ac6ee7fdcf4b98a3","name":"checkout","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:47.610896128Z","endTime":"2021-03-25T17:21:47.951144448Z","durationInNanos":340248320,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"e0a50216313cc1e6"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"e0a50216313cc1e6","traceState":"","parentSpanId":"6c91acd65cba9a6d","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:47.766609408Z","endTime":"2021-03-25T17:21:47.827251968Z","durationInNanos":60642560,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"span.attributes.http@url":"http://localhost:8083/update_item","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"34f833b94123fbe2"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"34f833b94123fbe2","traceState":"","parentSpanId":"bf3e3de22bfb1397","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:47.796408320Z","endTime":"2021-03-25T17:21:47.797313536Z","durationInNanos":905216,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'apple', 'Qty': 1}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"0acc5f8c05209119"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"0acc5f8c05209119","traceState":"","parentSpanId":"e0a50216313cc1e6","name":"updateItem","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:47.771975936Z","endTime":"2021-03-25T17:21:47.816274688Z","durationInNanos":44298752,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55782,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_item","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/update_item","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"42e7d4b396e9803b"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"42e7d4b396e9803b","traceState":"","parentSpanId":"d00e0bf784079e5f","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:47.927003691Z","endTime":"2021-03-25T17:21:47.935461246Z","durationInNanos":8457555,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-2","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":129,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56506,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"bf3e3de22bfb1397"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"bf3e3de22bfb1397","traceState":"","parentSpanId":"0acc5f8c05209119","name":"update_item","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:47.773264640Z","endTime":"2021-03-25T17:21:47.808190976Z","durationInNanos":34926336,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"6860e98ae999b587"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"6860e98ae999b587","traceState":"","parentSpanId":"b7fa039966521399","name":"update_item","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:47.619275264Z","endTime":"2021-03-25T17:21:47.664597760Z","durationInNanos":45322496,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"a5d5a43a5ca42d60"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"a5d5a43a5ca42d60","traceState":"","parentSpanId":"091b784a264d8a54","name":"update_item","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:47.707945472Z","endTime":"2021-03-25T17:21:47.742619136Z","durationInNanos":34673664,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"48ae0737dcc3a439"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"48ae0737dcc3a439","traceState":"","parentSpanId":"2e6de774f1e5e5c7","name":"update_inventory","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:47.613990912Z","endTime":"2021-03-25T17:21:47.897009920Z","durationInNanos":283019008,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8082,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":45638,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_inventory","span.attributes.http@host":"localhost:8082","span.attributes.http@target":"/update_inventory","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"e8c880db1b019137"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"e8c880db1b019137","traceState":"","parentSpanId":"4db977971d810987","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:47.854917010Z","endTime":"2021-03-25T17:21:47.866128201Z","durationInNanos":11211191,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"span.attributes.thread@name":"http-nio-8087-exec-10","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":137,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"ac6ee7fdcf4b98a3"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"ac6ee7fdcf4b98a3","traceState":"","parentSpanId":"21f66a4f7501d0ed","name":"payment","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:47.609924608Z","endTime":"2021-03-25T17:21:47.959924224Z","durationInNanos":349999616,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8084,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":50378,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/checkout","span.attributes.http@host":"localhost:8084","span.attributes.http@target":"/checkout","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"21f66a4f7501d0ed"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"21f66a4f7501d0ed","traceState":"","parentSpanId":"dbc247c510f8fa6c","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:47.607205632Z","endTime":"2021-03-25T17:21:47.976232192Z","durationInNanos":369026560,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"span.attributes.http@url":"http://localhost:8084/checkout","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"091b784a264d8a54"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"091b784a264d8a54","traceState":"","parentSpanId":"afabcf304a619d61","name":"updateItem","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:47.707056384Z","endTime":"2021-03-25T17:21:47.748450816Z","durationInNanos":41394432,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55778,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_item","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/update_item","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"b7fa039966521399"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"b7fa039966521399","traceState":"","parentSpanId":"c4a09da623eb1ecb","name":"updateItem","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:47.618215680Z","endTime":"2021-03-25T17:21:47.675187200Z","durationInNanos":56971520,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55774,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_item","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/update_item","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"c4a09da623eb1ecb"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"c4a09da623eb1ecb","traceState":"","parentSpanId":"6c91acd65cba9a6d","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:47.615485952Z","endTime":"2021-03-25T17:21:47.693196288Z","durationInNanos":77710336,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"span.attributes.http@url":"http://localhost:8083/update_item","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"51b550897e8d5b54"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"51b550897e8d5b54","traceState":"","parentSpanId":"6c91acd65cba9a6d","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:47.838560512Z","endTime":"2021-03-25T17:21:47.858291712Z","durationInNanos":19731200,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"6c91acd65cba9a6d"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"6c91acd65cba9a6d","traceState":"","parentSpanId":"48ae0737dcc3a439","name":"update_inventory","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:47.614964224Z","endTime":"2021-03-25T17:21:47.890344192Z","durationInNanos":275379968,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"4db977971d810987"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"4db977971d810987","traceState":"","parentSpanId":"51b550897e8d5b54","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:47.854003483Z","endTime":"2021-03-25T17:21:47.866331785Z","durationInNanos":12328302,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-10","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":137,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56504,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"3e9ba08b87cc6da9"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"3e9ba08b87cc6da9","traceState":"","parentSpanId":"42e7d4b396e9803b","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:47.927846737Z","endTime":"2021-03-25T17:21:47.935255710Z","durationInNanos":7408973,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"span.attributes.thread@name":"http-nio-8087-exec-2","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":129,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"d00e0bf784079e5f"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"d00e0bf784079e5f","traceState":"","parentSpanId":"b2c8e3bea8c0c6da","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:47.919819264Z","endTime":"2021-03-25T17:21:47.937713920Z","durationInNanos":17894656,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"c077e0796515ec33"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"c077e0796515ec33","traceState":"","parentSpanId":"a5d5a43a5ca42d60","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:47.730230528Z","endTime":"2021-03-25T17:21:47.731288832Z","durationInNanos":1058304,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'orange', 'Qty': 3}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"afabcf304a619d61"}}
+{"traceId":"1fc75f4679fb60382b8394405f1d3206","spanId":"afabcf304a619d61","traceState":"","parentSpanId":"6c91acd65cba9a6d","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:47.700137728Z","endTime":"2021-03-25T17:21:47.758095104Z","durationInNanos":57957376,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:47.984790016Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":377888000,"span.attributes.http@url":"http://localhost:8083/update_item","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"54035ed549d99079"}}
+{"traceId":"76064f11707d1e0718b0b02a77bff58d","spanId":"54035ed549d99079","traceState":"","parentSpanId":"","name":"client_cancel_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:48.574600192Z","endTime":"2021-03-25T17:21:48.745840640Z","durationInNanos":171240448,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:48.745840640Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":171240448,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"7325aeb5cd30c014"}}
+{"traceId":"76064f11707d1e0718b0b02a77bff58d","spanId":"7325aeb5cd30c014","traceState":"","parentSpanId":"5a71901ca81287ec","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:48.676800988Z","endTime":"2021-03-25T17:21:48.679158178Z","durationInNanos":2357190,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:48.745840640Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":171240448,"span.attributes.thread@name":"http-nio-8087-exec-4","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":131,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"28463ae48643c8b7"}}
+{"traceId":"76064f11707d1e0718b0b02a77bff58d","spanId":"28463ae48643c8b7","traceState":"","parentSpanId":"e25c7f0bee0fdc57","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:48.604971776Z","endTime":"2021-03-25T17:21:48.607241728Z","durationInNanos":2269952,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:48.745840640Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":171240448,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"SELECT ItemId, TotalQty FROM User_Carts","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"b3f658afbe6f7ccf"}}
+{"traceId":"76064f11707d1e0718b0b02a77bff58d","spanId":"b3f658afbe6f7ccf","traceState":"","parentSpanId":"fbfe826f4c2c3bd2","name":"clear_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:48.577446144Z","endTime":"2021-03-25T17:21:48.695392512Z","durationInNanos":117946368,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:48.745840640Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":171240448,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"DELETE","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56776,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/clear_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/clear_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"e25c7f0bee0fdc57"}}
+{"traceId":"76064f11707d1e0718b0b02a77bff58d","spanId":"e25c7f0bee0fdc57","traceState":"","parentSpanId":"9274f8881cde156e","name":"cart_empty","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:48.582540032Z","endTime":"2021-03-25T17:21:48.642361600Z","durationInNanos":59821568,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:48.745840640Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":171240448,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"5a71901ca81287ec"}}
+{"traceId":"76064f11707d1e0718b0b02a77bff58d","spanId":"5a71901ca81287ec","traceState":"","parentSpanId":"271acd6e6d28e189","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:48.676003585Z","endTime":"2021-03-25T17:21:48.679356137Z","durationInNanos":3352552,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:48.745840640Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":171240448,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-4","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":131,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56514,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"6cb05117cdb01f88"}}
+{"traceId":"76064f11707d1e0718b0b02a77bff58d","spanId":"6cb05117cdb01f88","traceState":"","parentSpanId":"48ccdcea24b8a347","name":"HTTP PUT","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:48.578734592Z","endTime":"2021-03-25T17:21:48.664337408Z","durationInNanos":85602816,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:48.745840640Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":171240448,"span.attributes.http@url":"http://localhost:8083/cart_empty","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"PUT","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"271acd6e6d28e189"}}
+{"traceId":"76064f11707d1e0718b0b02a77bff58d","spanId":"271acd6e6d28e189","traceState":"","parentSpanId":"48ccdcea24b8a347","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:48.672167936Z","endTime":"2021-03-25T17:21:48.681381632Z","durationInNanos":9213696,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:48.745840640Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":171240448,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"9274f8881cde156e"}}
+{"traceId":"76064f11707d1e0718b0b02a77bff58d","spanId":"9274f8881cde156e","traceState":"","parentSpanId":"6cb05117cdb01f88","name":"cartEmpty","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:48.581450752Z","endTime":"2021-03-25T17:21:48.651885056Z","durationInNanos":70434304,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:48.745840640Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":171240448,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"PUT","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55792,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/cart_empty","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/cart_empty","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"fbfe826f4c2c3bd2"}}
+{"traceId":"76064f11707d1e0718b0b02a77bff58d","spanId":"fbfe826f4c2c3bd2","traceState":"","parentSpanId":"54035ed549d99079","name":"HTTP DELETE","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:48.574898432Z","endTime":"2021-03-25T17:21:48.737892096Z","durationInNanos":162993664,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:48.745840640Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":171240448,"span.attributes.http@url":"http://localhost:8088/clear_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"DELETE","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"7ec1853748fda8ff"}}
+{"traceId":"76064f11707d1e0718b0b02a77bff58d","spanId":"7ec1853748fda8ff","traceState":"","parentSpanId":"e25c7f0bee0fdc57","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:48.614138368Z","endTime":"2021-03-25T17:21:48.636585728Z","durationInNanos":22447360,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:48.745840640Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":171240448,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"TRUNCATE TABLE User_Carts","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"48ccdcea24b8a347"}}
+{"traceId":"76064f11707d1e0718b0b02a77bff58d","spanId":"48ccdcea24b8a347","traceState":"","parentSpanId":"b3f658afbe6f7ccf","name":"clear_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:48.578475264Z","endTime":"2021-03-25T17:21:48.688380928Z","durationInNanos":109905664,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:48.745840640Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":171240448,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"c31fccfac7074ab0"}}
+{"traceId":"e5ca67df0bbdb779bd1846f138439bce","spanId":"c31fccfac7074ab0","traceState":"","parentSpanId":"","name":"client_create_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:49.258101504Z","endTime":"2021-03-25T17:21:49.531125504Z","durationInNanos":273024000,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:49.531125504Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":273024000,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"4ecdda1d6bd123a5"}}
+{"traceId":"e5ca67df0bbdb779bd1846f138439bce","spanId":"4ecdda1d6bd123a5","traceState":"","parentSpanId":"2d8bb1f183215851","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:49.440151040Z","endTime":"2021-03-25T17:21:49.441044224Z","durationInNanos":893184,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:49.531125504Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":273024000,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'banana', 'Qty': '2'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"93cf47c8e681c60f"}}
+{"traceId":"e5ca67df0bbdb779bd1846f138439bce","spanId":"93cf47c8e681c60f","traceState":"","parentSpanId":"e2811a70a83b29da","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:49.487172608Z","endTime":"2021-03-25T17:21:49.497463552Z","durationInNanos":10290944,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:49.531125504Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":273024000,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"a0e52e16bb92338c"}}
+{"traceId":"e5ca67df0bbdb779bd1846f138439bce","spanId":"a0e52e16bb92338c","traceState":"","parentSpanId":"c31fccfac7074ab0","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:49.258438144Z","endTime":"2021-03-25T17:21:49.524093952Z","durationInNanos":265655808,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:49.531125504Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":273024000,"span.attributes.http@url":"http://localhost:8088/update_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"f0b38747a78a5590"}}
+{"traceId":"e5ca67df0bbdb779bd1846f138439bce","spanId":"f0b38747a78a5590","traceState":"","parentSpanId":"a0e52e16bb92338c","name":"update_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:49.261078528Z","endTime":"2021-03-25T17:21:49.510315008Z","durationInNanos":249236480,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:49.531125504Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":273024000,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56784,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/update_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"309f43ae9cab572b"}}
+{"traceId":"e5ca67df0bbdb779bd1846f138439bce","spanId":"309f43ae9cab572b","traceState":"","parentSpanId":"e2811a70a83b29da","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:49.412836352Z","endTime":"2021-03-25T17:21:49.476348928Z","durationInNanos":63512576,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:49.531125504Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":273024000,"span.attributes.http@url":"http://localhost:8083/add_item_to_cart","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"e2811a70a83b29da"}}
+{"traceId":"e5ca67df0bbdb779bd1846f138439bce","spanId":"e2811a70a83b29da","traceState":"","parentSpanId":"f0b38747a78a5590","name":"update_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:49.262012416Z","endTime":"2021-03-25T17:21:49.504557312Z","durationInNanos":242544896,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:49.531125504Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":273024000,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"0e369cfafd635987"}}
+{"traceId":"e5ca67df0bbdb779bd1846f138439bce","spanId":"0e369cfafd635987","traceState":"","parentSpanId":"d6e195ff0adc561a","name":"add_item_to_cart","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:49.266362880Z","endTime":"2021-03-25T17:21:49.313359104Z","durationInNanos":46996224,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:49.531125504Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":273024000,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"52ce5eedf9f848fd"}}
+{"traceId":"e5ca67df0bbdb779bd1846f138439bce","spanId":"52ce5eedf9f848fd","traceState":"","parentSpanId":"0e369cfafd635987","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:49.298149376Z","endTime":"2021-03-25T17:21:49.300026112Z","durationInNanos":1876736,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:49.531125504Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":273024000,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'apple', 'Qty': '1'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"INSERT INTO User_Carts (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"d6e195ff0adc561a"}}
+{"traceId":"e5ca67df0bbdb779bd1846f138439bce","spanId":"d6e195ff0adc561a","traceState":"","parentSpanId":"a70984b8c786c65b","name":"addItemToCart","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:49.265307648Z","endTime":"2021-03-25T17:21:49.321311488Z","durationInNanos":56003840,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:49.531125504Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":273024000,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55800,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/add_item_to_cart","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/add_item_to_cart","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"a70984b8c786c65b"}}
+{"traceId":"e5ca67df0bbdb779bd1846f138439bce","spanId":"a70984b8c786c65b","traceState":"","parentSpanId":"e2811a70a83b29da","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:49.262542080Z","endTime":"2021-03-25T17:21:49.332455424Z","durationInNanos":69913344,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:49.531125504Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":273024000,"span.attributes.http@url":"http://localhost:8083/add_item_to_cart","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"675650382e9c1c68"}}
+{"traceId":"e5ca67df0bbdb779bd1846f138439bce","spanId":"675650382e9c1c68","traceState":"","parentSpanId":"005c234e8b2d4a9e","name":"add_item_to_cart","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:49.343079424Z","endTime":"2021-03-25T17:21:49.387046656Z","durationInNanos":43967232,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:49.531125504Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":273024000,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"2d8bb1f183215851"}}
+{"traceId":"e5ca67df0bbdb779bd1846f138439bce","spanId":"2d8bb1f183215851","traceState":"","parentSpanId":"f03815533b30bc89","name":"add_item_to_cart","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:49.417788160Z","endTime":"2021-03-25T17:21:49.459834880Z","durationInNanos":42046720,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:49.531125504Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":273024000,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"1b4b9bcc546ab0c0"}}
+{"traceId":"e5ca67df0bbdb779bd1846f138439bce","spanId":"1b4b9bcc546ab0c0","traceState":"","parentSpanId":"93cf47c8e681c60f","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:49.492002870Z","endTime":"2021-03-25T17:21:49.500860714Z","durationInNanos":8857844,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:49.531125504Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":273024000,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-6","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":133,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56530,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"f03815533b30bc89"}}
+{"traceId":"e5ca67df0bbdb779bd1846f138439bce","spanId":"f03815533b30bc89","traceState":"","parentSpanId":"309f43ae9cab572b","name":"addItemToCart","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:49.416881152Z","endTime":"2021-03-25T17:21:49.466066688Z","durationInNanos":49185536,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:49.531125504Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":273024000,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55808,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/add_item_to_cart","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/add_item_to_cart","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"d8f75a62dc93bb44"}}
+{"traceId":"e5ca67df0bbdb779bd1846f138439bce","spanId":"d8f75a62dc93bb44","traceState":"","parentSpanId":"0e369cfafd635987","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:49.288495616Z","endTime":"2021-03-25T17:21:49.289379840Z","durationInNanos":884224,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:49.531125504Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":273024000,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'apple', 'Qty': '1'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"3886c807af86de35"}}
+{"traceId":"e5ca67df0bbdb779bd1846f138439bce","spanId":"3886c807af86de35","traceState":"","parentSpanId":"675650382e9c1c68","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:49.374640128Z","endTime":"2021-03-25T17:21:49.375667968Z","durationInNanos":1027840,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:49.531125504Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":273024000,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'orange', 'Qty': '3'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"INSERT INTO User_Carts (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"1f635f8d3eaabed5"}}
+{"traceId":"e5ca67df0bbdb779bd1846f138439bce","spanId":"1f635f8d3eaabed5","traceState":"","parentSpanId":"1b4b9bcc546ab0c0","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:49.493967540Z","endTime":"2021-03-25T17:21:49.500642788Z","durationInNanos":6675248,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:49.531125504Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":273024000,"span.attributes.thread@name":"http-nio-8087-exec-6","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":133,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"005c234e8b2d4a9e"}}
+{"traceId":"e5ca67df0bbdb779bd1846f138439bce","spanId":"005c234e8b2d4a9e","traceState":"","parentSpanId":"fc28883b621642e2","name":"addItemToCart","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:49.342033664Z","endTime":"2021-03-25T17:21:49.396767744Z","durationInNanos":54734080,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:49.531125504Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":273024000,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55804,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/add_item_to_cart","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/add_item_to_cart","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"b845c9f96d0ff1f3"}}
+{"traceId":"e5ca67df0bbdb779bd1846f138439bce","spanId":"b845c9f96d0ff1f3","traceState":"","parentSpanId":"675650382e9c1c68","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:49.365459968Z","endTime":"2021-03-25T17:21:49.366375936Z","durationInNanos":915968,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:49.531125504Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":273024000,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'orange', 'Qty': '3'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"fc28883b621642e2"}}
+{"traceId":"e5ca67df0bbdb779bd1846f138439bce","spanId":"fc28883b621642e2","traceState":"","parentSpanId":"e2811a70a83b29da","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:49.339384576Z","endTime":"2021-03-25T17:21:49.406950656Z","durationInNanos":67566080,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:49.531125504Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":273024000,"span.attributes.http@url":"http://localhost:8083/add_item_to_cart","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"5ce303d8b91011bc"}}
+{"traceId":"e5ca67df0bbdb779bd1846f138439bce","spanId":"5ce303d8b91011bc","traceState":"","parentSpanId":"2d8bb1f183215851","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:49.447627776Z","endTime":"2021-03-25T17:21:49.449848064Z","durationInNanos":2220288,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:49.531125504Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":273024000,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'banana', 'Qty': '2'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"INSERT INTO User_Carts (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"8a854623f90fb54f"}}
+{"traceId":"5ee77a65f251ed8600371446157e70dc","spanId":"8a854623f90fb54f","traceState":"","parentSpanId":"","name":"client_delivery_status","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:49.845881856Z","endTime":"2021-03-25T17:21:49.984027648Z","durationInNanos":138145792,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:21:49.984027648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":138145792,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"d57cf256040644f3"}}
+{"traceId":"5ee77a65f251ed8600371446157e70dc","spanId":"d57cf256040644f3","traceState":"","parentSpanId":"8a854623f90fb54f","name":"HTTP GET","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:49.846182912Z","endTime":"2021-03-25T17:21:49.952503296Z","durationInNanos":106320384,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:21:49.984027648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":138145792,"span.attributes.http@url":"http://localhost:8088/get_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"GET","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"7a2a0ca635baf4db"}}
+{"traceId":"5ee77a65f251ed8600371446157e70dc","spanId":"7a2a0ca635baf4db","traceState":"","parentSpanId":"500db987681d8ede","name":"get_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:49.849632768Z","endTime":"2021-03-25T17:21:49.926034688Z","durationInNanos":76401920,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:21:49.984027648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":138145792,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"5653e07ba17cbd8b"}}
+{"traceId":"5ee77a65f251ed8600371446157e70dc","spanId":"5653e07ba17cbd8b","traceState":"","parentSpanId":"7a2a0ca635baf4db","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:49.912790272Z","endTime":"2021-03-25T17:21:49.920825088Z","durationInNanos":8034816,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:21:49.984027648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":138145792,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"5bf67d699fe6d247"}}
+{"traceId":"5ee77a65f251ed8600371446157e70dc","spanId":"5bf67d699fe6d247","traceState":"","parentSpanId":"1d505c87dea42700","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:49.915879531Z","endTime":"2021-03-25T17:21:49.918056080Z","durationInNanos":2176549,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:21:49.984027648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":138145792,"span.attributes.thread@name":"http-nio-8087-exec-8","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":135,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"1d505c87dea42700"}}
+{"traceId":"5ee77a65f251ed8600371446157e70dc","spanId":"1d505c87dea42700","traceState":"","parentSpanId":"5653e07ba17cbd8b","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:49.915003530Z","endTime":"2021-03-25T17:21:49.918236011Z","durationInNanos":3232481,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:21:49.984027648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":138145792,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-8","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":135,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56538,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"caee48dba4382c02"}}
+{"traceId":"5ee77a65f251ed8600371446157e70dc","spanId":"caee48dba4382c02","traceState":"","parentSpanId":"52fa1c07d9e504c9","name":"getCart","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:49.852563456Z","endTime":"2021-03-25T17:21:49.889665792Z","durationInNanos":37102336,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:21:49.984027648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":138145792,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"GET","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55816,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/get_cart","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/get_cart","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"6ddf636a43d5d36d"}}
+{"traceId":"5ee77a65f251ed8600371446157e70dc","spanId":"6ddf636a43d5d36d","traceState":"","parentSpanId":"235766a9328bb23e","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:49.875479296Z","endTime":"2021-03-25T17:21:49.876210944Z","durationInNanos":731648,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:21:49.984027648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":138145792,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"SELECT * FROM User_Carts","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"52fa1c07d9e504c9"}}
+{"traceId":"5ee77a65f251ed8600371446157e70dc","spanId":"52fa1c07d9e504c9","traceState":"","parentSpanId":"7a2a0ca635baf4db","name":"HTTP GET","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:49.849892608Z","endTime":"2021-03-25T17:21:49.903207168Z","durationInNanos":53314560,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:21:49.984027648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":138145792,"span.attributes.http@url":"http://localhost:8083/get_cart","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"GET","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"500db987681d8ede"}}
+{"traceId":"5ee77a65f251ed8600371446157e70dc","spanId":"500db987681d8ede","traceState":"","parentSpanId":"d57cf256040644f3","name":"get_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:49.848685312Z","endTime":"2021-03-25T17:21:49.932677376Z","durationInNanos":83992064,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:21:49.984027648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":138145792,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"GET","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56800,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/get_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/get_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"235766a9328bb23e"}}
+{"traceId":"5ee77a65f251ed8600371446157e70dc","spanId":"235766a9328bb23e","traceState":"","parentSpanId":"caee48dba4382c02","name":"get_cart","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:49.853675520Z","endTime":"2021-03-25T17:21:49.883213056Z","durationInNanos":29537536,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:21:49.984027648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":138145792,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"6b14ed5be4c88e99"}}
+{"traceId":"ba3c828db75aee377b6fbebb58d6b6d3","spanId":"6b14ed5be4c88e99","traceState":"","parentSpanId":"","name":"mysql","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:02.990599936Z","endTime":"2021-03-25T17:21:02.991838464Z","durationInNanos":1238528,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"mysql","traceGroupFields.endTime":"2021-03-25T17:21:02.991838464Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":1238528,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"","span.attributes.db@statement":"USE APM","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"55a698828fe06a42"}}
+{"traceId":"c1d985bd02e1dbb85b444011f19a1ecc","spanId":"55a698828fe06a42","traceState":"","parentSpanId":"","name":"mysql","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:03.000792576Z","endTime":"2021-03-25T17:21:03.023983360Z","durationInNanos":23190784,"serviceName":"database","events":[{"time":"2021-03-25T17:21:03.023934720Z","name":"exception","attributes":{"exception@message":"1050 (42S01): Table 'Inventory_Items' already exists","exception@type":"ProgrammingError","exception@stacktrace":"Traceback (most recent call last):\n File \"/usr/lib/python3.6/site-packages/opentelemetry/sdk/trace/__init__.py\", line 804, in use_span\n yield span\n File \"/usr/lib/python3.6/site-packages/opentelemetry/instrumentation/dbapi/__init__.py\", line 354, in traced_execution\n raise ex\n File \"/usr/lib/python3.6/site-packages/opentelemetry/instrumentation/dbapi/__init__.py\", line 345, in traced_execution\n result = query_method(*args, **kwargs)\n File \"/usr/lib/python3.6/site-packages/mysql/connector/cursor.py\", line 577, in execute\n self._handle_result(self._connection.cmd_query(stmt))\n File \"/usr/lib/python3.6/site-packages/mysql/connector/connection.py\", line 695, in cmd_query\n result = self._handle_result(self._send_cmd(ServerCmd.QUERY, query))\n File \"/usr/lib/python3.6/site-packages/mysql/connector/connection.py\", line 582, in _handle_result\n raise errors.get_exception(packet)\nmysql.connector.errors.ProgrammingError: 1050 (42S01): Table 'Inventory_Items' already exists\n"},"droppedAttributesCount":0}],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"mysql","traceGroupFields.endTime":"2021-03-25T17:21:03.023983360Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":23190784,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","status.message":"1050 (42S01): Table 'Inventory_Items' already exists","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":2,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"","span.attributes.db@statement":"CREATE TABLE `Inventory_Items` ( `ItemId` varchar(16) NOT NULL, `TotalQty` int(11) NOT NULL, PRIMARY KEY (`ItemId`)) ENGINE=InnoDB","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"5bcca8ba513bb54a"}}
+{"traceId":"15d30e4d211d79e10fcaeab97015c90d","spanId":"5bcca8ba513bb54a","traceState":"","parentSpanId":"","name":"mysql","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:03.038618112Z","endTime":"2021-03-25T17:21:03.041571328Z","durationInNanos":2953216,"serviceName":"database","events":[{"time":"2021-03-25T17:21:03.041542912Z","name":"exception","attributes":{"exception@message":"1050 (42S01): Table 'User_Carts' already exists","exception@type":"ProgrammingError","exception@stacktrace":"Traceback (most recent call last):\n File \"/usr/lib/python3.6/site-packages/opentelemetry/sdk/trace/__init__.py\", line 804, in use_span\n yield span\n File \"/usr/lib/python3.6/site-packages/opentelemetry/instrumentation/dbapi/__init__.py\", line 354, in traced_execution\n raise ex\n File \"/usr/lib/python3.6/site-packages/opentelemetry/instrumentation/dbapi/__init__.py\", line 345, in traced_execution\n result = query_method(*args, **kwargs)\n File \"/usr/lib/python3.6/site-packages/mysql/connector/cursor.py\", line 577, in execute\n self._handle_result(self._connection.cmd_query(stmt))\n File \"/usr/lib/python3.6/site-packages/mysql/connector/connection.py\", line 695, in cmd_query\n result = self._handle_result(self._send_cmd(ServerCmd.QUERY, query))\n File \"/usr/lib/python3.6/site-packages/mysql/connector/connection.py\", line 582, in _handle_result\n raise errors.get_exception(packet)\nmysql.connector.errors.ProgrammingError: 1050 (42S01): Table 'User_Carts' already exists\n"},"droppedAttributesCount":0}],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"mysql","traceGroupFields.endTime":"2021-03-25T17:21:03.041571328Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":2953216,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","status.message":"1050 (42S01): Table 'User_Carts' already exists","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":2,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"","span.attributes.db@statement":"CREATE TABLE `User_Carts` ( `ItemId` varchar(16) NOT NULL, `TotalQty` int(11) NOT NULL, PRIMARY KEY (`ItemId`)) ENGINE=InnoDB","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"8ee1d294e46f34bf"}}
+{"traceId":"b207e9bcd70e5b49daea3a40e0c60e4c","spanId":"8ee1d294e46f34bf","traceState":"","parentSpanId":"","name":"HTTP GET","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:03.304552704Z","endTime":"2021-03-25T17:21:03.307507968Z","durationInNanos":2955264,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"HTTP GET","traceGroupFields.endTime":"2021-03-25T17:21:03.307507968Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":2955264,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"NOT FOUND","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":2,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"GET","span.attributes.http@user_agent":"curl/7.61.1","span.attributes.net@peer@port":55638,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":404}
+{"index":{"_id":"5ff3516909562c60"}}
+{"traceId":"d5409f0d4ed15dfe47afe24d4988d078","spanId":"5ff3516909562c60","traceState":"","parentSpanId":"","name":"HTTP GET","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:04.377200384Z","endTime":"2021-03-25T17:21:04.381007104Z","durationInNanos":3806720,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"HTTP GET","traceGroupFields.endTime":"2021-03-25T17:21:04.381007104Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":3806720,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"NOT FOUND","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":2,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"GET","span.attributes.http@user_agent":"curl/7.61.1","span.attributes.net@peer@port":56628,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":404}
+{"index":{"_id":"72ee42547c5c5125"}}
+{"traceId":"3cacf76df174d71c19a5ff78248cd490","spanId":"72ee42547c5c5125","traceState":"","parentSpanId":"","name":"HTTP GET","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:05.416123648Z","endTime":"2021-03-25T17:21:05.419973376Z","durationInNanos":3849728,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"HTTP GET","traceGroupFields.endTime":"2021-03-25T17:21:05.419973376Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":3849728,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8082,"span.attributes.http@status_text":"NOT FOUND","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":2,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"GET","span.attributes.http@user_agent":"curl/7.61.1","span.attributes.net@peer@port":45514,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@host":"localhost:8082","span.attributes.http@target":"/","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":404}
+{"index":{"_id":"1bcd486350ea581e"}}
+{"traceId":"29158720fe1cf7db0a8c45067945d94d","spanId":"1bcd486350ea581e","traceState":"","parentSpanId":"","name":"HTTP GET","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:06.498122240Z","endTime":"2021-03-25T17:21:06.514853888Z","durationInNanos":16731648,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"HTTP GET","traceGroupFields.endTime":"2021-03-25T17:21:06.514853888Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":16731648,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8084,"span.attributes.http@status_text":"NOT FOUND","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","span.attributes.component":"http","status.code":2,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"GET","span.attributes.http@user_agent":"curl/7.61.1","span.attributes.net@peer@port":50262,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@host":"localhost:8084","span.attributes.http@target":"/","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":404}
+{"index":{"_id":"e1ba7015b9194eba"}}
+{"traceId":"648058570b784b90c1c596d7a6d14c54","spanId":"e1ba7015b9194eba","traceState":"","parentSpanId":"","name":"/**","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:01.992579399Z","endTime":"2021-03-25T17:21:02.049460860Z","durationInNanos":56881461,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"/**","traceGroupFields.endTime":"2021-03-25T17:21:02.049460860Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":56881461,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/","span.attributes.thread@name":"http-nio-8087-exec-1","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":128,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":2,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"GET","span.attributes.http@user_agent":"curl/7.61.1","span.attributes.net@peer@port":56348,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":404,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"1eaf4782819b853d"}}
+{"traceId":"648058570b784b90c1c596d7a6d14c54","spanId":"1eaf4782819b853d","traceState":"","parentSpanId":"5494c2e7d070507f","name":"ResponseFacade.sendError","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:02.045710038Z","endTime":"2021-03-25T17:21:02.045931096Z","durationInNanos":221058,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"/**","traceGroupFields.endTime":"2021-03-25T17:21:02.049460860Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":56881461,"span.attributes.thread@name":"http-nio-8087-exec-1","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":128,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet"}
+{"index":{"_id":"0c71ce2f032ad48e"}}
+{"traceId":"648058570b784b90c1c596d7a6d14c54","spanId":"0c71ce2f032ad48e","traceState":"","parentSpanId":"e1ba7015b9194eba","name":"ApplicationDispatcher.forward","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:02.053502985Z","endTime":"2021-03-25T17:21:02.262349094Z","durationInNanos":208846109,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"/**","traceGroupFields.endTime":"2021-03-25T17:21:02.049460860Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":56881461,"span.attributes.thread@name":"http-nio-8087-exec-1","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":128,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet"}
+{"index":{"_id":"5494c2e7d070507f"}}
+{"traceId":"648058570b784b90c1c596d7a6d14c54","spanId":"5494c2e7d070507f","traceState":"","parentSpanId":"e1ba7015b9194eba","name":"ResourceHttpRequestHandler.handleRequest","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:02.043354145Z","endTime":"2021-03-25T17:21:02.048099869Z","durationInNanos":4745724,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"/**","traceGroupFields.endTime":"2021-03-25T17:21:02.049460860Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":56881461,"span.attributes.thread@name":"http-nio-8087-exec-1","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":128,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"3ce2f80841493cbb"}}
+{"traceId":"450905d31307509532d9e2db7460fcb6","spanId":"3ce2f80841493cbb","traceState":"","parentSpanId":"","name":"HTTP GET","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:07.595561728Z","endTime":"2021-03-25T17:21:07.599333376Z","durationInNanos":3771648,"serviceName":"recommendation","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"HTTP GET","traceGroupFields.endTime":"2021-03-25T17:21:07.599333376Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":3771648,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8086,"span.attributes.http@status_text":"NOT FOUND","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140465266593744","resource.attributes.service@name":"recommendation","span.attributes.component":"http","status.code":2,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"GET","span.attributes.http@user_agent":"curl/7.61.1","span.attributes.net@peer@port":51118,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@host":"localhost:8086","span.attributes.http@target":"/","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":404}
+{"index":{"_id":"718dc32a693c8a17"}}
+{"traceId":"c81499c3007a8532a987c27047bb9cdd","spanId":"718dc32a693c8a17","traceState":"","parentSpanId":"","name":"HTTP GET","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:08.627664384Z","endTime":"2021-03-25T17:21:08.631421696Z","durationInNanos":3757312,"serviceName":"authentication","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"HTTP GET","traceGroupFields.endTime":"2021-03-25T17:21:08.631421696Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":3757312,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8085,"span.attributes.http@status_text":"NOT FOUND","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140122129537568","resource.attributes.service@name":"authentication","span.attributes.component":"http","status.code":2,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"GET","span.attributes.http@user_agent":"curl/7.61.1","span.attributes.net@peer@port":44150,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@host":"localhost:8085","span.attributes.http@target":"/","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":404}
+{"index":{"_id":"28f096bc84619ef2"}}
+{"traceId":"4cb0014c4d311691da84b0fcbb649796","spanId":"28f096bc84619ef2","traceState":"","parentSpanId":"","name":"load_main_screen","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:14.559582720Z","endTime":"2021-03-25T17:21:15.017436928Z","durationInNanos":457854208,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"load_main_screen","traceGroupFields.endTime":"2021-03-25T17:21:15.017436928Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":457854208,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"69a2949c11c65a77"}}
+{"traceId":"4cb0014c4d311691da84b0fcbb649796","spanId":"69a2949c11c65a77","traceState":"","parentSpanId":"48ab433d50014cbe","name":"recommend","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:14.581978880Z","endTime":"2021-03-25T17:21:14.920316160Z","durationInNanos":338337280,"serviceName":"recommendation","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"load_main_screen","traceGroupFields.endTime":"2021-03-25T17:21:15.017436928Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":457854208,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8086,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140465266593744","resource.attributes.service@name":"recommendation","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"GET","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":51138,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/recommend","span.attributes.http@host":"localhost:8086","span.attributes.http@target":"/recommend","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"3cec59b11f5d84fa"}}
+{"traceId":"4cb0014c4d311691da84b0fcbb649796","spanId":"3cec59b11f5d84fa","traceState":"","parentSpanId":"4c9af7d9bc4961cc","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:14.678003676Z","endTime":"2021-03-25T17:21:14.815579605Z","durationInNanos":137575929,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"load_main_screen","traceGroupFields.endTime":"2021-03-25T17:21:15.017436928Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":457854208,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-2","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":129,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56408,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"277a5934acf55dcf"}}
+{"traceId":"4cb0014c4d311691da84b0fcbb649796","spanId":"277a5934acf55dcf","traceState":"","parentSpanId":"d03fecfa0f55b77c","name":"verify_login","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:14.566578432Z","endTime":"2021-03-25T17:21:14.566626304Z","durationInNanos":47872,"serviceName":"authentication","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"load_main_screen","traceGroupFields.endTime":"2021-03-25T17:21:15.017436928Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":457854208,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140122129537568","resource.attributes.service@name":"authentication","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"59182c75e7b7289a"}}
+{"traceId":"4cb0014c4d311691da84b0fcbb649796","spanId":"59182c75e7b7289a","traceState":"","parentSpanId":"1aef01694e12e529","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:14.618924032Z","endTime":"2021-03-25T17:21:14.619691008Z","durationInNanos":766976,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"load_main_screen","traceGroupFields.endTime":"2021-03-25T17:21:15.017436928Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":457854208,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"SELECT * FROM Inventory_Items","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"b57ce805362f7790"}}
+{"traceId":"4cb0014c4d311691da84b0fcbb649796","spanId":"b57ce805362f7790","traceState":"","parentSpanId":"0b62a0dc48347737","name":"getIntentory","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:14.594951168Z","endTime":"2021-03-25T17:21:14.646179072Z","durationInNanos":51227904,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"load_main_screen","traceGroupFields.endTime":"2021-03-25T17:21:15.017436928Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":457854208,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"GET","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55686,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/get_inventory","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/get_inventory","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"01c9ce32ee706927"}}
+{"traceId":"4cb0014c4d311691da84b0fcbb649796","spanId":"01c9ce32ee706927","traceState":"","parentSpanId":"69a2949c11c65a77","name":"recommend","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:14.583037440Z","endTime":"2021-03-25T17:21:14.908792576Z","durationInNanos":325755136,"serviceName":"recommendation","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"load_main_screen","traceGroupFields.endTime":"2021-03-25T17:21:15.017436928Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":457854208,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140465266593744","resource.attributes.service@name":"recommendation","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"5e94ade6b01c39ab"}}
+{"traceId":"4cb0014c4d311691da84b0fcbb649796","spanId":"5e94ade6b01c39ab","traceState":"","parentSpanId":"01c9ce32ee706927","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:14.851265024Z","endTime":"2021-03-25T17:21:14.896640512Z","durationInNanos":45375488,"serviceName":"recommendation","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"load_main_screen","traceGroupFields.endTime":"2021-03-25T17:21:15.017436928Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":457854208,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140465266593744","resource.attributes.service@name":"recommendation","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"f666a1d3fbbe538f"}}
+{"traceId":"4cb0014c4d311691da84b0fcbb649796","spanId":"f666a1d3fbbe538f","traceState":"","parentSpanId":"68a74776159d7f19","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:14.960927106Z","endTime":"2021-03-25T17:21:14.963257076Z","durationInNanos":2329970,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"load_main_screen","traceGroupFields.endTime":"2021-03-25T17:21:15.017436928Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":457854208,"span.attributes.thread@name":"http-nio-8087-exec-6","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":133,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"8a6144390c29b1ec"}}
+{"traceId":"4cb0014c4d311691da84b0fcbb649796","spanId":"8a6144390c29b1ec","traceState":"","parentSpanId":"d99fac2b5eb511e4","name":"read_inventory","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:14.589584640Z","endTime":"2021-03-25T17:21:14.823812608Z","durationInNanos":234227968,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"load_main_screen","traceGroupFields.endTime":"2021-03-25T17:21:15.017436928Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":457854208,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"48ab433d50014cbe"}}
+{"traceId":"4cb0014c4d311691da84b0fcbb649796","spanId":"48ab433d50014cbe","traceState":"","parentSpanId":"d03fecfa0f55b77c","name":"HTTP GET","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:14.576976128Z","endTime":"2021-03-25T17:21:14.945266432Z","durationInNanos":368290304,"serviceName":"authentication","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"load_main_screen","traceGroupFields.endTime":"2021-03-25T17:21:15.017436928Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":457854208,"span.attributes.http@url":"http://localhost:8086/recommend","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140122129537568","resource.attributes.service@name":"authentication","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"GET","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"68a74776159d7f19"}}
+{"traceId":"4cb0014c4d311691da84b0fcbb649796","spanId":"68a74776159d7f19","traceState":"","parentSpanId":"6af54de5eb15c6da","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:14.960003661Z","endTime":"2021-03-25T17:21:14.963455163Z","durationInNanos":3451502,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"load_main_screen","traceGroupFields.endTime":"2021-03-25T17:21:15.017436928Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":457854208,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-6","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":133,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56412,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"d99fac2b5eb511e4"}}
+{"traceId":"4cb0014c4d311691da84b0fcbb649796","spanId":"d99fac2b5eb511e4","traceState":"","parentSpanId":"cc62f643157da23b","name":"read_inventory","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:14.588622080Z","endTime":"2021-03-25T17:21:14.829069056Z","durationInNanos":240446976,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"load_main_screen","traceGroupFields.endTime":"2021-03-25T17:21:15.017436928Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":457854208,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8082,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"GET","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":45550,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/read_inventory","span.attributes.http@host":"localhost:8082","span.attributes.http@target":"/read_inventory","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"6af54de5eb15c6da"}}
+{"traceId":"4cb0014c4d311691da84b0fcbb649796","spanId":"6af54de5eb15c6da","traceState":"","parentSpanId":"d03fecfa0f55b77c","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:14.957758976Z","endTime":"2021-03-25T17:21:14.967944448Z","durationInNanos":10185472,"serviceName":"authentication","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"load_main_screen","traceGroupFields.endTime":"2021-03-25T17:21:15.017436928Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":457854208,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140122129537568","resource.attributes.service@name":"authentication","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"69a731074a9bdf13"}}
+{"traceId":"4cb0014c4d311691da84b0fcbb649796","spanId":"69a731074a9bdf13","traceState":"","parentSpanId":"f62cd2694115a885","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:14.856992146Z","endTime":"2021-03-25T17:21:14.900501999Z","durationInNanos":43509853,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"load_main_screen","traceGroupFields.endTime":"2021-03-25T17:21:15.017436928Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":457854208,"span.attributes.thread@name":"http-nio-8087-exec-4","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":131,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"f62cd2694115a885"}}
+{"traceId":"4cb0014c4d311691da84b0fcbb649796","spanId":"f62cd2694115a885","traceState":"","parentSpanId":"5e94ade6b01c39ab","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:14.856003651Z","endTime":"2021-03-25T17:21:14.901306943Z","durationInNanos":45303292,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"load_main_screen","traceGroupFields.endTime":"2021-03-25T17:21:15.017436928Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":457854208,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-4","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":131,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56410,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"0b62a0dc48347737"}}
+{"traceId":"4cb0014c4d311691da84b0fcbb649796","spanId":"0b62a0dc48347737","traceState":"","parentSpanId":"8a6144390c29b1ec","name":"HTTP GET","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:14.589961984Z","endTime":"2021-03-25T17:21:14.658458368Z","durationInNanos":68496384,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"load_main_screen","traceGroupFields.endTime":"2021-03-25T17:21:15.017436928Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":457854208,"span.attributes.http@url":"http://localhost:8083/get_inventory","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"GET","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"4c9af7d9bc4961cc"}}
+{"traceId":"4cb0014c4d311691da84b0fcbb649796","spanId":"4c9af7d9bc4961cc","traceState":"","parentSpanId":"8a6144390c29b1ec","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:14.672780544Z","endTime":"2021-03-25T17:21:14.816105216Z","durationInNanos":143324672,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"load_main_screen","traceGroupFields.endTime":"2021-03-25T17:21:15.017436928Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":457854208,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"e9e09c3ce939b488"}}
+{"traceId":"4cb0014c4d311691da84b0fcbb649796","spanId":"e9e09c3ce939b488","traceState":"","parentSpanId":"28f096bc84619ef2","name":"HTTP GET","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:14.560204544Z","endTime":"2021-03-25T17:21:15.010031360Z","durationInNanos":449826816,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"load_main_screen","traceGroupFields.endTime":"2021-03-25T17:21:15.017436928Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":457854208,"span.attributes.http@url":"http://localhost:8085/server_request_login","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"GET","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"e258f824e8f8bcb4"}}
+{"traceId":"4cb0014c4d311691da84b0fcbb649796","spanId":"e258f824e8f8bcb4","traceState":"","parentSpanId":"3cec59b11f5d84fa","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:14.679095501Z","endTime":"2021-03-25T17:21:14.815378442Z","durationInNanos":136282941,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"load_main_screen","traceGroupFields.endTime":"2021-03-25T17:21:15.017436928Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":457854208,"span.attributes.thread@name":"http-nio-8087-exec-2","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":129,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"cc62f643157da23b"}}
+{"traceId":"4cb0014c4d311691da84b0fcbb649796","spanId":"cc62f643157da23b","traceState":"","parentSpanId":"01c9ce32ee706927","name":"HTTP GET","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:14.583482368Z","endTime":"2021-03-25T17:21:14.843803648Z","durationInNanos":260321280,"serviceName":"recommendation","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"load_main_screen","traceGroupFields.endTime":"2021-03-25T17:21:15.017436928Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":457854208,"span.attributes.http@url":"http://localhost:8082/read_inventory","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140465266593744","resource.attributes.service@name":"recommendation","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"GET","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"1aef01694e12e529"}}
+{"traceId":"4cb0014c4d311691da84b0fcbb649796","spanId":"1aef01694e12e529","traceState":"","parentSpanId":"b57ce805362f7790","name":"get_inventory","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:14.595916544Z","endTime":"2021-03-25T17:21:14.627271680Z","durationInNanos":31355136,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"load_main_screen","traceGroupFields.endTime":"2021-03-25T17:21:15.017436928Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":457854208,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"d03fecfa0f55b77c"}}
+{"traceId":"4cb0014c4d311691da84b0fcbb649796","spanId":"d03fecfa0f55b77c","traceState":"","parentSpanId":"e9e09c3ce939b488","name":"server_request_login","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:14.565522176Z","endTime":"2021-03-25T17:21:14.992583936Z","durationInNanos":427061760,"serviceName":"authentication","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"load_main_screen","traceGroupFields.endTime":"2021-03-25T17:21:15.017436928Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":457854208,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8085,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140122129537568","resource.attributes.service@name":"authentication","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"GET","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":44162,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/server_request_login","span.attributes.http@host":"localhost:8085","span.attributes.http@target":"/server_request_login","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"62debfbb65838232"}}
+{"traceId":"ae9f8814e541d128c01662da42cbb4e5","spanId":"62debfbb65838232","traceState":"","parentSpanId":"","name":"client_cancel_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:28.897886464Z","endTime":"2021-03-25T17:23:29.051137792Z","durationInNanos":153251328,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:29.051137792Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":153251328,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"9ba2105853a19123"}}
+{"traceId":"ae9f8814e541d128c01662da42cbb4e5","spanId":"9ba2105853a19123","traceState":"","parentSpanId":"1d4345e2a25404e1","name":"HTTP PUT","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:28.901952512Z","endTime":"2021-03-25T17:23:28.987020544Z","durationInNanos":85068032,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:29.051137792Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":153251328,"span.attributes.http@url":"http://localhost:8083/cart_empty","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"PUT","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"7836e3dc48047a34"}}
+{"traceId":"ae9f8814e541d128c01662da42cbb4e5","spanId":"7836e3dc48047a34","traceState":"","parentSpanId":"9ba2105853a19123","name":"cartEmpty","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:28.904730112Z","endTime":"2021-03-25T17:23:28.977625088Z","durationInNanos":72894976,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:29.051137792Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":153251328,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"PUT","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55846,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/cart_empty","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/cart_empty","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"694c40a049b6bb75"}}
+{"traceId":"ae9f8814e541d128c01662da42cbb4e5","spanId":"694c40a049b6bb75","traceState":"","parentSpanId":"a949e38f139e5367","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:28.937193728Z","endTime":"2021-03-25T17:23:28.959799040Z","durationInNanos":22605312,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:29.051137792Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":153251328,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"TRUNCATE TABLE User_Carts","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"e9196d0973d34783"}}
+{"traceId":"ae9f8814e541d128c01662da42cbb4e5","spanId":"e9196d0973d34783","traceState":"","parentSpanId":"1d4345e2a25404e1","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:28.996000512Z","endTime":"2021-03-25T17:23:29.007382272Z","durationInNanos":11381760,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:29.051137792Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":153251328,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"1d4345e2a25404e1"}}
+{"traceId":"ae9f8814e541d128c01662da42cbb4e5","spanId":"1d4345e2a25404e1","traceState":"","parentSpanId":"acac8cf2cd25bdca","name":"clear_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:28.901695488Z","endTime":"2021-03-25T17:23:29.014134784Z","durationInNanos":112439296,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:29.051137792Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":153251328,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"acac8cf2cd25bdca"}}
+{"traceId":"ae9f8814e541d128c01662da42cbb4e5","spanId":"acac8cf2cd25bdca","traceState":"","parentSpanId":"a43d5066600179db","name":"clear_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:28.900759296Z","endTime":"2021-03-25T17:23:29.032418816Z","durationInNanos":131659520,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:29.051137792Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":153251328,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"DELETE","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56830,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/clear_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/clear_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"a43d5066600179db"}}
+{"traceId":"ae9f8814e541d128c01662da42cbb4e5","spanId":"a43d5066600179db","traceState":"","parentSpanId":"62debfbb65838232","name":"HTTP DELETE","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:28.898195200Z","endTime":"2021-03-25T17:23:29.043842304Z","durationInNanos":145647104,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:29.051137792Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":153251328,"span.attributes.http@url":"http://localhost:8088/clear_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"DELETE","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"02f0ed503fa076d2"}}
+{"traceId":"ae9f8814e541d128c01662da42cbb4e5","spanId":"02f0ed503fa076d2","traceState":"","parentSpanId":"a949e38f139e5367","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:28.927772928Z","endTime":"2021-03-25T17:23:28.930001920Z","durationInNanos":2228992,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:29.051137792Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":153251328,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"SELECT ItemId, TotalQty FROM User_Carts","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"6ddb545e34349c2e"}}
+{"traceId":"ae9f8814e541d128c01662da42cbb4e5","spanId":"6ddb545e34349c2e","traceState":"","parentSpanId":"e9196d0973d34783","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:28.999003355Z","endTime":"2021-03-25T17:23:29.003272166Z","durationInNanos":4268811,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:29.051137792Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":153251328,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-2","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":129,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56568,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"0b3a8cf9058f1a24"}}
+{"traceId":"ae9f8814e541d128c01662da42cbb4e5","spanId":"0b3a8cf9058f1a24","traceState":"","parentSpanId":"6ddb545e34349c2e","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:28.999920538Z","endTime":"2021-03-25T17:23:29.003108996Z","durationInNanos":3188458,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:29.051137792Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":153251328,"span.attributes.thread@name":"http-nio-8087-exec-2","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":129,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"a949e38f139e5367"}}
+{"traceId":"ae9f8814e541d128c01662da42cbb4e5","spanId":"a949e38f139e5367","traceState":"","parentSpanId":"7836e3dc48047a34","name":"cart_empty","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:28.905807616Z","endTime":"2021-03-25T17:23:28.966087424Z","durationInNanos":60279808,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:29.051137792Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":153251328,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"f6f9645fcad95fd6"}}
+{"traceId":"f0068334415fc4ef70c2a19edaef9573","spanId":"f6f9645fcad95fd6","traceState":"","parentSpanId":"","name":"client_pay_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:50.460224768Z","endTime":"2021-03-25T17:21:50.927259648Z","durationInNanos":467034880,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:21:50.927259648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":467034880,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"b1c3ea856510a6a1"}}
+{"traceId":"f0068334415fc4ef70c2a19edaef9573","spanId":"b1c3ea856510a6a1","traceState":"","parentSpanId":"0ab2072b5fd96775","name":"HTTP DELETE","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:50.466888192Z","endTime":"2021-03-25T17:21:50.709159168Z","durationInNanos":242270976,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:21:50.927259648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":467034880,"span.attributes.http@url":"http://localhost:8083/cart_sold","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"DELETE","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"9099440984e79531"}}
+{"traceId":"f0068334415fc4ef70c2a19edaef9573","spanId":"9099440984e79531","traceState":"","parentSpanId":"f6f9645fcad95fd6","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:50.460729344Z","endTime":"2021-03-25T17:21:50.917506304Z","durationInNanos":456776960,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:21:50.927259648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":467034880,"span.attributes.http@url":"http://localhost:8088/pay_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"0ab2072b5fd96775"}}
+{"traceId":"f0068334415fc4ef70c2a19edaef9573","spanId":"0ab2072b5fd96775","traceState":"","parentSpanId":"60829ac6236571df","name":"pay_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:50.466437120Z","endTime":"2021-03-25T17:21:50.847299584Z","durationInNanos":380862464,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:21:50.927259648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":467034880,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"ff47096ac1c2981c"}}
+{"traceId":"f0068334415fc4ef70c2a19edaef9573","spanId":"ff47096ac1c2981c","traceState":"","parentSpanId":"27deb6b75cd58962","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:50.762004687Z","endTime":"2021-03-25T17:21:50.788365631Z","durationInNanos":26360944,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:21:50.927259648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":467034880,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-10","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":137,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56546,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"60829ac6236571df"}}
+{"traceId":"f0068334415fc4ef70c2a19edaef9573","spanId":"60829ac6236571df","traceState":"","parentSpanId":"9099440984e79531","name":"pay_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:50.464929280Z","endTime":"2021-03-25T17:21:50.863437568Z","durationInNanos":398508288,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:21:50.927259648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":467034880,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56808,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/pay_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/pay_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"74feec0d3dfacd42"}}
+{"traceId":"f0068334415fc4ef70c2a19edaef9573","spanId":"74feec0d3dfacd42","traceState":"","parentSpanId":"ff47096ac1c2981c","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:50.764756104Z","endTime":"2021-03-25T17:21:50.788130297Z","durationInNanos":23374193,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:21:50.927259648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":467034880,"span.attributes.thread@name":"http-nio-8087-exec-10","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":137,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"2b6ee7267bce731a"}}
+{"traceId":"f0068334415fc4ef70c2a19edaef9573","spanId":"2b6ee7267bce731a","traceState":"","parentSpanId":"b1c3ea856510a6a1","name":"cartSold","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:50.479571456Z","endTime":"2021-03-25T17:21:50.664975872Z","durationInNanos":185404416,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:21:50.927259648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":467034880,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"DELETE","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55824,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/cart_sold","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/cart_sold","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"27deb6b75cd58962"}}
+{"traceId":"f0068334415fc4ef70c2a19edaef9573","spanId":"27deb6b75cd58962","traceState":"","parentSpanId":"0ab2072b5fd96775","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:50.747032064Z","endTime":"2021-03-25T17:21:50.803802624Z","durationInNanos":56770560,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:21:50.927259648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":467034880,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"5bb3c3c798268415"}}
+{"traceId":"f0068334415fc4ef70c2a19edaef9573","spanId":"5bb3c3c798268415","traceState":"","parentSpanId":"2b6ee7267bce731a","name":"cart_sold","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:50.481354496Z","endTime":"2021-03-25T17:21:50.646046208Z","durationInNanos":164691712,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:21:50.927259648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":467034880,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"bcc6b3a35599f34b"}}
+{"traceId":"f0068334415fc4ef70c2a19edaef9573","spanId":"bcc6b3a35599f34b","traceState":"","parentSpanId":"5bb3c3c798268415","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:50.604473600Z","endTime":"2021-03-25T17:21:50.634389504Z","durationInNanos":29915904,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:21:50.927259648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":467034880,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"TRUNCATE TABLE User_Carts","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"5166c25a1f6839c7"}}
+{"traceId":"2b4f29e4aef9b3838a7d1b83aab7c1bb","spanId":"5166c25a1f6839c7","traceState":"","parentSpanId":"","name":"client_pay_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:33.062937600Z","endTime":"2021-03-25T17:23:33.194503936Z","durationInNanos":131566336,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:33.194503936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":131566336,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"0802f5f8939438a8"}}
+{"traceId":"2b4f29e4aef9b3838a7d1b83aab7c1bb","spanId":"0802f5f8939438a8","traceState":"","parentSpanId":"2de7f35b0a1524cf","name":"pay_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:33.070421504Z","endTime":"2021-03-25T17:23:33.169714432Z","durationInNanos":99292928,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:33.194503936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":131566336,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"3b6de35d9794266b"}}
+{"traceId":"2b4f29e4aef9b3838a7d1b83aab7c1bb","spanId":"3b6de35d9794266b","traceState":"","parentSpanId":"0802f5f8939438a8","name":"HTTP DELETE","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:33.070677248Z","endTime":"2021-03-25T17:23:33.145324544Z","durationInNanos":74647296,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:33.194503936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":131566336,"span.attributes.http@url":"http://localhost:8083/cart_sold","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"DELETE","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"3050c75e2891cbd0"}}
+{"traceId":"2b4f29e4aef9b3838a7d1b83aab7c1bb","spanId":"3050c75e2891cbd0","traceState":"","parentSpanId":"5965aa92f19c1bc9","name":"cart_sold","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:33.074232064Z","endTime":"2021-03-25T17:23:33.127093504Z","durationInNanos":52861440,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:33.194503936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":131566336,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"184f2999b0681993"}}
+{"traceId":"2b4f29e4aef9b3838a7d1b83aab7c1bb","spanId":"184f2999b0681993","traceState":"","parentSpanId":"3050c75e2891cbd0","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:33.096890368Z","endTime":"2021-03-25T17:23:33.120715776Z","durationInNanos":23825408,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:33.194503936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":131566336,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"TRUNCATE TABLE User_Carts","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"5965aa92f19c1bc9"}}
+{"traceId":"2b4f29e4aef9b3838a7d1b83aab7c1bb","spanId":"5965aa92f19c1bc9","traceState":"","parentSpanId":"3b6de35d9794266b","name":"cartSold","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:33.073208576Z","endTime":"2021-03-25T17:23:33.135783936Z","durationInNanos":62575360,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:33.194503936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":131566336,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"DELETE","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55902,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/cart_sold","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/cart_sold","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"8f5082aa40f09354"}}
+{"traceId":"2b4f29e4aef9b3838a7d1b83aab7c1bb","spanId":"8f5082aa40f09354","traceState":"","parentSpanId":"0802f5f8939438a8","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:33.151627008Z","endTime":"2021-03-25T17:23:33.159618816Z","durationInNanos":7991808,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:33.194503936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":131566336,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"0629395312373daa"}}
+{"traceId":"2b4f29e4aef9b3838a7d1b83aab7c1bb","spanId":"0629395312373daa","traceState":"","parentSpanId":"5166c25a1f6839c7","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:33.063244288Z","endTime":"2021-03-25T17:23:33.186777600Z","durationInNanos":123533312,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:33.194503936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":131566336,"span.attributes.http@url":"http://localhost:8088/pay_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"beff2516bad059a3"}}
+{"traceId":"2b4f29e4aef9b3838a7d1b83aab7c1bb","spanId":"beff2516bad059a3","traceState":"","parentSpanId":"8f5082aa40f09354","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:33.154003504Z","endTime":"2021-03-25T17:23:33.157467694Z","durationInNanos":3464190,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:33.194503936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":131566336,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-4","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":131,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56624,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"d6b227e0493d3a65"}}
+{"traceId":"2b4f29e4aef9b3838a7d1b83aab7c1bb","spanId":"d6b227e0493d3a65","traceState":"","parentSpanId":"beff2516bad059a3","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:33.155245470Z","endTime":"2021-03-25T17:23:33.157299627Z","durationInNanos":2054157,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:33.194503936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":131566336,"span.attributes.thread@name":"http-nio-8087-exec-4","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":131,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"2de7f35b0a1524cf"}}
+{"traceId":"2b4f29e4aef9b3838a7d1b83aab7c1bb","spanId":"2de7f35b0a1524cf","traceState":"","parentSpanId":"0629395312373daa","name":"pay_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:33.069435392Z","endTime":"2021-03-25T17:23:33.177286656Z","durationInNanos":107851264,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:33.194503936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":131566336,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56886,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/pay_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/pay_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"1f4b8b2d230554f4"}}
+{"traceId":"9f010d58eed9c6ac836e0a0c3cce4789","spanId":"1f4b8b2d230554f4","traceState":"","parentSpanId":"","name":"client_pay_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:23.448014336Z","endTime":"2021-03-25T17:21:23.592395776Z","durationInNanos":144381440,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:21:23.592395776Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":144381440,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"11a4519551fd38a8"}}
+{"traceId":"9f010d58eed9c6ac836e0a0c3cce4789","spanId":"11a4519551fd38a8","traceState":"","parentSpanId":"1f4b8b2d230554f4","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:23.448317952Z","endTime":"2021-03-25T17:21:23.571843328Z","durationInNanos":123525376,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:21:23.592395776Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":144381440,"span.attributes.http@url":"http://localhost:8088/pay_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"60f93b7e6a56fd63"}}
+{"traceId":"9f010d58eed9c6ac836e0a0c3cce4789","spanId":"60f93b7e6a56fd63","traceState":"","parentSpanId":"829f37cd0aec9b9f","name":"cart_sold","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:23.455743744Z","endTime":"2021-03-25T17:21:23.508082688Z","durationInNanos":52338944,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:21:23.592395776Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":144381440,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"1f79b3db744fc299"}}
+{"traceId":"9f010d58eed9c6ac836e0a0c3cce4789","spanId":"1f79b3db744fc299","traceState":"","parentSpanId":"11a4519551fd38a8","name":"pay_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:23.450850304Z","endTime":"2021-03-25T17:21:23.558318336Z","durationInNanos":107468032,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:21:23.592395776Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":144381440,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56746,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/pay_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/pay_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"829f37cd0aec9b9f"}}
+{"traceId":"9f010d58eed9c6ac836e0a0c3cce4789","spanId":"829f37cd0aec9b9f","traceState":"","parentSpanId":"e011610aab3da935","name":"cartSold","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:23.454716928Z","endTime":"2021-03-25T17:21:23.518616320Z","durationInNanos":63899392,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:21:23.592395776Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":144381440,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"DELETE","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55762,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/cart_sold","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/cart_sold","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"0de97e875579dd04"}}
+{"traceId":"9f010d58eed9c6ac836e0a0c3cce4789","spanId":"0de97e875579dd04","traceState":"","parentSpanId":"60f93b7e6a56fd63","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:23.477390336Z","endTime":"2021-03-25T17:21:23.499967488Z","durationInNanos":22577152,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:21:23.592395776Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":144381440,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"TRUNCATE TABLE User_Carts","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"909eed2e2f3a94ef"}}
+{"traceId":"9f010d58eed9c6ac836e0a0c3cce4789","spanId":"909eed2e2f3a94ef","traceState":"","parentSpanId":"86b718226b9dbdbd","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:23.538002935Z","endTime":"2021-03-25T17:21:23.541793241Z","durationInNanos":3790306,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:21:23.592395776Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":144381440,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-8","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":135,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56484,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"6069aba83fa49e72"}}
+{"traceId":"9f010d58eed9c6ac836e0a0c3cce4789","spanId":"6069aba83fa49e72","traceState":"","parentSpanId":"909eed2e2f3a94ef","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:23.539599594Z","endTime":"2021-03-25T17:21:23.541647117Z","durationInNanos":2047523,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:21:23.592395776Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":144381440,"span.attributes.thread@name":"http-nio-8087-exec-8","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":135,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"86b718226b9dbdbd"}}
+{"traceId":"9f010d58eed9c6ac836e0a0c3cce4789","spanId":"86b718226b9dbdbd","traceState":"","parentSpanId":"6823703aa507463c","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:23.535015680Z","endTime":"2021-03-25T17:21:23.546532608Z","durationInNanos":11516928,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:21:23.592395776Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":144381440,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"e011610aab3da935"}}
+{"traceId":"9f010d58eed9c6ac836e0a0c3cce4789","spanId":"e011610aab3da935","traceState":"","parentSpanId":"6823703aa507463c","name":"HTTP DELETE","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:23.452033280Z","endTime":"2021-03-25T17:21:23.528720384Z","durationInNanos":76687104,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:21:23.592395776Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":144381440,"span.attributes.http@url":"http://localhost:8083/cart_sold","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"DELETE","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"6823703aa507463c"}}
+{"traceId":"9f010d58eed9c6ac836e0a0c3cce4789","spanId":"6823703aa507463c","traceState":"","parentSpanId":"1f79b3db744fc299","name":"pay_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:23.451779840Z","endTime":"2021-03-25T17:21:23.551823872Z","durationInNanos":100044032,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:21:23.592395776Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":144381440,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"8070bc776d7b3fdf"}}
+{"traceId":"55cfebc5c8c42e2b92e1731c71f65aa6","spanId":"8070bc776d7b3fdf","traceState":"","parentSpanId":"","name":"client_delivery_status","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:32.123475712Z","endTime":"2021-03-25T17:23:32.254567424Z","durationInNanos":131091712,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:23:32.254567424Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":131091712,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"0bae057bc46bf20d"}}
+{"traceId":"55cfebc5c8c42e2b92e1731c71f65aa6","spanId":"0bae057bc46bf20d","traceState":"","parentSpanId":"8040060a8677541b","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:32.153403904Z","endTime":"2021-03-25T17:23:32.154142720Z","durationInNanos":738816,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:23:32.254567424Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":131091712,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"SELECT * FROM User_Carts","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"b0aecf48b3d1cdd2"}}
+{"traceId":"55cfebc5c8c42e2b92e1731c71f65aa6","spanId":"b0aecf48b3d1cdd2","traceState":"","parentSpanId":"6b69e82cbc53b10a","name":"getCart","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:32.130227200Z","endTime":"2021-03-25T17:23:32.175308032Z","durationInNanos":45080832,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:23:32.254567424Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":131091712,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"GET","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55894,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/get_cart","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/get_cart","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"db16bff78edeb4e2"}}
+{"traceId":"55cfebc5c8c42e2b92e1731c71f65aa6","spanId":"db16bff78edeb4e2","traceState":"","parentSpanId":"451a52b4b1ad6937","name":"get_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:32.126292480Z","endTime":"2021-03-25T17:23:32.236474624Z","durationInNanos":110182144,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:23:32.254567424Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":131091712,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"GET","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56878,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/get_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/get_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"4916a83e6a831cc0"}}
+{"traceId":"55cfebc5c8c42e2b92e1731c71f65aa6","spanId":"4916a83e6a831cc0","traceState":"","parentSpanId":"6c4c5b024b202730","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:32.203003771Z","endTime":"2021-03-25T17:23:32.206036233Z","durationInNanos":3032462,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:23:32.254567424Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":131091712,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-2","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":129,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56616,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"451a52b4b1ad6937"}}
+{"traceId":"55cfebc5c8c42e2b92e1731c71f65aa6","spanId":"451a52b4b1ad6937","traceState":"","parentSpanId":"8070bc776d7b3fdf","name":"HTTP GET","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:32.123781120Z","endTime":"2021-03-25T17:23:32.246547712Z","durationInNanos":122766592,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:23:32.254567424Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":131091712,"span.attributes.http@url":"http://localhost:8088/get_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"GET","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"9bb1cb211a2c96d9"}}
+{"traceId":"55cfebc5c8c42e2b92e1731c71f65aa6","spanId":"9bb1cb211a2c96d9","traceState":"","parentSpanId":"4916a83e6a831cc0","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:32.203886974Z","endTime":"2021-03-25T17:23:32.205898014Z","durationInNanos":2011040,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:23:32.254567424Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":131091712,"span.attributes.thread@name":"http-nio-8087-exec-2","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":129,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"6c4c5b024b202730"}}
+{"traceId":"55cfebc5c8c42e2b92e1731c71f65aa6","spanId":"6c4c5b024b202730","traceState":"","parentSpanId":"e7ce1695e61e91e3","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:32.199425024Z","endTime":"2021-03-25T17:23:32.209982208Z","durationInNanos":10557184,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:23:32.254567424Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":131091712,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"6b69e82cbc53b10a"}}
+{"traceId":"55cfebc5c8c42e2b92e1731c71f65aa6","spanId":"6b69e82cbc53b10a","traceState":"","parentSpanId":"e7ce1695e61e91e3","name":"HTTP GET","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:32.127502080Z","endTime":"2021-03-25T17:23:32.190182656Z","durationInNanos":62680576,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:23:32.254567424Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":131091712,"span.attributes.http@url":"http://localhost:8083/get_cart","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"GET","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"8040060a8677541b"}}
+{"traceId":"55cfebc5c8c42e2b92e1731c71f65aa6","spanId":"8040060a8677541b","traceState":"","parentSpanId":"b0aecf48b3d1cdd2","name":"get_cart","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:32.131343360Z","endTime":"2021-03-25T17:23:32.162667520Z","durationInNanos":31324160,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:23:32.254567424Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":131091712,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"e7ce1695e61e91e3"}}
+{"traceId":"55cfebc5c8c42e2b92e1731c71f65aa6","spanId":"e7ce1695e61e91e3","traceState":"","parentSpanId":"db16bff78edeb4e2","name":"get_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:32.127243776Z","endTime":"2021-03-25T17:23:32.231066368Z","durationInNanos":103822592,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:23:32.254567424Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":131091712,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"e6ced0ee51a5e024"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"e6ced0ee51a5e024","traceState":"","parentSpanId":"","name":"client_checkout","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:38.695432960Z","endTime":"2021-03-25T17:24:39.071426816Z","durationInNanos":375993856,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"06832e96addf20f3"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"06832e96addf20f3","traceState":"","parentSpanId":"3e40e04d328f2a0a","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:38.868930560Z","endTime":"2021-03-25T17:24:38.870375936Z","durationInNanos":1445376,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'apple', 'Qty': 1}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"72c34e7343e6509a"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"72c34e7343e6509a","traceState":"","parentSpanId":"76ba99744a401f21","name":"update_item","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:38.707735040Z","endTime":"2021-03-25T17:24:38.744882176Z","durationInNanos":37147136,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"c64650fb3e55152c"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"c64650fb3e55152c","traceState":"","parentSpanId":"21de487dcbd508b2","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:38.920792255Z","endTime":"2021-03-25T17:24:38.922798175Z","durationInNanos":2005920,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"span.attributes.thread@name":"http-nio-8087-exec-10","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":137,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"b13470a2bba1d4b2"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"b13470a2bba1d4b2","traceState":"","parentSpanId":"97faa65422f03e15","name":"payment","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:38.698324480Z","endTime":"2021-03-25T17:24:39.044744192Z","durationInNanos":346419712,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8084,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":50628,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/checkout","span.attributes.http@host":"localhost:8084","span.attributes.http@target":"/checkout","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"e9215f70dc3df982"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"e9215f70dc3df982","traceState":"","parentSpanId":"8b44f219d62e0a15","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:38.772626176Z","endTime":"2021-03-25T17:24:38.832209408Z","durationInNanos":59583232,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"span.attributes.http@url":"http://localhost:8083/update_item","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"2a59f4370347c6e9"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"2a59f4370347c6e9","traceState":"","parentSpanId":"c641adcb80f8c7ab","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:38.995855360Z","endTime":"2021-03-25T17:24:39.012676864Z","durationInNanos":16821504,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"3e40e04d328f2a0a"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"3e40e04d328f2a0a","traceState":"","parentSpanId":"7034699ebd9affd5","name":"update_item","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:38.844057344Z","endTime":"2021-03-25T17:24:38.882541568Z","durationInNanos":38484224,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"8d52dbf2ce18447b"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"8d52dbf2ce18447b","traceState":"","parentSpanId":"819176f60584727b","name":"update_inventory","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:38.702367232Z","endTime":"2021-03-25T17:24:38.966861824Z","durationInNanos":264494592,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8082,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":45888,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_inventory","span.attributes.http@host":"localhost:8082","span.attributes.http@target":"/update_inventory","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"819176f60584727b"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"819176f60584727b","traceState":"","parentSpanId":"c641adcb80f8c7ab","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:38.699733504Z","endTime":"2021-03-25T17:24:38.983250944Z","durationInNanos":283517440,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"span.attributes.http@url":"http://localhost:8082/update_inventory","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"5a19345c46d15c91"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"5a19345c46d15c91","traceState":"","parentSpanId":"54b68480d4a455c4","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:39.000786325Z","endTime":"2021-03-25T17:24:39.010878319Z","durationInNanos":10091994,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"span.attributes.thread@name":"http-nio-8087-exec-2","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":129,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"c00c4de722cc894a"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"c00c4de722cc894a","traceState":"","parentSpanId":"8b44f219d62e0a15","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:38.703847936Z","endTime":"2021-03-25T17:24:38.766967296Z","durationInNanos":63119360,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"span.attributes.http@url":"http://localhost:8083/update_item","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"08c2ba1f92ec53e6"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"08c2ba1f92ec53e6","traceState":"","parentSpanId":"e9215f70dc3df982","name":"updateItem","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:38.776030208Z","endTime":"2021-03-25T17:24:38.821522176Z","durationInNanos":45491968,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56028,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_item","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/update_item","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"76ba99744a401f21"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"76ba99744a401f21","traceState":"","parentSpanId":"c00c4de722cc894a","name":"updateItem","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:38.706701312Z","endTime":"2021-03-25T17:24:38.757098240Z","durationInNanos":50396928,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56024,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_item","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/update_item","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"c641adcb80f8c7ab"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"c641adcb80f8c7ab","traceState":"","parentSpanId":"b13470a2bba1d4b2","name":"checkout","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:38.699252224Z","endTime":"2021-03-25T17:24:39.036041984Z","durationInNanos":336789760,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"2d31e874898dba36"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"2d31e874898dba36","traceState":"","parentSpanId":"08c2ba1f92ec53e6","name":"update_item","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:38.777075968Z","endTime":"2021-03-25T17:24:38.815331328Z","durationInNanos":38255360,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"56e7709900b0ca90"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"56e7709900b0ca90","traceState":"","parentSpanId":"8b44f219d62e0a15","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:38.916526592Z","endTime":"2021-03-25T17:24:38.925087232Z","durationInNanos":8560640,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"21de487dcbd508b2"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"21de487dcbd508b2","traceState":"","parentSpanId":"56e7709900b0ca90","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:38.920004214Z","endTime":"2021-03-25T17:24:38.923003040Z","durationInNanos":2998826,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-10","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":137,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56754,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"97faa65422f03e15"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"97faa65422f03e15","traceState":"","parentSpanId":"e6ced0ee51a5e024","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:38.695734016Z","endTime":"2021-03-25T17:24:39.062184704Z","durationInNanos":366450688,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"span.attributes.http@url":"http://localhost:8084/checkout","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"54b68480d4a455c4"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"54b68480d4a455c4","traceState":"","parentSpanId":"2a59f4370347c6e9","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:39.000003640Z","endTime":"2021-03-25T17:24:39.011020618Z","durationInNanos":11016978,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-2","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":129,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56756,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"74bd9e337e04fe80"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"74bd9e337e04fe80","traceState":"","parentSpanId":"72c34e7343e6509a","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:38.730163712Z","endTime":"2021-03-25T17:24:38.731151872Z","durationInNanos":988160,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'banana', 'Qty': 2}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"7034699ebd9affd5"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"7034699ebd9affd5","traceState":"","parentSpanId":"0a73ecf1c5fc2220","name":"updateItem","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:38.843072256Z","endTime":"2021-03-25T17:24:38.890055936Z","durationInNanos":46983680,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56032,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_item","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/update_item","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"bc3986c93afde351"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"bc3986c93afde351","traceState":"","parentSpanId":"2d31e874898dba36","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:38.803536384Z","endTime":"2021-03-25T17:24:38.804492032Z","durationInNanos":955648,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'orange', 'Qty': 3}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"0a73ecf1c5fc2220"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"0a73ecf1c5fc2220","traceState":"","parentSpanId":"8b44f219d62e0a15","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:38.840366080Z","endTime":"2021-03-25T17:24:38.905483776Z","durationInNanos":65117696,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"span.attributes.http@url":"http://localhost:8083/update_item","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"8b44f219d62e0a15"}}
+{"traceId":"83e711a859fde181df3d4398cda11405","spanId":"8b44f219d62e0a15","traceState":"","parentSpanId":"8d52dbf2ce18447b","name":"update_inventory","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:38.703366144Z","endTime":"2021-03-25T17:24:38.943165696Z","durationInNanos":239799552,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:39.071426816Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":375993856,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"3359ca1b6d6db780"}}
+{"traceId":"bc84e238fc20f480738b7733b1aa8331","spanId":"3359ca1b6d6db780","traceState":"","parentSpanId":"","name":"client_cancel_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:39.768194304Z","endTime":"2021-03-25T17:24:39.806145280Z","durationInNanos":37950976,"serviceName":"frontend-client","events":[{"time":"2021-03-25T17:24:39.806087680Z","name":"exception","attributes":{"exception@message":"","exception@type":"AssertionError","exception@stacktrace":"Traceback (most recent call last):\n File \"/usr/lib/python3.6/site-packages/opentelemetry/sdk/trace/__init__.py\", line 804, in use_span\n yield span\n File \"/app/client.py\", line 209, in cancelOrder\n assert cancelOrderAPIRequest.status_code == 200\nAssertionError\n"},"droppedAttributesCount":0}],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:24:39.806145280Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":37950976,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","status.message":"AssertionError: ","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":2,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"40366bdbbe7a647c"}}
+{"traceId":"bc84e238fc20f480738b7733b1aa8331","spanId":"40366bdbbe7a647c","traceState":"","parentSpanId":"3359ca1b6d6db780","name":"HTTP DELETE","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:39.768545024Z","endTime":"2021-03-25T17:24:39.800680704Z","durationInNanos":32135680,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:24:39.806145280Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":37950976,"span.attributes.http@url":"http://localhost:8088/clear_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"SERVICE UNAVAILABLE","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":2,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"DELETE","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":503}
+{"index":{"_id":"301185ff94eed72d"}}
+{"traceId":"bc84e238fc20f480738b7733b1aa8331","spanId":"301185ff94eed72d","traceState":"","parentSpanId":"d39ada3ebb20031d","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:39.772635648Z","endTime":"2021-03-25T17:24:39.779730688Z","durationInNanos":7095040,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:24:39.806145280Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":37950976,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"1b8bfeb41c684ad8"}}
+{"traceId":"bc84e238fc20f480738b7733b1aa8331","spanId":"1b8bfeb41c684ad8","traceState":"","parentSpanId":"0217c79f64c43d16","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:39.775682302Z","endTime":"2021-03-25T17:24:39.777381896Z","durationInNanos":1699594,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:24:39.806145280Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":37950976,"span.attributes.thread@name":"http-nio-8087-exec-4","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":131,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"0217c79f64c43d16"}}
+{"traceId":"bc84e238fc20f480738b7733b1aa8331","spanId":"0217c79f64c43d16","traceState":"","parentSpanId":"301185ff94eed72d","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:39.775003883Z","endTime":"2021-03-25T17:24:39.777547574Z","durationInNanos":2543691,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:24:39.806145280Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":37950976,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-4","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":131,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56760,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"d39ada3ebb20031d"}}
+{"traceId":"bc84e238fc20f480738b7733b1aa8331","spanId":"d39ada3ebb20031d","traceState":"","parentSpanId":"40366bdbbe7a647c","name":"clear_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:39.771380736Z","endTime":"2021-03-25T17:24:39.788654080Z","durationInNanos":17273344,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:24:39.806145280Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":37950976,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"SERVICE UNAVAILABLE","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":2,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"DELETE","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":57026,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/clear_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/clear_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":503}
+{"index":{"_id":"909eca7a01416520"}}
+{"traceId":"386d26555771f39c0caafdaf16739d9f","spanId":"909eca7a01416520","traceState":"","parentSpanId":"","name":"client_create_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:40.674289152Z","endTime":"2021-03-25T17:24:40.938973184Z","durationInNanos":264684032,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:40.938973184Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":264684032,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"623f8925e9ed74be"}}
+{"traceId":"386d26555771f39c0caafdaf16739d9f","spanId":"623f8925e9ed74be","traceState":"","parentSpanId":"740200d311a15cbc","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:40.746123776Z","endTime":"2021-03-25T17:24:40.819686656Z","durationInNanos":73562880,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:40.938973184Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":264684032,"span.attributes.http@url":"http://localhost:8083/add_item_to_cart","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"150e2d39d592096a"}}
+{"traceId":"386d26555771f39c0caafdaf16739d9f","spanId":"150e2d39d592096a","traceState":"","parentSpanId":"740200d311a15cbc","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:40.678726656Z","endTime":"2021-03-25T17:24:40.739863808Z","durationInNanos":61137152,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:40.938973184Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":264684032,"span.attributes.http@url":"http://localhost:8083/add_item_to_cart","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"9fbb9a88883f3dac"}}
+{"traceId":"386d26555771f39c0caafdaf16739d9f","spanId":"9fbb9a88883f3dac","traceState":"","parentSpanId":"dfd44641cfa1c3e2","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:40.783504896Z","endTime":"2021-03-25T17:24:40.784676608Z","durationInNanos":1171712,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:40.938973184Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":264684032,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'orange', 'Qty': '3'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"INSERT INTO User_Carts (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"cde1a819e0978d4b"}}
+{"traceId":"386d26555771f39c0caafdaf16739d9f","spanId":"cde1a819e0978d4b","traceState":"","parentSpanId":"61c8c5a6c6fec6f6","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:40.900667958Z","endTime":"2021-03-25T17:24:40.906771544Z","durationInNanos":6103586,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:40.938973184Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":264684032,"span.attributes.thread@name":"http-nio-8087-exec-6","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":133,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"1e2d414d8ed0baf6"}}
+{"traceId":"386d26555771f39c0caafdaf16739d9f","spanId":"1e2d414d8ed0baf6","traceState":"","parentSpanId":"0d5b9fc9b7839fa9","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:40.704969216Z","endTime":"2021-03-25T17:24:40.705938176Z","durationInNanos":968960,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:40.938973184Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":264684032,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'apple', 'Qty': '1'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"86775de8fd79c391"}}
+{"traceId":"386d26555771f39c0caafdaf16739d9f","spanId":"86775de8fd79c391","traceState":"","parentSpanId":"0d5b9fc9b7839fa9","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:40.712461824Z","endTime":"2021-03-25T17:24:40.714333440Z","durationInNanos":1871616,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:40.938973184Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":264684032,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'apple', 'Qty': '1'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"INSERT INTO User_Carts (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"83324bea415aeb42"}}
+{"traceId":"386d26555771f39c0caafdaf16739d9f","spanId":"83324bea415aeb42","traceState":"","parentSpanId":"a5b31343288f51a9","name":"update_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:40.677266688Z","endTime":"2021-03-25T17:24:40.915795200Z","durationInNanos":238528512,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:40.938973184Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":264684032,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":57030,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/update_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"adc427aef5411564"}}
+{"traceId":"386d26555771f39c0caafdaf16739d9f","spanId":"adc427aef5411564","traceState":"","parentSpanId":"67d5cbbdae2849bd","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:40.863040768Z","endTime":"2021-03-25T17:24:40.864137472Z","durationInNanos":1096704,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:40.938973184Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":264684032,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'banana', 'Qty': '2'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"INSERT INTO User_Carts (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"0ebb517eba85341f"}}
+{"traceId":"386d26555771f39c0caafdaf16739d9f","spanId":"0ebb517eba85341f","traceState":"","parentSpanId":"8341f145a8322596","name":"addItemToCart","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:40.828758016Z","endTime":"2021-03-25T17:24:40.880685056Z","durationInNanos":51927040,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:40.938973184Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":264684032,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56054,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/add_item_to_cart","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/add_item_to_cart","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"a5b31343288f51a9"}}
+{"traceId":"386d26555771f39c0caafdaf16739d9f","spanId":"a5b31343288f51a9","traceState":"","parentSpanId":"909eca7a01416520","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:40.674618880Z","endTime":"2021-03-25T17:24:40.930931712Z","durationInNanos":256312832,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:40.938973184Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":264684032,"span.attributes.http@url":"http://localhost:8088/update_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"61c8c5a6c6fec6f6"}}
+{"traceId":"386d26555771f39c0caafdaf16739d9f","spanId":"61c8c5a6c6fec6f6","traceState":"","parentSpanId":"032930bf72e67fd1","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:40.900003887Z","endTime":"2021-03-25T17:24:40.907163154Z","durationInNanos":7159267,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:40.938973184Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":264684032,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-6","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":133,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56776,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"bf900401c19b870f"}}
+{"traceId":"386d26555771f39c0caafdaf16739d9f","spanId":"bf900401c19b870f","traceState":"","parentSpanId":"dfd44641cfa1c3e2","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:40.775589632Z","endTime":"2021-03-25T17:24:40.776550400Z","durationInNanos":960768,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:40.938973184Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":264684032,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'orange', 'Qty': '3'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"032930bf72e67fd1"}}
+{"traceId":"386d26555771f39c0caafdaf16739d9f","spanId":"032930bf72e67fd1","traceState":"","parentSpanId":"740200d311a15cbc","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:40.897000192Z","endTime":"2021-03-25T17:24:40.903326208Z","durationInNanos":6326016,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:40.938973184Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":264684032,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"0d5b9fc9b7839fa9"}}
+{"traceId":"386d26555771f39c0caafdaf16739d9f","spanId":"0d5b9fc9b7839fa9","traceState":"","parentSpanId":"72a8313ee5905897","name":"add_item_to_cart","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:40.682670080Z","endTime":"2021-03-25T17:24:40.722864128Z","durationInNanos":40194048,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:40.938973184Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":264684032,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"dfd44641cfa1c3e2"}}
+{"traceId":"386d26555771f39c0caafdaf16739d9f","spanId":"dfd44641cfa1c3e2","traceState":"","parentSpanId":"74bd0a2b1c535dee","name":"add_item_to_cart","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:40.750823936Z","endTime":"2021-03-25T17:24:40.795968768Z","durationInNanos":45144832,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:40.938973184Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":264684032,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"72a8313ee5905897"}}
+{"traceId":"386d26555771f39c0caafdaf16739d9f","spanId":"72a8313ee5905897","traceState":"","parentSpanId":"150e2d39d592096a","name":"addItemToCart","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:40.681532160Z","endTime":"2021-03-25T17:24:40.730191872Z","durationInNanos":48659712,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:40.938973184Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":264684032,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56046,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/add_item_to_cart","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/add_item_to_cart","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"da703626231e808a"}}
+{"traceId":"386d26555771f39c0caafdaf16739d9f","spanId":"da703626231e808a","traceState":"","parentSpanId":"67d5cbbdae2849bd","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:40.853131008Z","endTime":"2021-03-25T17:24:40.854102272Z","durationInNanos":971264,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:40.938973184Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":264684032,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'banana', 'Qty': '2'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"740200d311a15cbc"}}
+{"traceId":"386d26555771f39c0caafdaf16739d9f","spanId":"740200d311a15cbc","traceState":"","parentSpanId":"83324bea415aeb42","name":"update_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:40.678199040Z","endTime":"2021-03-25T17:24:40.910448128Z","durationInNanos":232249088,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:40.938973184Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":264684032,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"74bd0a2b1c535dee"}}
+{"traceId":"386d26555771f39c0caafdaf16739d9f","spanId":"74bd0a2b1c535dee","traceState":"","parentSpanId":"623f8925e9ed74be","name":"addItemToCart","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:40.749567488Z","endTime":"2021-03-25T17:24:40.803897600Z","durationInNanos":54330112,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:40.938973184Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":264684032,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56050,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/add_item_to_cart","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/add_item_to_cart","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"8341f145a8322596"}}
+{"traceId":"386d26555771f39c0caafdaf16739d9f","spanId":"8341f145a8322596","traceState":"","parentSpanId":"740200d311a15cbc","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:40.825348864Z","endTime":"2021-03-25T17:24:40.891079680Z","durationInNanos":65730816,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:40.938973184Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":264684032,"span.attributes.http@url":"http://localhost:8083/add_item_to_cart","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"67d5cbbdae2849bd"}}
+{"traceId":"386d26555771f39c0caafdaf16739d9f","spanId":"67d5cbbdae2849bd","traceState":"","parentSpanId":"0ebb517eba85341f","name":"add_item_to_cart","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:40.829851904Z","endTime":"2021-03-25T17:24:40.874339840Z","durationInNanos":44487936,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:40.938973184Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":264684032,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"9b0ca0be3f3afeb5"}}
+{"traceId":"bf6b86edbb7810a0b69a435676483a21","spanId":"9b0ca0be3f3afeb5","traceState":"","parentSpanId":"","name":"client_delivery_status","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:41.379599616Z","endTime":"2021-03-25T17:24:41.486852608Z","durationInNanos":107252992,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:24:41.486852608Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":107252992,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"52d6f6459801a501"}}
+{"traceId":"bf6b86edbb7810a0b69a435676483a21","spanId":"52d6f6459801a501","traceState":"","parentSpanId":"d4da0d84ed0f398d","name":"get_cart","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:41.388732160Z","endTime":"2021-03-25T17:24:41.419036672Z","durationInNanos":30304512,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:24:41.486852608Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":107252992,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"5d4fdf19cc933a1c"}}
+{"traceId":"bf6b86edbb7810a0b69a435676483a21","spanId":"5d4fdf19cc933a1c","traceState":"","parentSpanId":"4dd32ba418f528c3","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:41.457002970Z","endTime":"2021-03-25T17:24:41.459454427Z","durationInNanos":2451457,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:24:41.486852608Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":107252992,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-8","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":135,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56784,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"56e05d7fa868a1c1"}}
+{"traceId":"bf6b86edbb7810a0b69a435676483a21","spanId":"56e05d7fa868a1c1","traceState":"","parentSpanId":"c7287204c63d5fad","name":"HTTP GET","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:41.383910400Z","endTime":"2021-03-25T17:24:41.445765888Z","durationInNanos":61855488,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:24:41.486852608Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":107252992,"span.attributes.http@url":"http://localhost:8083/get_cart","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"GET","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"234e172a980209ad"}}
+{"traceId":"bf6b86edbb7810a0b69a435676483a21","spanId":"234e172a980209ad","traceState":"","parentSpanId":"52d6f6459801a501","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:41.411823616Z","endTime":"2021-03-25T17:24:41.412596480Z","durationInNanos":772864,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:24:41.486852608Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":107252992,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"SELECT * FROM User_Carts","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"d4da0d84ed0f398d"}}
+{"traceId":"bf6b86edbb7810a0b69a435676483a21","spanId":"d4da0d84ed0f398d","traceState":"","parentSpanId":"56e05d7fa868a1c1","name":"getCart","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:41.387030784Z","endTime":"2021-03-25T17:24:41.425407488Z","durationInNanos":38376704,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:24:41.486852608Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":107252992,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"GET","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56062,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/get_cart","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/get_cart","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"02d6391c11b5bef0"}}
+{"traceId":"bf6b86edbb7810a0b69a435676483a21","spanId":"02d6391c11b5bef0","traceState":"","parentSpanId":"33e36a09b147701a","name":"get_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:41.382713344Z","endTime":"2021-03-25T17:24:41.471790080Z","durationInNanos":89076736,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:24:41.486852608Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":107252992,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"GET","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":57046,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/get_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/get_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"c7287204c63d5fad"}}
+{"traceId":"bf6b86edbb7810a0b69a435676483a21","spanId":"c7287204c63d5fad","traceState":"","parentSpanId":"02d6391c11b5bef0","name":"get_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:41.383650304Z","endTime":"2021-03-25T17:24:41.466961152Z","durationInNanos":83310848,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:24:41.486852608Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":107252992,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"4dd32ba418f528c3"}}
+{"traceId":"bf6b86edbb7810a0b69a435676483a21","spanId":"4dd32ba418f528c3","traceState":"","parentSpanId":"c7287204c63d5fad","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:41.455014144Z","endTime":"2021-03-25T17:24:41.460891904Z","durationInNanos":5877760,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:24:41.486852608Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":107252992,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"33e36a09b147701a"}}
+{"traceId":"bf6b86edbb7810a0b69a435676483a21","spanId":"33e36a09b147701a","traceState":"","parentSpanId":"9b0ca0be3f3afeb5","name":"HTTP GET","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:41.379963136Z","endTime":"2021-03-25T17:24:41.481062656Z","durationInNanos":101099520,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:24:41.486852608Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":107252992,"span.attributes.http@url":"http://localhost:8088/get_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"GET","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"ed1c40ba8f5c3ca1"}}
+{"traceId":"bf6b86edbb7810a0b69a435676483a21","spanId":"ed1c40ba8f5c3ca1","traceState":"","parentSpanId":"5d4fdf19cc933a1c","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:41.457727404Z","endTime":"2021-03-25T17:24:41.459309570Z","durationInNanos":1582166,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:24:41.486852608Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":107252992,"span.attributes.thread@name":"http-nio-8087-exec-8","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":135,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"87cec809f399dc30"}}
+{"traceId":"aa546c8539ad5cb0ee6d456c5072b1ec","spanId":"87cec809f399dc30","traceState":"","parentSpanId":"","name":"client_pay_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:42.199765504Z","endTime":"2021-03-25T17:24:42.321604096Z","durationInNanos":121838592,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:24:42.321604096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":121838592,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"b1cf7ec42c1b633d"}}
+{"traceId":"aa546c8539ad5cb0ee6d456c5072b1ec","spanId":"b1cf7ec42c1b633d","traceState":"","parentSpanId":"d7aee4db1f6e5763","name":"pay_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:42.202723072Z","endTime":"2021-03-25T17:24:42.300398336Z","durationInNanos":97675264,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:24:42.321604096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":121838592,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":57054,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/pay_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/pay_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"d7aee4db1f6e5763"}}
+{"traceId":"aa546c8539ad5cb0ee6d456c5072b1ec","spanId":"d7aee4db1f6e5763","traceState":"","parentSpanId":"87cec809f399dc30","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:42.200078848Z","endTime":"2021-03-25T17:24:42.312237568Z","durationInNanos":112158720,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:24:42.321604096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":121838592,"span.attributes.http@url":"http://localhost:8088/pay_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"6ec093eb614de902"}}
+{"traceId":"aa546c8539ad5cb0ee6d456c5072b1ec","spanId":"6ec093eb614de902","traceState":"","parentSpanId":"181fdbbc87ece9f3","name":"cartSold","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:42.206539008Z","endTime":"2021-03-25T17:24:42.265985280Z","durationInNanos":59446272,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:24:42.321604096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":121838592,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"DELETE","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56070,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/cart_sold","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/cart_sold","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"c097b32c179cd05b"}}
+{"traceId":"aa546c8539ad5cb0ee6d456c5072b1ec","spanId":"c097b32c179cd05b","traceState":"","parentSpanId":"b1cf7ec42c1b633d","name":"pay_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:42.203660288Z","endTime":"2021-03-25T17:24:42.295044096Z","durationInNanos":91383808,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:24:42.321604096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":121838592,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"8f8941685de6c284"}}
+{"traceId":"aa546c8539ad5cb0ee6d456c5072b1ec","spanId":"8f8941685de6c284","traceState":"","parentSpanId":"6ec093eb614de902","name":"cart_sold","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:42.207574272Z","endTime":"2021-03-25T17:24:42.255295744Z","durationInNanos":47721472,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:24:42.321604096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":121838592,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"5427cbedc82d9a86"}}
+{"traceId":"aa546c8539ad5cb0ee6d456c5072b1ec","spanId":"5427cbedc82d9a86","traceState":"","parentSpanId":"8ca74d2bb426df6b","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:42.285735214Z","endTime":"2021-03-25T17:24:42.287341397Z","durationInNanos":1606183,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:24:42.321604096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":121838592,"span.attributes.thread@name":"http-nio-8087-exec-10","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":137,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"181fdbbc87ece9f3"}}
+{"traceId":"aa546c8539ad5cb0ee6d456c5072b1ec","spanId":"181fdbbc87ece9f3","traceState":"","parentSpanId":"c097b32c179cd05b","name":"HTTP DELETE","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:42.203917056Z","endTime":"2021-03-25T17:24:42.276364032Z","durationInNanos":72446976,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:24:42.321604096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":121838592,"span.attributes.http@url":"http://localhost:8083/cart_sold","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"DELETE","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"8ca74d2bb426df6b"}}
+{"traceId":"aa546c8539ad5cb0ee6d456c5072b1ec","spanId":"8ca74d2bb426df6b","traceState":"","parentSpanId":"daf3d5e227d66b44","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:42.285003743Z","endTime":"2021-03-25T17:24:42.287789648Z","durationInNanos":2785905,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:24:42.321604096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":121838592,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-10","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":137,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56792,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"4c9fd6c35e7a0496"}}
+{"traceId":"aa546c8539ad5cb0ee6d456c5072b1ec","spanId":"4c9fd6c35e7a0496","traceState":"","parentSpanId":"8f8941685de6c284","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:42.230315008Z","endTime":"2021-03-25T17:24:42.248354560Z","durationInNanos":18039552,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:24:42.321604096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":121838592,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"TRUNCATE TABLE User_Carts","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"daf3d5e227d66b44"}}
+{"traceId":"aa546c8539ad5cb0ee6d456c5072b1ec","spanId":"daf3d5e227d66b44","traceState":"","parentSpanId":"c097b32c179cd05b","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:42.282489344Z","endTime":"2021-03-25T17:24:42.289478912Z","durationInNanos":6989568,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:24:42.321604096Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":121838592,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"fc2889232f6bfee2"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"fc2889232f6bfee2","traceState":"","parentSpanId":"","name":"client_checkout","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:20.387353600Z","endTime":"2021-03-25T17:21:20.759999232Z","durationInNanos":372645632,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"9c3f9115f871f5a0"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"9c3f9115f871f5a0","traceState":"","parentSpanId":"935cbd34eb35e840","name":"payment","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:20.390497024Z","endTime":"2021-03-25T17:21:20.739962624Z","durationInNanos":349465600,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8084,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":50316,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/checkout","span.attributes.http@host":"localhost:8084","span.attributes.http@target":"/checkout","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"81aca34992c3bb9a"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"81aca34992c3bb9a","traceState":"","parentSpanId":"2e0bcc35b46cdc58","name":"update_inventory","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:20.398322432Z","endTime":"2021-03-25T17:21:20.681257728Z","durationInNanos":282935296,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"0438f00bd05a7b08"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"0438f00bd05a7b08","traceState":"","parentSpanId":"81aca34992c3bb9a","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:20.493850624Z","endTime":"2021-03-25T17:21:20.565137920Z","durationInNanos":71287296,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"span.attributes.http@url":"http://localhost:8083/update_item","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"3365305ba3a4b271"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"3365305ba3a4b271","traceState":"","parentSpanId":"81aca34992c3bb9a","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:20.575116544Z","endTime":"2021-03-25T17:21:20.642036992Z","durationInNanos":66920448,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"span.attributes.http@url":"http://localhost:8083/update_item","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"232c0433f6087a19"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"232c0433f6087a19","traceState":"","parentSpanId":"81aca34992c3bb9a","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:20.398961920Z","endTime":"2021-03-25T17:21:20.482841600Z","durationInNanos":83879680,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"span.attributes.http@url":"http://localhost:8083/update_item","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"c1222bbdfe51df89"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"c1222bbdfe51df89","traceState":"","parentSpanId":"42ca61064e4fbbf8","name":"update_item","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:20.497675776Z","endTime":"2021-03-25T17:21:20.546634496Z","durationInNanos":48958720,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"9b9d9e6b892056b6"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"9b9d9e6b892056b6","traceState":"","parentSpanId":"7cae58d0f53be574","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:20.604836864Z","endTime":"2021-03-25T17:21:20.605860864Z","durationInNanos":1024000,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'apple', 'Qty': 1}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"ef20fcde9dee603a"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"ef20fcde9dee603a","traceState":"","parentSpanId":"3365305ba3a4b271","name":"updateItem","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:20.580970240Z","endTime":"2021-03-25T17:21:20.629545984Z","durationInNanos":48575744,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55720,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_item","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/update_item","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"42ca61064e4fbbf8"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"42ca61064e4fbbf8","traceState":"","parentSpanId":"0438f00bd05a7b08","name":"updateItem","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:20.496719104Z","endTime":"2021-03-25T17:21:20.552507648Z","durationInNanos":55788544,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55716,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_item","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/update_item","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"501798d3b0cd3ec2"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"501798d3b0cd3ec2","traceState":"","parentSpanId":"c1222bbdfe51df89","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:20.528640512Z","endTime":"2021-03-25T17:21:20.530060032Z","durationInNanos":1419520,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'orange', 'Qty': 3}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"97d426646346ed30"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"97d426646346ed30","traceState":"","parentSpanId":"dd1b6c64e71d0aeb","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:20.663003872Z","endTime":"2021-03-25T17:21:20.666492686Z","durationInNanos":3488814,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-8","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":135,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56442,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"e8f02bb624820c79"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"e8f02bb624820c79","traceState":"","parentSpanId":"002e214c71f9ddc3","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:20.723720232Z","endTime":"2021-03-25T17:21:20.727648Z","durationInNanos":3927768,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"span.attributes.thread@name":"http-nio-8087-exec-10","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":137,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"935cbd34eb35e840"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"935cbd34eb35e840","traceState":"","parentSpanId":"fc2889232f6bfee2","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:20.387662336Z","endTime":"2021-03-25T17:21:20.751462144Z","durationInNanos":363799808,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"span.attributes.http@url":"http://localhost:8084/checkout","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"002e214c71f9ddc3"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"002e214c71f9ddc3","traceState":"","parentSpanId":"6c8bd4a85a24b5dd","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:20.723002893Z","endTime":"2021-03-25T17:21:20.727804967Z","durationInNanos":4802074,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-10","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":137,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56444,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"53192fff614154f8"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"53192fff614154f8","traceState":"","parentSpanId":"97d426646346ed30","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:20.664003863Z","endTime":"2021-03-25T17:21:20.666249710Z","durationInNanos":2245847,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"span.attributes.thread@name":"http-nio-8087-exec-8","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":135,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"1a7b014c9c7784d1"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"1a7b014c9c7784d1","traceState":"","parentSpanId":"232c0433f6087a19","name":"updateItem","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:20.402530816Z","endTime":"2021-03-25T17:21:20.469684480Z","durationInNanos":67153664,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55712,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_item","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/update_item","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"daf8c1b89ef0f46e"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"daf8c1b89ef0f46e","traceState":"","parentSpanId":"9c3f9115f871f5a0","name":"checkout","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:20.391448832Z","endTime":"2021-03-25T17:21:20.735637760Z","durationInNanos":344188928,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"9670897539aa3cb5"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"9670897539aa3cb5","traceState":"","parentSpanId":"1a7b014c9c7784d1","name":"update_item","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:20.403919104Z","endTime":"2021-03-25T17:21:20.462452224Z","durationInNanos":58533120,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"aebd856791d9f772"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"aebd856791d9f772","traceState":"","parentSpanId":"daf8c1b89ef0f46e","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:20.392236032Z","endTime":"2021-03-25T17:21:20.712580096Z","durationInNanos":320344064,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"span.attributes.http@url":"http://localhost:8082/update_inventory","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"7cae58d0f53be574"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"7cae58d0f53be574","traceState":"","parentSpanId":"ef20fcde9dee603a","name":"update_item","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:20.582309632Z","endTime":"2021-03-25T17:21:20.620422912Z","durationInNanos":38113280,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"fbf637162922440c"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"fbf637162922440c","traceState":"","parentSpanId":"9670897539aa3cb5","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:20.446543616Z","endTime":"2021-03-25T17:21:20.448027904Z","durationInNanos":1484288,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'banana', 'Qty': 2}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"6c8bd4a85a24b5dd"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"6c8bd4a85a24b5dd","traceState":"","parentSpanId":"daf8c1b89ef0f46e","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:20.718433536Z","endTime":"2021-03-25T17:21:20.726854400Z","durationInNanos":8420864,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"dd1b6c64e71d0aeb"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"dd1b6c64e71d0aeb","traceState":"","parentSpanId":"81aca34992c3bb9a","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:20.654946048Z","endTime":"2021-03-25T17:21:20.668436736Z","durationInNanos":13490688,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"2e0bcc35b46cdc58"}}
+{"traceId":"aff58b618d5b6da700692607df9343ff","spanId":"2e0bcc35b46cdc58","traceState":"","parentSpanId":"aebd856791d9f772","name":"update_inventory","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:20.397296128Z","endTime":"2021-03-25T17:21:20.690810368Z","durationInNanos":293514240,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:21:20.759999232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":372645632,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8082,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":45576,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_inventory","span.attributes.http@host":"localhost:8082","span.attributes.http@target":"/update_inventory","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"6192513130aabc9d"}}
+{"traceId":"1e50a1c7c8d61d5a68331cb6c1c40a8f","spanId":"6192513130aabc9d","traceState":"","parentSpanId":"","name":"client_cancel_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:21.093042176Z","endTime":"2021-03-25T17:21:21.259883776Z","durationInNanos":166841600,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:21.259883776Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":166841600,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"e04e28e719caa00a"}}
+{"traceId":"1e50a1c7c8d61d5a68331cb6c1c40a8f","spanId":"e04e28e719caa00a","traceState":"","parentSpanId":"cebae850c737e427","name":"HTTP PUT","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:21.097510912Z","endTime":"2021-03-25T17:21:21.193844224Z","durationInNanos":96333312,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:21.259883776Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":166841600,"span.attributes.http@url":"http://localhost:8083/cart_empty","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"PUT","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"d843bf25bc4af127"}}
+{"traceId":"1e50a1c7c8d61d5a68331cb6c1c40a8f","spanId":"d843bf25bc4af127","traceState":"","parentSpanId":"cebae850c737e427","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:21.208868352Z","endTime":"2021-03-25T17:21:21.215510272Z","durationInNanos":6641920,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:21.259883776Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":166841600,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"65ed1b5a900339c5"}}
+{"traceId":"1e50a1c7c8d61d5a68331cb6c1c40a8f","spanId":"65ed1b5a900339c5","traceState":"","parentSpanId":"5780e7b8b048541d","name":"clear_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:21.096129280Z","endTime":"2021-03-25T17:21:21.237169920Z","durationInNanos":141040640,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:21.259883776Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":166841600,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"DELETE","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56714,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/clear_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/clear_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"f2f19e080c89a0af"}}
+{"traceId":"1e50a1c7c8d61d5a68331cb6c1c40a8f","spanId":"f2f19e080c89a0af","traceState":"","parentSpanId":"89ad4518c6e570fa","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:21.133353984Z","endTime":"2021-03-25T17:21:21.158749696Z","durationInNanos":25395712,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:21.259883776Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":166841600,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"TRUNCATE TABLE User_Carts","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"248105a4690d9618"}}
+{"traceId":"1e50a1c7c8d61d5a68331cb6c1c40a8f","spanId":"248105a4690d9618","traceState":"","parentSpanId":"89ad4518c6e570fa","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:21.125742592Z","endTime":"2021-03-25T17:21:21.126652672Z","durationInNanos":910080,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:21.259883776Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":166841600,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"SELECT ItemId, TotalQty FROM User_Carts","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"1089af99926957e9"}}
+{"traceId":"1e50a1c7c8d61d5a68331cb6c1c40a8f","spanId":"1089af99926957e9","traceState":"","parentSpanId":"5e6b5840fee372df","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:21.212668467Z","endTime":"2021-03-25T17:21:21.215023834Z","durationInNanos":2355367,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:21.259883776Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":166841600,"span.attributes.thread@name":"http-nio-8087-exec-2","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":129,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"89ad4518c6e570fa"}}
+{"traceId":"1e50a1c7c8d61d5a68331cb6c1c40a8f","spanId":"89ad4518c6e570fa","traceState":"","parentSpanId":"65579ac39ed78e8b","name":"cart_empty","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:21.103709696Z","endTime":"2021-03-25T17:21:21.167925248Z","durationInNanos":64215552,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:21.259883776Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":166841600,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"65579ac39ed78e8b"}}
+{"traceId":"1e50a1c7c8d61d5a68331cb6c1c40a8f","spanId":"65579ac39ed78e8b","traceState":"","parentSpanId":"e04e28e719caa00a","name":"cartEmpty","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:21.102652160Z","endTime":"2021-03-25T17:21:21.180791296Z","durationInNanos":78139136,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:21.259883776Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":166841600,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"PUT","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55730,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/cart_empty","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/cart_empty","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"5780e7b8b048541d"}}
+{"traceId":"1e50a1c7c8d61d5a68331cb6c1c40a8f","spanId":"5780e7b8b048541d","traceState":"","parentSpanId":"6192513130aabc9d","name":"HTTP DELETE","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:21.093342976Z","endTime":"2021-03-25T17:21:21.252124160Z","durationInNanos":158781184,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:21.259883776Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":166841600,"span.attributes.http@url":"http://localhost:8088/clear_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"DELETE","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"cebae850c737e427"}}
+{"traceId":"1e50a1c7c8d61d5a68331cb6c1c40a8f","spanId":"cebae850c737e427","traceState":"","parentSpanId":"65ed1b5a900339c5","name":"clear_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:21.097151232Z","endTime":"2021-03-25T17:21:21.229582080Z","durationInNanos":132430848,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:21.259883776Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":166841600,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"5e6b5840fee372df"}}
+{"traceId":"1e50a1c7c8d61d5a68331cb6c1c40a8f","spanId":"5e6b5840fee372df","traceState":"","parentSpanId":"d843bf25bc4af127","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:21.212002796Z","endTime":"2021-03-25T17:21:21.215186829Z","durationInNanos":3184033,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:21:21.259883776Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":166841600,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-2","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":129,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56452,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"519210d2f0b16de7"}}
+{"traceId":"c9c0606c8671aee3e4eaf7b908c2df03","spanId":"519210d2f0b16de7","traceState":"","parentSpanId":"","name":"client_create_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:22.074882304Z","endTime":"2021-03-25T17:21:22.504287232Z","durationInNanos":429404928,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:22.504287232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":429404928,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"0a8f2a5406669cd0"}}
+{"traceId":"c9c0606c8671aee3e4eaf7b908c2df03","spanId":"0a8f2a5406669cd0","traceState":"","parentSpanId":"6b49c6cd47144cf4","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:22.208856576Z","endTime":"2021-03-25T17:21:22.319724032Z","durationInNanos":110867456,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:22.504287232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":429404928,"span.attributes.http@url":"http://localhost:8083/add_item_to_cart","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"74f8214ff6302bb4"}}
+{"traceId":"c9c0606c8671aee3e4eaf7b908c2df03","spanId":"74f8214ff6302bb4","traceState":"","parentSpanId":"9d884fe648f374c0","name":"addItemToCart","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:22.086813440Z","endTime":"2021-03-25T17:21:22.174243840Z","durationInNanos":87430400,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:22.504287232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":429404928,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55738,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/add_item_to_cart","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/add_item_to_cart","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"a8c838c3e428ec44"}}
+{"traceId":"c9c0606c8671aee3e4eaf7b908c2df03","spanId":"a8c838c3e428ec44","traceState":"","parentSpanId":"4fe61f4c204b8b85","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:22.389894400Z","endTime":"2021-03-25T17:21:22.391394816Z","durationInNanos":1500416,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:22.504287232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":429404928,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'banana', 'Qty': '2'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"9c777ee6c23a6cf7"}}
+{"traceId":"c9c0606c8671aee3e4eaf7b908c2df03","spanId":"9c777ee6c23a6cf7","traceState":"","parentSpanId":"74f8214ff6302bb4","name":"add_item_to_cart","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:22.088591872Z","endTime":"2021-03-25T17:21:22.161988608Z","durationInNanos":73396736,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:22.504287232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":429404928,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"2fc3bd8e2583c489"}}
+{"traceId":"c9c0606c8671aee3e4eaf7b908c2df03","spanId":"2fc3bd8e2583c489","traceState":"","parentSpanId":"8ae8de0ae53b16a0","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:22.465665661Z","endTime":"2021-03-25T17:21:22.467963673Z","durationInNanos":2298012,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:22.504287232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":429404928,"span.attributes.thread@name":"http-nio-8087-exec-4","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":131,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"bc33c3276d43f701"}}
+{"traceId":"c9c0606c8671aee3e4eaf7b908c2df03","spanId":"bc33c3276d43f701","traceState":"","parentSpanId":"ed1a28b5e8524ce0","name":"add_item_to_cart","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:22.214860544Z","endTime":"2021-03-25T17:21:22.281757952Z","durationInNanos":66897408,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:22.504287232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":429404928,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"4fe61f4c204b8b85"}}
+{"traceId":"c9c0606c8671aee3e4eaf7b908c2df03","spanId":"4fe61f4c204b8b85","traceState":"","parentSpanId":"e63d9d3690995252","name":"add_item_to_cart","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:22.342049792Z","endTime":"2021-03-25T17:21:22.428568576Z","durationInNanos":86518784,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:22.504287232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":429404928,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"56a9aa15eb2b729e"}}
+{"traceId":"c9c0606c8671aee3e4eaf7b908c2df03","spanId":"56a9aa15eb2b729e","traceState":"","parentSpanId":"519210d2f0b16de7","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:22.075364352Z","endTime":"2021-03-25T17:21:22.497611776Z","durationInNanos":422247424,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:22.504287232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":429404928,"span.attributes.http@url":"http://localhost:8088/update_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"ae0d8f806540d5cd"}}
+{"traceId":"c9c0606c8671aee3e4eaf7b908c2df03","spanId":"ae0d8f806540d5cd","traceState":"","parentSpanId":"bc33c3276d43f701","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:22.265683712Z","endTime":"2021-03-25T17:21:22.266774784Z","durationInNanos":1091072,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:22.504287232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":429404928,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'orange', 'Qty': '3'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"INSERT INTO User_Carts (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"6be54c09fc04ece0"}}
+{"traceId":"c9c0606c8671aee3e4eaf7b908c2df03","spanId":"6be54c09fc04ece0","traceState":"","parentSpanId":"bc33c3276d43f701","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:22.254548992Z","endTime":"2021-03-25T17:21:22.255910400Z","durationInNanos":1361408,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:22.504287232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":429404928,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'orange', 'Qty': '3'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"4777fe10370f3cf5"}}
+{"traceId":"c9c0606c8671aee3e4eaf7b908c2df03","spanId":"4777fe10370f3cf5","traceState":"","parentSpanId":"9c777ee6c23a6cf7","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:22.142497280Z","endTime":"2021-03-25T17:21:22.146615296Z","durationInNanos":4118016,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:22.504287232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":429404928,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'apple', 'Qty': '1'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"INSERT INTO User_Carts (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"6b49c6cd47144cf4"}}
+{"traceId":"c9c0606c8671aee3e4eaf7b908c2df03","spanId":"6b49c6cd47144cf4","traceState":"","parentSpanId":"28bd75c7fb12f4cc","name":"update_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:22.081343488Z","endTime":"2021-03-25T17:21:22.479796992Z","durationInNanos":398453504,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:22.504287232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":429404928,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"8ae8de0ae53b16a0"}}
+{"traceId":"c9c0606c8671aee3e4eaf7b908c2df03","spanId":"8ae8de0ae53b16a0","traceState":"","parentSpanId":"a0ec3edc57edd84b","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:22.465003056Z","endTime":"2021-03-25T17:21:22.468122481Z","durationInNanos":3119425,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:22.504287232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":429404928,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-4","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":131,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56468,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"e63d9d3690995252"}}
+{"traceId":"c9c0606c8671aee3e4eaf7b908c2df03","spanId":"e63d9d3690995252","traceState":"","parentSpanId":"d33f2167a6bd28bc","name":"addItemToCart","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:22.340552960Z","endTime":"2021-03-25T17:21:22.440836864Z","durationInNanos":100283904,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:22.504287232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":429404928,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55746,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/add_item_to_cart","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/add_item_to_cart","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"9d884fe648f374c0"}}
+{"traceId":"c9c0606c8671aee3e4eaf7b908c2df03","spanId":"9d884fe648f374c0","traceState":"","parentSpanId":"6b49c6cd47144cf4","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:22.082465024Z","endTime":"2021-03-25T17:21:22.200846592Z","durationInNanos":118381568,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:22.504287232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":429404928,"span.attributes.http@url":"http://localhost:8083/add_item_to_cart","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"a0ec3edc57edd84b"}}
+{"traceId":"c9c0606c8671aee3e4eaf7b908c2df03","spanId":"a0ec3edc57edd84b","traceState":"","parentSpanId":"6b49c6cd47144cf4","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:22.459736064Z","endTime":"2021-03-25T17:21:22.469625344Z","durationInNanos":9889280,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:22.504287232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":429404928,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"28bd75c7fb12f4cc"}}
+{"traceId":"c9c0606c8671aee3e4eaf7b908c2df03","spanId":"28bd75c7fb12f4cc","traceState":"","parentSpanId":"56a9aa15eb2b729e","name":"update_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:22.079751168Z","endTime":"2021-03-25T17:21:22.484825600Z","durationInNanos":405074432,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:22.504287232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":429404928,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56722,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/update_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"ed1a28b5e8524ce0"}}
+{"traceId":"c9c0606c8671aee3e4eaf7b908c2df03","spanId":"ed1a28b5e8524ce0","traceState":"","parentSpanId":"0a8f2a5406669cd0","name":"addItemToCart","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:22.213234688Z","endTime":"2021-03-25T17:21:22.294454528Z","durationInNanos":81219840,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:22.504287232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":429404928,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55742,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/add_item_to_cart","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/add_item_to_cart","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"9d041fbb4e4f72c1"}}
+{"traceId":"c9c0606c8671aee3e4eaf7b908c2df03","spanId":"9d041fbb4e4f72c1","traceState":"","parentSpanId":"4fe61f4c204b8b85","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:22.414493952Z","endTime":"2021-03-25T17:21:22.415668736Z","durationInNanos":1174784,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:22.504287232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":429404928,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'banana', 'Qty': '2'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"INSERT INTO User_Carts (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"d33f2167a6bd28bc"}}
+{"traceId":"c9c0606c8671aee3e4eaf7b908c2df03","spanId":"d33f2167a6bd28bc","traceState":"","parentSpanId":"6b49c6cd47144cf4","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:22.336448256Z","endTime":"2021-03-25T17:21:22.453875968Z","durationInNanos":117427712,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:22.504287232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":429404928,"span.attributes.http@url":"http://localhost:8083/add_item_to_cart","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"04a010f9ee8bf16b"}}
+{"traceId":"c9c0606c8671aee3e4eaf7b908c2df03","spanId":"04a010f9ee8bf16b","traceState":"","parentSpanId":"9c777ee6c23a6cf7","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:22.130534656Z","endTime":"2021-03-25T17:21:22.132026624Z","durationInNanos":1491968,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:21:22.504287232Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":429404928,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'apple', 'Qty': '1'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"76cbcf558cf04819"}}
+{"traceId":"8832ed6abbb2a83516461960c89af49d","spanId":"76cbcf558cf04819","traceState":"","parentSpanId":"","name":"client_delivery_status","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:22.748892160Z","endTime":"2021-03-25T17:21:22.896669696Z","durationInNanos":147777536,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:21:22.896669696Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":147777536,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"e5c083f49dd5a05e"}}
+{"traceId":"8832ed6abbb2a83516461960c89af49d","spanId":"e5c083f49dd5a05e","traceState":"","parentSpanId":"1813e6ceecb24033","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:22.834003336Z","endTime":"2021-03-25T17:21:22.837250561Z","durationInNanos":3247225,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:21:22.896669696Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":147777536,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-6","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":133,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56476,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"a5ac11f134ed6971"}}
+{"traceId":"8832ed6abbb2a83516461960c89af49d","spanId":"a5ac11f134ed6971","traceState":"","parentSpanId":"aebfec9be2f4514f","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:22.781006848Z","endTime":"2021-03-25T17:21:22.781871616Z","durationInNanos":864768,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:21:22.896669696Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":147777536,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"SELECT * FROM User_Carts","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"1097a86537c3c79b"}}
+{"traceId":"8832ed6abbb2a83516461960c89af49d","spanId":"1097a86537c3c79b","traceState":"","parentSpanId":"76cbcf558cf04819","name":"HTTP GET","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:22.749218816Z","endTime":"2021-03-25T17:21:22.886730240Z","durationInNanos":137511424,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:21:22.896669696Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":147777536,"span.attributes.http@url":"http://localhost:8088/get_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"GET","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"c3fe7416eeb8c884"}}
+{"traceId":"8832ed6abbb2a83516461960c89af49d","spanId":"c3fe7416eeb8c884","traceState":"","parentSpanId":"3856bdf927e7242e","name":"HTTP GET","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:22.753215232Z","endTime":"2021-03-25T17:21:22.817274624Z","durationInNanos":64059392,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:21:22.896669696Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":147777536,"span.attributes.http@url":"http://localhost:8083/get_cart","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"GET","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"a673bc074b438374"}}
+{"traceId":"8832ed6abbb2a83516461960c89af49d","spanId":"a673bc074b438374","traceState":"","parentSpanId":"e5c083f49dd5a05e","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:22.834954238Z","endTime":"2021-03-25T17:21:22.837060125Z","durationInNanos":2105887,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:21:22.896669696Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":147777536,"span.attributes.thread@name":"http-nio-8087-exec-6","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":133,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"aebfec9be2f4514f"}}
+{"traceId":"8832ed6abbb2a83516461960c89af49d","spanId":"aebfec9be2f4514f","traceState":"","parentSpanId":"b704dc75f3ea9c1f","name":"get_cart","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:22.757242880Z","endTime":"2021-03-25T17:21:22.791789056Z","durationInNanos":34546176,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:21:22.896669696Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":147777536,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"3856bdf927e7242e"}}
+{"traceId":"8832ed6abbb2a83516461960c89af49d","spanId":"3856bdf927e7242e","traceState":"","parentSpanId":"3cc0a046c424c986","name":"get_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:21:22.752957440Z","endTime":"2021-03-25T17:21:22.854703360Z","durationInNanos":101745920,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:21:22.896669696Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":147777536,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"3cc0a046c424c986"}}
+{"traceId":"8832ed6abbb2a83516461960c89af49d","spanId":"3cc0a046c424c986","traceState":"","parentSpanId":"1097a86537c3c79b","name":"get_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:22.751980544Z","endTime":"2021-03-25T17:21:22.869998848Z","durationInNanos":118018304,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:21:22.896669696Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":147777536,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"GET","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56738,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/get_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/get_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"b704dc75f3ea9c1f"}}
+{"traceId":"8832ed6abbb2a83516461960c89af49d","spanId":"b704dc75f3ea9c1f","traceState":"","parentSpanId":"c3fe7416eeb8c884","name":"getCart","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:21:22.756071680Z","endTime":"2021-03-25T17:21:22.806841344Z","durationInNanos":50769664,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:21:22.896669696Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":147777536,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"GET","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55754,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/get_cart","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/get_cart","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"1813e6ceecb24033"}}
+{"traceId":"8832ed6abbb2a83516461960c89af49d","spanId":"1813e6ceecb24033","traceState":"","parentSpanId":"3856bdf927e7242e","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:21:22.830035200Z","endTime":"2021-03-25T17:21:22.839351296Z","durationInNanos":9316096,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:21:22.896669696Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":147777536,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"67c279e1100d75c3"}}
+{"traceId":"03f9c770db5ee2f1caac0afc36db49ba","spanId":"67c279e1100d75c3","traceState":"","parentSpanId":"","name":"client_pay_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:45.724285696Z","endTime":"2021-03-25T17:23:45.949285120Z","durationInNanos":224999424,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:45.949285120Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":224999424,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"d67c5bb617ba9203"}}
+{"traceId":"03f9c770db5ee2f1caac0afc36db49ba","spanId":"d67c5bb617ba9203","traceState":"","parentSpanId":"421660af43ed2f96","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:45.786072576Z","endTime":"2021-03-25T17:23:45.809853952Z","durationInNanos":23781376,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:45.949285120Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":224999424,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"TRUNCATE TABLE User_Carts","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"c54e1c2f383b1462"}}
+{"traceId":"03f9c770db5ee2f1caac0afc36db49ba","spanId":"c54e1c2f383b1462","traceState":"","parentSpanId":"918b5d6cac30fa13","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:45.863757056Z","endTime":"2021-03-25T17:23:45.879998720Z","durationInNanos":16241664,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:45.949285120Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":224999424,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"d35fa1184168044c"}}
+{"traceId":"03f9c770db5ee2f1caac0afc36db49ba","spanId":"d35fa1184168044c","traceState":"","parentSpanId":"72b91b096fe15a7e","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:45.874673885Z","endTime":"2021-03-25T17:23:45.876600285Z","durationInNanos":1926400,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:45.949285120Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":224999424,"span.attributes.thread@name":"http-nio-8087-exec-6","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":133,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"a4869b984bdcdb69"}}
+{"traceId":"03f9c770db5ee2f1caac0afc36db49ba","spanId":"a4869b984bdcdb69","traceState":"","parentSpanId":"a08a8a483b30d818","name":"cartSold","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:45.743732992Z","endTime":"2021-03-25T17:23:45.832090368Z","durationInNanos":88357376,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:45.949285120Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":224999424,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"DELETE","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55910,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/cart_sold","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/cart_sold","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"e8e61cf518ff0d47"}}
+{"traceId":"03f9c770db5ee2f1caac0afc36db49ba","spanId":"e8e61cf518ff0d47","traceState":"","parentSpanId":"67c279e1100d75c3","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:45.724760576Z","endTime":"2021-03-25T17:23:45.940549888Z","durationInNanos":215789312,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:45.949285120Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":224999424,"span.attributes.http@url":"http://localhost:8088/pay_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"72b91b096fe15a7e"}}
+{"traceId":"03f9c770db5ee2f1caac0afc36db49ba","spanId":"72b91b096fe15a7e","traceState":"","parentSpanId":"c54e1c2f383b1462","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:45.871003680Z","endTime":"2021-03-25T17:23:45.877972732Z","durationInNanos":6969052,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:45.949285120Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":224999424,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-6","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":133,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56632,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"918b5d6cac30fa13"}}
+{"traceId":"03f9c770db5ee2f1caac0afc36db49ba","spanId":"918b5d6cac30fa13","traceState":"","parentSpanId":"11c4d645b0b6544a","name":"pay_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:45.730200832Z","endTime":"2021-03-25T17:23:45.895294208Z","durationInNanos":165093376,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:45.949285120Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":224999424,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"11c4d645b0b6544a"}}
+{"traceId":"03f9c770db5ee2f1caac0afc36db49ba","spanId":"11c4d645b0b6544a","traceState":"","parentSpanId":"e8e61cf518ff0d47","name":"pay_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:45.728619520Z","endTime":"2021-03-25T17:23:45.909096192Z","durationInNanos":180476672,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:45.949285120Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":224999424,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56894,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/pay_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/pay_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"421660af43ed2f96"}}
+{"traceId":"03f9c770db5ee2f1caac0afc36db49ba","spanId":"421660af43ed2f96","traceState":"","parentSpanId":"a4869b984bdcdb69","name":"cart_sold","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:45.745376768Z","endTime":"2021-03-25T17:23:45.819226880Z","durationInNanos":73850112,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:45.949285120Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":224999424,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"a08a8a483b30d818"}}
+{"traceId":"03f9c770db5ee2f1caac0afc36db49ba","spanId":"a08a8a483b30d818","traceState":"","parentSpanId":"918b5d6cac30fa13","name":"HTTP DELETE","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:45.730639872Z","endTime":"2021-03-25T17:23:45.853490432Z","durationInNanos":122850560,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:45.949285120Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":224999424,"span.attributes.http@url":"http://localhost:8083/cart_sold","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"DELETE","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"9c09591194d5d102"}}
+{"traceId":"9cce3149f673950c9ccb0b2e104e730d","spanId":"9c09591194d5d102","traceState":"","parentSpanId":"","name":"client_delivery_status","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:46.998478592Z","endTime":"2021-03-25T17:23:47.113243648Z","durationInNanos":114765056,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:23:47.113243648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":114765056,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"68cb40977bd6eab8"}}
+{"traceId":"9cce3149f673950c9ccb0b2e104e730d","spanId":"68cb40977bd6eab8","traceState":"","parentSpanId":"3221fd7e7e20755a","name":"get_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:47.002198528Z","endTime":"2021-03-25T17:23:47.087424256Z","durationInNanos":85225728,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:23:47.113243648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":114765056,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"e3f874297f242418"}}
+{"traceId":"9cce3149f673950c9ccb0b2e104e730d","spanId":"e3f874297f242418","traceState":"","parentSpanId":"68cb40977bd6eab8","name":"HTTP GET","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:47.002505216Z","endTime":"2021-03-25T17:23:47.057874688Z","durationInNanos":55369472,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:23:47.113243648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":114765056,"span.attributes.http@url":"http://localhost:8083/get_cart","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"GET","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"1f0bc3af282b41e9"}}
+{"traceId":"9cce3149f673950c9ccb0b2e104e730d","spanId":"1f0bc3af282b41e9","traceState":"","parentSpanId":"cfa977442e9ff51c","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:47.068743984Z","endTime":"2021-03-25T17:23:47.070433471Z","durationInNanos":1689487,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:23:47.113243648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":114765056,"span.attributes.thread@name":"http-nio-8087-exec-8","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":135,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"cfa977442e9ff51c"}}
+{"traceId":"9cce3149f673950c9ccb0b2e104e730d","spanId":"cfa977442e9ff51c","traceState":"","parentSpanId":"47cdf0730792e64c","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:47.068003332Z","endTime":"2021-03-25T17:23:47.075911172Z","durationInNanos":7907840,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:23:47.113243648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":114765056,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-8","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":135,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56640,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"4e2b9046e9942e2b"}}
+{"traceId":"9cce3149f673950c9ccb0b2e104e730d","spanId":"4e2b9046e9942e2b","traceState":"","parentSpanId":"e3f874297f242418","name":"getCart","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:47.005123328Z","endTime":"2021-03-25T17:23:47.047171072Z","durationInNanos":42047744,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:23:47.113243648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":114765056,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"GET","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55918,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/get_cart","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/get_cart","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"df58ebf17b36f970"}}
+{"traceId":"9cce3149f673950c9ccb0b2e104e730d","spanId":"df58ebf17b36f970","traceState":"","parentSpanId":"4e2b9046e9942e2b","name":"get_cart","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:47.006217472Z","endTime":"2021-03-25T17:23:47.037839104Z","durationInNanos":31621632,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:23:47.113243648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":114765056,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"3221fd7e7e20755a"}}
+{"traceId":"9cce3149f673950c9ccb0b2e104e730d","spanId":"3221fd7e7e20755a","traceState":"","parentSpanId":"77555840320cb81d","name":"get_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:47.001265408Z","endTime":"2021-03-25T17:23:47.093001472Z","durationInNanos":91736064,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:23:47.113243648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":114765056,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"GET","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56902,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/get_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/get_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"888acd07415400a1"}}
+{"traceId":"9cce3149f673950c9ccb0b2e104e730d","spanId":"888acd07415400a1","traceState":"","parentSpanId":"df58ebf17b36f970","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:47.028200960Z","endTime":"2021-03-25T17:23:47.029597696Z","durationInNanos":1396736,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:23:47.113243648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":114765056,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"SELECT * FROM User_Carts","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"47cdf0730792e64c"}}
+{"traceId":"9cce3149f673950c9ccb0b2e104e730d","spanId":"47cdf0730792e64c","traceState":"","parentSpanId":"68cb40977bd6eab8","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:47.066144256Z","endTime":"2021-03-25T17:23:47.072265728Z","durationInNanos":6121472,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:23:47.113243648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":114765056,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"77555840320cb81d"}}
+{"traceId":"9cce3149f673950c9ccb0b2e104e730d","spanId":"77555840320cb81d","traceState":"","parentSpanId":"9c09591194d5d102","name":"HTTP GET","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:46.998782208Z","endTime":"2021-03-25T17:23:47.104758528Z","durationInNanos":105976320,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:23:47.113243648Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":114765056,"span.attributes.http@url":"http://localhost:8088/get_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"GET","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"1a0cb28940f561a8"}}
+{"traceId":"e991d404ff13b33caafd240b9afba158","spanId":"1a0cb28940f561a8","traceState":"","parentSpanId":"","name":"client_create_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:48.084371456Z","endTime":"2021-03-25T17:23:48.359975936Z","durationInNanos":275604480,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:48.359975936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":275604480,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"8066b9d09b81c92f"}}
+{"traceId":"e991d404ff13b33caafd240b9afba158","spanId":"8066b9d09b81c92f","traceState":"","parentSpanId":"831080abac6795cf","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:48.115765504Z","endTime":"2021-03-25T17:23:48.116704Z","durationInNanos":938496,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:48.359975936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":275604480,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'apple', 'Qty': '1'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"fd68372fc1dd1373"}}
+{"traceId":"e991d404ff13b33caafd240b9afba158","spanId":"fd68372fc1dd1373","traceState":"","parentSpanId":"a43a68ba4dec877d","name":"add_item_to_cart","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:48.163528704Z","endTime":"2021-03-25T17:23:48.214047232Z","durationInNanos":50518528,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:48.359975936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":275604480,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"a95608b807c2c60f"}}
+{"traceId":"e991d404ff13b33caafd240b9afba158","spanId":"a95608b807c2c60f","traceState":"","parentSpanId":"a8209b6ba0064d37","name":"update_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:48.088389888Z","endTime":"2021-03-25T17:23:48.337500416Z","durationInNanos":249110528,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:48.359975936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":275604480,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"b51ce57104b3621c"}}
+{"traceId":"e991d404ff13b33caafd240b9afba158","spanId":"b51ce57104b3621c","traceState":"","parentSpanId":"fd68372fc1dd1373","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:48.197120768Z","endTime":"2021-03-25T17:23:48.198455552Z","durationInNanos":1334784,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:48.359975936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":275604480,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'orange', 'Qty': '3'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"INSERT INTO User_Carts (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"a8209b6ba0064d37"}}
+{"traceId":"e991d404ff13b33caafd240b9afba158","spanId":"a8209b6ba0064d37","traceState":"","parentSpanId":"2a58f381f8c70e2e","name":"update_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:48.087305728Z","endTime":"2021-03-25T17:23:48.343833088Z","durationInNanos":256527360,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:48.359975936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":275604480,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56910,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/update_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"1c6cd3e12182ed11"}}
+{"traceId":"e991d404ff13b33caafd240b9afba158","spanId":"1c6cd3e12182ed11","traceState":"","parentSpanId":"36e00b610031f457","name":"add_item_to_cart","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:48.246038272Z","endTime":"2021-03-25T17:23:48.286460928Z","durationInNanos":40422656,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:48.359975936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":275604480,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"b83e713b3a5f444f"}}
+{"traceId":"e991d404ff13b33caafd240b9afba158","spanId":"b83e713b3a5f444f","traceState":"","parentSpanId":"fd68372fc1dd1373","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:48.185838592Z","endTime":"2021-03-25T17:23:48.186730752Z","durationInNanos":892160,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:48.359975936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":275604480,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'orange', 'Qty': '3'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"a43a68ba4dec877d"}}
+{"traceId":"e991d404ff13b33caafd240b9afba158","spanId":"a43a68ba4dec877d","traceState":"","parentSpanId":"29873549e67f2556","name":"addItemToCart","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:48.162587648Z","endTime":"2021-03-25T17:23:48.220827904Z","durationInNanos":58240256,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:48.359975936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":275604480,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55930,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/add_item_to_cart","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/add_item_to_cart","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"36e00b610031f457"}}
+{"traceId":"e991d404ff13b33caafd240b9afba158","spanId":"36e00b610031f457","traceState":"","parentSpanId":"83de8102e998c5f6","name":"addItemToCart","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:48.245083392Z","endTime":"2021-03-25T17:23:48.293122560Z","durationInNanos":48039168,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:48.359975936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":275604480,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55934,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/add_item_to_cart","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/add_item_to_cart","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"c2a85c2dc054a8fe"}}
+{"traceId":"e991d404ff13b33caafd240b9afba158","spanId":"c2a85c2dc054a8fe","traceState":"","parentSpanId":"831080abac6795cf","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:48.125617152Z","endTime":"2021-03-25T17:23:48.126324224Z","durationInNanos":707072,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:48.359975936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":275604480,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'apple', 'Qty': '1'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"INSERT INTO User_Carts (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"83de8102e998c5f6"}}
+{"traceId":"e991d404ff13b33caafd240b9afba158","spanId":"83de8102e998c5f6","traceState":"","parentSpanId":"a95608b807c2c60f","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:48.240862464Z","endTime":"2021-03-25T17:23:48.308264192Z","durationInNanos":67401728,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:48.359975936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":275604480,"span.attributes.http@url":"http://localhost:8083/add_item_to_cart","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"d606d3dd283b20c5"}}
+{"traceId":"e991d404ff13b33caafd240b9afba158","spanId":"d606d3dd283b20c5","traceState":"","parentSpanId":"b492c94dcd1b6a4d","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:48.324002749Z","endTime":"2021-03-25T17:23:48.327644015Z","durationInNanos":3641266,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:48.359975936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":275604480,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-10","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":137,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56656,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"29873549e67f2556"}}
+{"traceId":"e991d404ff13b33caafd240b9afba158","spanId":"29873549e67f2556","traceState":"","parentSpanId":"a95608b807c2c60f","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:48.159489536Z","endTime":"2021-03-25T17:23:48.233933312Z","durationInNanos":74443776,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:48.359975936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":275604480,"span.attributes.http@url":"http://localhost:8083/add_item_to_cart","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"831080abac6795cf"}}
+{"traceId":"e991d404ff13b33caafd240b9afba158","spanId":"831080abac6795cf","traceState":"","parentSpanId":"0fb86f8c49324042","name":"add_item_to_cart","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:48.092900864Z","endTime":"2021-03-25T17:23:48.137275392Z","durationInNanos":44374528,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:48.359975936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":275604480,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"6b2ede68bc8fa5f4"}}
+{"traceId":"e991d404ff13b33caafd240b9afba158","spanId":"6b2ede68bc8fa5f4","traceState":"","parentSpanId":"1c6cd3e12182ed11","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:48.275602688Z","endTime":"2021-03-25T17:23:48.276599040Z","durationInNanos":996352,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:48.359975936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":275604480,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'banana', 'Qty': '2'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"INSERT INTO User_Carts (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"bfe27ce19f70e729"}}
+{"traceId":"e991d404ff13b33caafd240b9afba158","spanId":"bfe27ce19f70e729","traceState":"","parentSpanId":"1c6cd3e12182ed11","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:48.268308736Z","endTime":"2021-03-25T17:23:48.269206272Z","durationInNanos":897536,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:48.359975936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":275604480,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'banana', 'Qty': '2'}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"6dc05e88f4467863"}}
+{"traceId":"e991d404ff13b33caafd240b9afba158","spanId":"6dc05e88f4467863","traceState":"","parentSpanId":"d606d3dd283b20c5","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:48.324561176Z","endTime":"2021-03-25T17:23:48.327441217Z","durationInNanos":2880041,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:48.359975936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":275604480,"span.attributes.thread@name":"http-nio-8087-exec-10","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":137,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"c42df275e25b0e8f"}}
+{"traceId":"e991d404ff13b33caafd240b9afba158","spanId":"c42df275e25b0e8f","traceState":"","parentSpanId":"a95608b807c2c60f","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:48.088905472Z","endTime":"2021-03-25T17:23:48.153333504Z","durationInNanos":64428032,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:48.359975936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":275604480,"span.attributes.http@url":"http://localhost:8083/add_item_to_cart","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"2a58f381f8c70e2e"}}
+{"traceId":"e991d404ff13b33caafd240b9afba158","spanId":"2a58f381f8c70e2e","traceState":"","parentSpanId":"1a0cb28940f561a8","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:48.084678144Z","endTime":"2021-03-25T17:23:48.353726976Z","durationInNanos":269048832,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:48.359975936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":275604480,"span.attributes.http@url":"http://localhost:8088/update_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"0fb86f8c49324042"}}
+{"traceId":"e991d404ff13b33caafd240b9afba158","spanId":"0fb86f8c49324042","traceState":"","parentSpanId":"c42df275e25b0e8f","name":"addItemToCart","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:48.091877632Z","endTime":"2021-03-25T17:23:48.143332864Z","durationInNanos":51455232,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:48.359975936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":275604480,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55926,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/add_item_to_cart","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/add_item_to_cart","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"b492c94dcd1b6a4d"}}
+{"traceId":"e991d404ff13b33caafd240b9afba158","spanId":"b492c94dcd1b6a4d","traceState":"","parentSpanId":"a95608b807c2c60f","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:48.318687232Z","endTime":"2021-03-25T17:23:48.327306496Z","durationInNanos":8619264,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:23:48.359975936Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":275604480,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"577a7fd9713d82e3"}}
+{"traceId":"eeef72a379b08acc21a7a1da140b496f","spanId":"577a7fd9713d82e3","traceState":"","parentSpanId":"","name":"client_delivery_status","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:00.337438720Z","endTime":"2021-03-25T17:24:00.443709952Z","durationInNanos":106271232,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:24:00.443709952Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":106271232,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"ee14230a7bf6a820"}}
+{"traceId":"eeef72a379b08acc21a7a1da140b496f","spanId":"ee14230a7bf6a820","traceState":"","parentSpanId":"3bbfbbb8b5ccdca9","name":"HTTP GET","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:00.341403648Z","endTime":"2021-03-25T17:24:00.396574208Z","durationInNanos":55170560,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:24:00.443709952Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":106271232,"span.attributes.http@url":"http://localhost:8083/get_cart","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"GET","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"4d51ee300ffdafab"}}
+{"traceId":"eeef72a379b08acc21a7a1da140b496f","spanId":"4d51ee300ffdafab","traceState":"","parentSpanId":"ee14230a7bf6a820","name":"getCart","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:00.344109824Z","endTime":"2021-03-25T17:24:00.386901504Z","durationInNanos":42791680,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:24:00.443709952Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":106271232,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"GET","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55978,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/get_cart","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/get_cart","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"3e3c69d965b84c07"}}
+{"traceId":"eeef72a379b08acc21a7a1da140b496f","spanId":"3e3c69d965b84c07","traceState":"","parentSpanId":"9776392cce908429","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:00.367306496Z","endTime":"2021-03-25T17:24:00.369491712Z","durationInNanos":2185216,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:24:00.443709952Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":106271232,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"SELECT * FROM User_Carts","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"0fb4d938a4db181b"}}
+{"traceId":"eeef72a379b08acc21a7a1da140b496f","spanId":"0fb4d938a4db181b","traceState":"","parentSpanId":"3bbfbbb8b5ccdca9","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:00.403020288Z","endTime":"2021-03-25T17:24:00.408785408Z","durationInNanos":5765120,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:24:00.443709952Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":106271232,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"3bbfbbb8b5ccdca9"}}
+{"traceId":"eeef72a379b08acc21a7a1da140b496f","spanId":"3bbfbbb8b5ccdca9","traceState":"","parentSpanId":"1c599f19b10082a4","name":"get_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:00.341143552Z","endTime":"2021-03-25T17:24:00.415056384Z","durationInNanos":73912832,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:24:00.443709952Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":106271232,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"1c599f19b10082a4"}}
+{"traceId":"eeef72a379b08acc21a7a1da140b496f","spanId":"1c599f19b10082a4","traceState":"","parentSpanId":"458c486c6a8e9527","name":"get_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:00.340208128Z","endTime":"2021-03-25T17:24:00.420619008Z","durationInNanos":80410880,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:24:00.443709952Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":106271232,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"GET","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56962,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/get_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/get_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"9776392cce908429"}}
+{"traceId":"eeef72a379b08acc21a7a1da140b496f","spanId":"9776392cce908429","traceState":"","parentSpanId":"4d51ee300ffdafab","name":"get_cart","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:00.345138944Z","endTime":"2021-03-25T17:24:00.379310336Z","durationInNanos":34171392,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:24:00.443709952Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":106271232,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"35baa091df01834e"}}
+{"traceId":"eeef72a379b08acc21a7a1da140b496f","spanId":"35baa091df01834e","traceState":"","parentSpanId":"37729eb1aa61f9a2","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:00.406588562Z","endTime":"2021-03-25T17:24:00.409684446Z","durationInNanos":3095884,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:24:00.443709952Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":106271232,"span.attributes.thread@name":"http-nio-8087-exec-10","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":137,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"37729eb1aa61f9a2"}}
+{"traceId":"eeef72a379b08acc21a7a1da140b496f","spanId":"37729eb1aa61f9a2","traceState":"","parentSpanId":"0fb4d938a4db181b","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:00.406003034Z","endTime":"2021-03-25T17:24:00.409877327Z","durationInNanos":3874293,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:24:00.443709952Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":106271232,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-10","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":137,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56700,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"458c486c6a8e9527"}}
+{"traceId":"eeef72a379b08acc21a7a1da140b496f","spanId":"458c486c6a8e9527","traceState":"","parentSpanId":"577a7fd9713d82e3","name":"HTTP GET","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:00.337747200Z","endTime":"2021-03-25T17:24:00.432306176Z","durationInNanos":94558976,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_delivery_status","traceGroupFields.endTime":"2021-03-25T17:24:00.443709952Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":106271232,"span.attributes.http@url":"http://localhost:8088/get_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"GET","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"44875f61ade8d4d1"}}
+{"traceId":"852a3fa441c2dd319d94be4e90cdc593","spanId":"44875f61ade8d4d1","traceState":"","parentSpanId":"","name":"client_create_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:01.302660864Z","endTime":"2021-03-25T17:24:01.342219776Z","durationInNanos":39558912,"serviceName":"frontend-client","events":[{"time":"2021-03-25T17:24:01.342160896Z","name":"exception","attributes":{"exception@message":"","exception@type":"AssertionError","exception@stacktrace":"Traceback (most recent call last):\n File \"/usr/lib/python3.6/site-packages/opentelemetry/sdk/trace/__init__.py\", line 804, in use_span\n yield span\n File \"/app/client.py\", line 198, in createOrder\n assert updateOrderAPIRequest.status_code == 200\nAssertionError\n"},"droppedAttributesCount":0}],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:01.342219776Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":39558912,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","status.message":"AssertionError: ","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":2,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"1dcf16c24109157c"}}
+{"traceId":"852a3fa441c2dd319d94be4e90cdc593","spanId":"1dcf16c24109157c","traceState":"","parentSpanId":"c762ea561c90bacc","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:01.309003470Z","endTime":"2021-03-25T17:24:01.311803818Z","durationInNanos":2800348,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:01.342219776Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":39558912,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-2","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":129,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56704,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"f90e7d8e2be7ed42"}}
+{"traceId":"852a3fa441c2dd319d94be4e90cdc593","spanId":"f90e7d8e2be7ed42","traceState":"","parentSpanId":"44875f61ade8d4d1","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:01.302975744Z","endTime":"2021-03-25T17:24:01.333780224Z","durationInNanos":30804480,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:01.342219776Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":39558912,"span.attributes.http@url":"http://localhost:8088/update_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"SERVICE UNAVAILABLE","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":2,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":503}
+{"index":{"_id":"b8c7c406109e6853"}}
+{"traceId":"852a3fa441c2dd319d94be4e90cdc593","spanId":"b8c7c406109e6853","traceState":"","parentSpanId":"f90e7d8e2be7ed42","name":"update_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:01.305604608Z","endTime":"2021-03-25T17:24:01.322971904Z","durationInNanos":17367296,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:01.342219776Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":39558912,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"SERVICE UNAVAILABLE","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":2,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56970,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/update_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":503}
+{"index":{"_id":"c762ea561c90bacc"}}
+{"traceId":"852a3fa441c2dd319d94be4e90cdc593","spanId":"c762ea561c90bacc","traceState":"","parentSpanId":"b8c7c406109e6853","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:01.306888704Z","endTime":"2021-03-25T17:24:01.314155008Z","durationInNanos":7266304,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:01.342219776Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":39558912,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"c04780a1b5dfb8db"}}
+{"traceId":"852a3fa441c2dd319d94be4e90cdc593","spanId":"c04780a1b5dfb8db","traceState":"","parentSpanId":"1dcf16c24109157c","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:01.309685404Z","endTime":"2021-03-25T17:24:01.311637506Z","durationInNanos":1952102,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_create_order","traceGroupFields.endTime":"2021-03-25T17:24:01.342219776Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":39558912,"span.attributes.thread@name":"http-nio-8087-exec-2","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":129,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"9e00987a5ddb1389"}}
+{"traceId":"61e206cdf99796bd5d0d6660fafeaa13","spanId":"9e00987a5ddb1389","traceState":"","parentSpanId":"","name":"client_cancel_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:02.180425472Z","endTime":"2021-03-25T17:24:02.499118080Z","durationInNanos":318692608,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:24:02.499118080Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":318692608,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"df08a6411e1e1320"}}
+{"traceId":"61e206cdf99796bd5d0d6660fafeaa13","spanId":"df08a6411e1e1320","traceState":"","parentSpanId":"00dbedd07cdc6605","name":"HTTP PUT","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:02.184506880Z","endTime":"2021-03-25T17:24:02.340449536Z","durationInNanos":155942656,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:24:02.499118080Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":318692608,"span.attributes.http@url":"http://localhost:8083/cart_empty","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"PUT","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"c55168f05f4c0788"}}
+{"traceId":"61e206cdf99796bd5d0d6660fafeaa13","spanId":"c55168f05f4c0788","traceState":"","parentSpanId":"6a1caed3da777ed1","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:02.218972672Z","endTime":"2021-03-25T17:24:02.244534528Z","durationInNanos":25561856,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:24:02.499118080Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":318692608,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"TRUNCATE TABLE User_Carts","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"c9b1c98d861a21ad"}}
+{"traceId":"61e206cdf99796bd5d0d6660fafeaa13","spanId":"c9b1c98d861a21ad","traceState":"","parentSpanId":"df08a6411e1e1320","name":"cartEmpty","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:02.187168768Z","endTime":"2021-03-25T17:24:02.259351040Z","durationInNanos":72182272,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:24:02.499118080Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":318692608,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"PUT","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55990,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/cart_empty","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/cart_empty","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"6a1caed3da777ed1"}}
+{"traceId":"61e206cdf99796bd5d0d6660fafeaa13","spanId":"6a1caed3da777ed1","traceState":"","parentSpanId":"c9b1c98d861a21ad","name":"cart_empty","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:02.188187392Z","endTime":"2021-03-25T17:24:02.252571136Z","durationInNanos":64383744,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:24:02.499118080Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":318692608,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"105e06978064066e"}}
+{"traceId":"61e206cdf99796bd5d0d6660fafeaa13","spanId":"105e06978064066e","traceState":"","parentSpanId":"7db6b40beda6e9f5","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:02.371685355Z","endTime":"2021-03-25T17:24:02.387731715Z","durationInNanos":16046360,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:24:02.499118080Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":318692608,"span.attributes.thread@name":"http-nio-8087-exec-4","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":131,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"db71b12b5a3048a7"}}
+{"traceId":"61e206cdf99796bd5d0d6660fafeaa13","spanId":"db71b12b5a3048a7","traceState":"","parentSpanId":"00dbedd07cdc6605","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:02.362716160Z","endTime":"2021-03-25T17:24:02.389943040Z","durationInNanos":27226880,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:24:02.499118080Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":318692608,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"980fd01685cf617b"}}
+{"traceId":"61e206cdf99796bd5d0d6660fafeaa13","spanId":"980fd01685cf617b","traceState":"","parentSpanId":"6a1caed3da777ed1","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:02.211183360Z","endTime":"2021-03-25T17:24:02.211932416Z","durationInNanos":749056,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:24:02.499118080Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":318692608,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"SELECT ItemId, TotalQty FROM User_Carts","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"7db6b40beda6e9f5"}}
+{"traceId":"61e206cdf99796bd5d0d6660fafeaa13","spanId":"7db6b40beda6e9f5","traceState":"","parentSpanId":"db71b12b5a3048a7","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:02.371004080Z","endTime":"2021-03-25T17:24:02.387975467Z","durationInNanos":16971387,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:24:02.499118080Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":318692608,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-4","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":131,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56712,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"fbd7035fb360050b"}}
+{"traceId":"61e206cdf99796bd5d0d6660fafeaa13","spanId":"fbd7035fb360050b","traceState":"","parentSpanId":"9e00987a5ddb1389","name":"HTTP DELETE","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:02.180734208Z","endTime":"2021-03-25T17:24:02.483553280Z","durationInNanos":302819072,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:24:02.499118080Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":318692608,"span.attributes.http@url":"http://localhost:8088/clear_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"DELETE","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"00dbedd07cdc6605"}}
+{"traceId":"61e206cdf99796bd5d0d6660fafeaa13","spanId":"00dbedd07cdc6605","traceState":"","parentSpanId":"f9698d94a2bc5e93","name":"clear_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:02.184233216Z","endTime":"2021-03-25T17:24:02.435438592Z","durationInNanos":251205376,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:24:02.499118080Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":318692608,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"f9698d94a2bc5e93"}}
+{"traceId":"61e206cdf99796bd5d0d6660fafeaa13","spanId":"f9698d94a2bc5e93","traceState":"","parentSpanId":"fbd7035fb360050b","name":"clear_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:02.183235584Z","endTime":"2021-03-25T17:24:02.459529472Z","durationInNanos":276293888,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:24:02.499118080Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":318692608,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"DELETE","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56974,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/clear_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/clear_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"e41a501e2b463e4f"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"e41a501e2b463e4f","traceState":"","parentSpanId":"","name":"client_checkout","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:02.873396736Z","endTime":"2021-03-25T17:24:03.338473728Z","durationInNanos":465076992,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"2ab2346b8a2256ec"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"2ab2346b8a2256ec","traceState":"","parentSpanId":"83c126b28a4e3ba1","name":"update_item","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:03.022118656Z","endTime":"2021-03-25T17:24:03.106782976Z","durationInNanos":84664320,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"68e7c47304e4e3b7"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"68e7c47304e4e3b7","traceState":"","parentSpanId":"2f9dedfb4a0ce070","name":"updateItem","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:02.950728448Z","endTime":"2021-03-25T17:24:02.992670464Z","durationInNanos":41942016,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56004,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_item","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/update_item","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"6bf83533c911fa84"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"6bf83533c911fa84","traceState":"","parentSpanId":"8f46983d67cbfb08","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:02.974441472Z","endTime":"2021-03-25T17:24:02.975385344Z","durationInNanos":943872,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'orange', 'Qty': 3}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"8f46983d67cbfb08"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"8f46983d67cbfb08","traceState":"","parentSpanId":"68e7c47304e4e3b7","name":"update_item","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:02.951733248Z","endTime":"2021-03-25T17:24:02.986525952Z","durationInNanos":34792704,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"71eb12de1c6f0856"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"71eb12de1c6f0856","traceState":"","parentSpanId":"68757226266da9fb","name":"update_item","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:02.885796608Z","endTime":"2021-03-25T17:24:02.920141824Z","durationInNanos":34345216,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"40490d98955d0ee8"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"40490d98955d0ee8","traceState":"","parentSpanId":"6a721b1de414f8ea","name":"checkout","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:02.877249280Z","endTime":"2021-03-25T17:24:03.263083264Z","durationInNanos":385833984,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"af0ac45bddb77682"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"af0ac45bddb77682","traceState":"","parentSpanId":"ca2bbe96720126cd","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:03.155657816Z","endTime":"2021-03-25T17:24:03.157957035Z","durationInNanos":2299219,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"span.attributes.thread@name":"http-nio-8087-exec-6","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":133,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"88b577c6de6a1a0c"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"88b577c6de6a1a0c","traceState":"","parentSpanId":"71eb12de1c6f0856","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:02.908273152Z","endTime":"2021-03-25T17:24:02.909201664Z","durationInNanos":928512,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'banana', 'Qty': 2}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"04715e4b7c6c8c67"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"04715e4b7c6c8c67","traceState":"","parentSpanId":"1b922c46eca3681a","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:03.229519732Z","endTime":"2021-03-25T17:24:03.231141820Z","durationInNanos":1622088,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"span.attributes.thread@name":"http-nio-8087-exec-8","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":135,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"482f5d2e5d2e01a5"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"482f5d2e5d2e01a5","traceState":"","parentSpanId":"40490d98955d0ee8","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:02.877730560Z","endTime":"2021-03-25T17:24:03.218989568Z","durationInNanos":341259008,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"span.attributes.http@url":"http://localhost:8082/update_inventory","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"6a721b1de414f8ea"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"6a721b1de414f8ea","traceState":"","parentSpanId":"1e69dea1cc3bb675","name":"payment","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:02.876323072Z","endTime":"2021-03-25T17:24:03.275425024Z","durationInNanos":399101952,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8084,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":50604,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/checkout","span.attributes.http@host":"localhost:8084","span.attributes.http@target":"/checkout","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"a40b2ee1ad083444"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"a40b2ee1ad083444","traceState":"","parentSpanId":"544d4016f47447db","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:02.881920768Z","endTime":"2021-03-25T17:24:02.937480192Z","durationInNanos":55559424,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"span.attributes.http@url":"http://localhost:8083/update_item","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"83c126b28a4e3ba1"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"83c126b28a4e3ba1","traceState":"","parentSpanId":"bace8af7ec6dcea1","name":"updateItem","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:03.020527872Z","endTime":"2021-03-25T17:24:03.125422848Z","durationInNanos":104894976,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56008,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_item","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/update_item","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"544d4016f47447db"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"544d4016f47447db","traceState":"","parentSpanId":"6a5c44f70df8ba60","name":"update_inventory","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:24:02.881451264Z","endTime":"2021-03-25T17:24:03.184011776Z","durationInNanos":302560512,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"c5583c927c0eaa55"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"c5583c927c0eaa55","traceState":"","parentSpanId":"2ab2346b8a2256ec","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:03.082126592Z","endTime":"2021-03-25T17:24:03.090554112Z","durationInNanos":8427520,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'apple', 'Qty': 1}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"68757226266da9fb"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"68757226266da9fb","traceState":"","parentSpanId":"a40b2ee1ad083444","name":"updateItem","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:02.884764672Z","endTime":"2021-03-25T17:24:02.926254336Z","durationInNanos":41489664,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56000,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_item","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/update_item","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"fd6830be1f9eb762"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"fd6830be1f9eb762","traceState":"","parentSpanId":"544d4016f47447db","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:03.152131584Z","endTime":"2021-03-25T17:24:03.160588288Z","durationInNanos":8456704,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"bace8af7ec6dcea1"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"bace8af7ec6dcea1","traceState":"","parentSpanId":"544d4016f47447db","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:03.011334400Z","endTime":"2021-03-25T17:24:03.140665088Z","durationInNanos":129330688,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"span.attributes.http@url":"http://localhost:8083/update_item","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"9072fd63220b9e78"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"9072fd63220b9e78","traceState":"","parentSpanId":"40490d98955d0ee8","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:03.225950976Z","endTime":"2021-03-25T17:24:03.232076800Z","durationInNanos":6125824,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"6a5c44f70df8ba60"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"6a5c44f70df8ba60","traceState":"","parentSpanId":"482f5d2e5d2e01a5","name":"update_inventory","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:02.880508160Z","endTime":"2021-03-25T17:24:03.195376128Z","durationInNanos":314867968,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8082,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":45864,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_inventory","span.attributes.http@host":"localhost:8082","span.attributes.http@target":"/update_inventory","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"1b922c46eca3681a"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"1b922c46eca3681a","traceState":"","parentSpanId":"9072fd63220b9e78","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:03.229002687Z","endTime":"2021-03-25T17:24:03.231262707Z","durationInNanos":2260020,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-8","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":135,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56732,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"1e69dea1cc3bb675"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"1e69dea1cc3bb675","traceState":"","parentSpanId":"e41a501e2b463e4f","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:02.873706752Z","endTime":"2021-03-25T17:24:03.313766144Z","durationInNanos":440059392,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"span.attributes.http@url":"http://localhost:8084/checkout","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"ca2bbe96720126cd"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"ca2bbe96720126cd","traceState":"","parentSpanId":"fd6830be1f9eb762","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:24:03.155003840Z","endTime":"2021-03-25T17:24:03.158155250Z","durationInNanos":3151410,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-6","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":133,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56730,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"2f9dedfb4a0ce070"}}
+{"traceId":"7c2bfe48d13025cbe3de0d1e679110b3","spanId":"2f9dedfb4a0ce070","traceState":"","parentSpanId":"544d4016f47447db","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:24:02.947977728Z","endTime":"2021-03-25T17:24:03.002557696Z","durationInNanos":54579968,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:24:03.338473728Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":465076992,"span.attributes.http@url":"http://localhost:8083/update_item","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"332629e923ac50db"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"332629e923ac50db","traceState":"","parentSpanId":"","name":"client_checkout","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:50.139097856Z","endTime":"2021-03-25T17:23:50.452619520Z","durationInNanos":313521664,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"890da55b4bf3f689"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"890da55b4bf3f689","traceState":"","parentSpanId":"6d13264d84ba303a","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:50.147685888Z","endTime":"2021-03-25T17:23:50.208268032Z","durationInNanos":60582144,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"span.attributes.http@url":"http://localhost:8083/update_item","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"4581bfcf161daadf"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"4581bfcf161daadf","traceState":"","parentSpanId":"6f3f0792cb8e496b","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:50.174119680Z","endTime":"2021-03-25T17:23:50.175104256Z","durationInNanos":984576,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'banana', 'Qty': 2}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"6d13264d84ba303a"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"6d13264d84ba303a","traceState":"","parentSpanId":"de75ad62453ecad2","name":"update_inventory","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:50.147162880Z","endTime":"2021-03-25T17:23:50.376714496Z","durationInNanos":229551616,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"7f42156901df64b2"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"7f42156901df64b2","traceState":"","parentSpanId":"d5d6ed934d615c30","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:50.366125705Z","endTime":"2021-03-25T17:23:50.367776649Z","durationInNanos":1650944,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"span.attributes.thread@name":"http-nio-8087-exec-4","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":131,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"d62eadcb8d597bc8"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"d62eadcb8d597bc8","traceState":"","parentSpanId":"6d13264d84ba303a","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:50.363076352Z","endTime":"2021-03-25T17:23:50.370151936Z","durationInNanos":7075584,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"21189f9303855cfa"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"21189f9303855cfa","traceState":"","parentSpanId":"66ddc3bd5b8d66de","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:50.415933995Z","endTime":"2021-03-25T17:23:50.417755384Z","durationInNanos":1821389,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"span.attributes.thread@name":"http-nio-8087-exec-6","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":133,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"28e67bf8b11bb104"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"28e67bf8b11bb104","traceState":"","parentSpanId":"7fd52e0343db5fbb","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:50.410137856Z","endTime":"2021-03-25T17:23:50.420290048Z","durationInNanos":10152192,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"5bd5bd45f33b2b21"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"5bd5bd45f33b2b21","traceState":"","parentSpanId":"453806261422f6ca","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:50.242040576Z","endTime":"2021-03-25T17:23:50.243015680Z","durationInNanos":975104,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'orange', 'Qty': 3}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"d5d6ed934d615c30"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"d5d6ed934d615c30","traceState":"","parentSpanId":"d62eadcb8d597bc8","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:50.365003562Z","endTime":"2021-03-25T17:23:50.367971850Z","durationInNanos":2968288,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-4","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":131,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56682,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"45f70d65167608fc"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"45f70d65167608fc","traceState":"","parentSpanId":"4327f98275af2884","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:50.327499008Z","endTime":"2021-03-25T17:23:50.328442112Z","durationInNanos":943104,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'apple', 'Qty': 1}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"de75ad62453ecad2"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"de75ad62453ecad2","traceState":"","parentSpanId":"2e7c2bbadd552e62","name":"update_inventory","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:50.146197248Z","endTime":"2021-03-25T17:23:50.384520192Z","durationInNanos":238322944,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8082,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":45816,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_inventory","span.attributes.http@host":"localhost:8082","span.attributes.http@target":"/update_inventory","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"b543ad1e5818e7d1"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"b543ad1e5818e7d1","traceState":"","parentSpanId":"332629e923ac50db","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:50.139403520Z","endTime":"2021-03-25T17:23:50.446737664Z","durationInNanos":307334144,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"span.attributes.http@url":"http://localhost:8084/checkout","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"66ddc3bd5b8d66de"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"66ddc3bd5b8d66de","traceState":"","parentSpanId":"28e67bf8b11bb104","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:50.415003489Z","endTime":"2021-03-25T17:23:50.417955096Z","durationInNanos":2951607,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-6","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":133,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56684,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"2e7c2bbadd552e62"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"2e7c2bbadd552e62","traceState":"","parentSpanId":"7fd52e0343db5fbb","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:50.143588096Z","endTime":"2021-03-25T17:23:50.400794624Z","durationInNanos":257206528,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"span.attributes.http@url":"http://localhost:8082/update_inventory","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"528b94722fcafb8b"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"528b94722fcafb8b","traceState":"","parentSpanId":"6d13264d84ba303a","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:50.214470400Z","endTime":"2021-03-25T17:23:50.290921216Z","durationInNanos":76450816,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"span.attributes.http@url":"http://localhost:8083/update_item","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"453806261422f6ca"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"453806261422f6ca","traceState":"","parentSpanId":"a82da103bfa98cda","name":"update_item","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:50.219420416Z","endTime":"2021-03-25T17:23:50.262448640Z","durationInNanos":43028224,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"4327f98275af2884"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"4327f98275af2884","traceState":"","parentSpanId":"20fb32e5166673b1","name":"update_item","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:50.303989760Z","endTime":"2021-03-25T17:23:50.339736832Z","durationInNanos":35747072,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"a82da103bfa98cda"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"a82da103bfa98cda","traceState":"","parentSpanId":"528b94722fcafb8b","name":"updateItem","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:50.218430976Z","endTime":"2021-03-25T17:23:50.273203200Z","durationInNanos":54772224,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55956,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_item","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/update_item","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"dadacac33c3d835d"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"dadacac33c3d835d","traceState":"","parentSpanId":"b543ad1e5818e7d1","name":"payment","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:50.142040576Z","endTime":"2021-03-25T17:23:50.434752512Z","durationInNanos":292711936,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8084,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":50556,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/checkout","span.attributes.http@host":"localhost:8084","span.attributes.http@target":"/checkout","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"20fb32e5166673b1"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"20fb32e5166673b1","traceState":"","parentSpanId":"7a5e15e7fcb71763","name":"updateItem","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:50.302988288Z","endTime":"2021-03-25T17:23:50.345838848Z","durationInNanos":42850560,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55960,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_item","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/update_item","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"7fd52e0343db5fbb"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"7fd52e0343db5fbb","traceState":"","parentSpanId":"dadacac33c3d835d","name":"checkout","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:50.143095296Z","endTime":"2021-03-25T17:23:50.428341504Z","durationInNanos":285246208,"serviceName":"payment","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140260160921552","resource.attributes.service@name":"payment","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"69969783a0394304"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"69969783a0394304","traceState":"","parentSpanId":"890da55b4bf3f689","name":"updateItem","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:50.150543360Z","endTime":"2021-03-25T17:23:50.194194432Z","durationInNanos":43651072,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55952,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/update_item","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/update_item","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"7a5e15e7fcb71763"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"7a5e15e7fcb71763","traceState":"","parentSpanId":"6d13264d84ba303a","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:50.300090112Z","endTime":"2021-03-25T17:23:50.356072192Z","durationInNanos":55982080,"serviceName":"inventory","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"span.attributes.http@url":"http://localhost:8083/update_item","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140016202633168","resource.attributes.service@name":"inventory","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"6f3f0792cb8e496b"}}
+{"traceId":"ce6b3fddebc63e2a83f8a08fd51afae7","spanId":"6f3f0792cb8e496b","traceState":"","parentSpanId":"69969783a0394304","name":"update_item","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:50.151575808Z","endTime":"2021-03-25T17:23:50.187208448Z","durationInNanos":35632640,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_checkout","traceGroupFields.endTime":"2021-03-25T17:23:50.452619520Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":313521664,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"bb5241efad532b9d"}}
+{"traceId":"cb65f65f84de2ead8c9b85304d654983","spanId":"bb5241efad532b9d","traceState":"","parentSpanId":"","name":"client_cancel_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:49.098619648Z","endTime":"2021-03-25T17:23:49.249286144Z","durationInNanos":150666496,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:49.249286144Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":150666496,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"7a9aabaff1af2284"}}
+{"traceId":"cb65f65f84de2ead8c9b85304d654983","spanId":"7a9aabaff1af2284","traceState":"","parentSpanId":"bb5241efad532b9d","name":"HTTP DELETE","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:49.098923264Z","endTime":"2021-03-25T17:23:49.242379520Z","durationInNanos":143456256,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:49.249286144Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":150666496,"span.attributes.http@url":"http://localhost:8088/clear_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"DELETE","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"7a20276ff8152236"}}
+{"traceId":"cb65f65f84de2ead8c9b85304d654983","spanId":"7a20276ff8152236","traceState":"","parentSpanId":"212b18ede97b3928","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:49.128396800Z","endTime":"2021-03-25T17:23:49.129145600Z","durationInNanos":748800,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:49.249286144Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":150666496,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"SELECT ItemId, TotalQty FROM User_Carts","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"f37a027ee2c9d0a5"}}
+{"traceId":"cb65f65f84de2ead8c9b85304d654983","spanId":"f37a027ee2c9d0a5","traceState":"","parentSpanId":"5a4ab4679e300a34","name":"clear_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:49.102409728Z","endTime":"2021-03-25T17:23:49.227282944Z","durationInNanos":124873216,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:49.249286144Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":150666496,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"403d9c331fda4328"}}
+{"traceId":"cb65f65f84de2ead8c9b85304d654983","spanId":"403d9c331fda4328","traceState":"","parentSpanId":"1e774d246aa3c5c4","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:49.218892812Z","endTime":"2021-03-25T17:23:49.220353279Z","durationInNanos":1460467,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:49.249286144Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":150666496,"span.attributes.thread@name":"http-nio-8087-exec-2","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":129,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"2be6a1c0faa8107a"}}
+{"traceId":"cb65f65f84de2ead8c9b85304d654983","spanId":"2be6a1c0faa8107a","traceState":"","parentSpanId":"212b18ede97b3928","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:49.138344448Z","endTime":"2021-03-25T17:23:49.139050496Z","durationInNanos":706048,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:49.249286144Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":150666496,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'apple', 'Qty': 1}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"INSERT INTO Inventory_Items (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"21437513f7184a58"}}
+{"traceId":"cb65f65f84de2ead8c9b85304d654983","spanId":"21437513f7184a58","traceState":"","parentSpanId":"212b18ede97b3928","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:49.152794368Z","endTime":"2021-03-25T17:23:49.154668800Z","durationInNanos":1874432,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:49.249286144Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":150666496,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'orange', 'Qty': 3}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"INSERT INTO Inventory_Items (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"012e590c33c1c603"}}
+{"traceId":"cb65f65f84de2ead8c9b85304d654983","spanId":"012e590c33c1c603","traceState":"","parentSpanId":"212b18ede97b3928","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:49.162752Z","endTime":"2021-03-25T17:23:49.184285184Z","durationInNanos":21533184,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:49.249286144Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":150666496,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"TRUNCATE TABLE User_Carts","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"120b3c8a3f7590ce"}}
+{"traceId":"cb65f65f84de2ead8c9b85304d654983","spanId":"120b3c8a3f7590ce","traceState":"","parentSpanId":"f37a027ee2c9d0a5","name":"HTTP PUT","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:49.102667776Z","endTime":"2021-03-25T17:23:49.209395200Z","durationInNanos":106727424,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:49.249286144Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":150666496,"span.attributes.http@url":"http://localhost:8083/cart_empty","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"PUT","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"212b18ede97b3928"}}
+{"traceId":"cb65f65f84de2ead8c9b85304d654983","spanId":"212b18ede97b3928","traceState":"","parentSpanId":"378d0aa862c77ae8","name":"cart_empty","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:49.106436352Z","endTime":"2021-03-25T17:23:49.192958976Z","durationInNanos":86522624,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:49.249286144Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":150666496,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"2c1783219ee685be"}}
+{"traceId":"cb65f65f84de2ead8c9b85304d654983","spanId":"2c1783219ee685be","traceState":"","parentSpanId":"212b18ede97b3928","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:49.144996096Z","endTime":"2021-03-25T17:23:49.146592768Z","durationInNanos":1596672,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:49.249286144Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":150666496,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.db@statement@parameters":"{'ItemId': 'banana', 'Qty': 2}","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"INSERT INTO Inventory_Items (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"378d0aa862c77ae8"}}
+{"traceId":"cb65f65f84de2ead8c9b85304d654983","spanId":"378d0aa862c77ae8","traceState":"","parentSpanId":"120b3c8a3f7590ce","name":"cartEmpty","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:49.105362944Z","endTime":"2021-03-25T17:23:49.199950592Z","durationInNanos":94587648,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:49.249286144Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":150666496,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"PUT","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55942,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/cart_empty","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/cart_empty","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"6ffca6d4aff16069"}}
+{"traceId":"cb65f65f84de2ead8c9b85304d654983","spanId":"6ffca6d4aff16069","traceState":"","parentSpanId":"f37a027ee2c9d0a5","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:49.215243008Z","endTime":"2021-03-25T17:23:49.221854208Z","durationInNanos":6611200,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:49.249286144Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":150666496,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"1e774d246aa3c5c4"}}
+{"traceId":"cb65f65f84de2ead8c9b85304d654983","spanId":"1e774d246aa3c5c4","traceState":"","parentSpanId":"6ffca6d4aff16069","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:49.218005395Z","endTime":"2021-03-25T17:23:49.220497993Z","durationInNanos":2492598,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:49.249286144Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":150666496,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-2","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":129,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56664,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"5a4ab4679e300a34"}}
+{"traceId":"cb65f65f84de2ead8c9b85304d654983","spanId":"5a4ab4679e300a34","traceState":"","parentSpanId":"7a9aabaff1af2284","name":"clear_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:49.101421568Z","endTime":"2021-03-25T17:23:49.232189440Z","durationInNanos":130767872,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_cancel_order","traceGroupFields.endTime":"2021-03-25T17:23:49.249286144Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":150666496,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"DELETE","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56926,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/clear_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/clear_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"542385797ac7122c"}}
+{"traceId":"690d3c7af1a78cf89c43ef4b07c05b43","spanId":"542385797ac7122c","traceState":"","parentSpanId":"","name":"client_pay_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:59.321163264Z","endTime":"2021-03-25T17:23:59.497588224Z","durationInNanos":176424960,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:59.497588224Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":176424960,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"f9d9427c810291d8"}}
+{"traceId":"690d3c7af1a78cf89c43ef4b07c05b43","spanId":"f9d9427c810291d8","traceState":"","parentSpanId":"7df5609a6d104736","name":"pay_order","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:59.323977728Z","endTime":"2021-03-25T17:23:59.480053760Z","durationInNanos":156076032,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:59.497588224Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":176424960,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56954,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/pay_order","span.attributes.http@host":"localhost:8088","span.attributes.http@target":"/pay_order","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"c8fff65b158a58b0"}}
+{"traceId":"690d3c7af1a78cf89c43ef4b07c05b43","spanId":"c8fff65b158a58b0","traceState":"","parentSpanId":"303b76b989099bb5","name":"cartSold","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:59.327906816Z","endTime":"2021-03-25T17:23:59.409421568Z","durationInNanos":81514752,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:59.497588224Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":176424960,"span.attributes.net@peer@ip":"127.0.0.1","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8083,"span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"DELETE","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":55970,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@route":"/cart_sold","span.attributes.http@host":"localhost:8083","span.attributes.http@target":"/cart_sold","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":200}
+{"index":{"_id":"303b76b989099bb5"}}
+{"traceId":"690d3c7af1a78cf89c43ef4b07c05b43","spanId":"303b76b989099bb5","traceState":"","parentSpanId":"e2ab54f8e8a03c99","name":"HTTP DELETE","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:59.325160960Z","endTime":"2021-03-25T17:23:59.430193920Z","durationInNanos":105032960,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:59.497588224Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":176424960,"span.attributes.http@url":"http://localhost:8083/cart_sold","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"DELETE","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
diff --git a/.cypress/utils/otel-v1-apm-span-000002.json b/.cypress/utils/otel-v1-apm-span-000002.json
new file mode 100644
index 0000000000..9166e0e682
--- /dev/null
+++ b/.cypress/utils/otel-v1-apm-span-000002.json
@@ -0,0 +1,968 @@
+{"index":{"_id":"ba677184b5efee9c"}}
+{"traceId":"690d3c7af1a78cf89c43ef4b07c05b43","spanId":"ba677184b5efee9c","traceState":"","parentSpanId":"05d70136fe1f5159","name":"/logs","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:23:59.461002874Z","endTime":"2021-03-25T17:23:59.463725749Z","durationInNanos":2722875,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:59.497588224Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":176424960,"span.attributes.net@peer@ip":"127.0.0.1","span.attributes.http@url":"http://localhost:8087/logs","span.attributes.thread@name":"http-nio-8087-exec-8","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":135,"resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.servlet","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.25.1","span.attributes.net@peer@port":56692,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@auto@version":"0.10.1","span.attributes.http@flavor":"HTTP/1.1","span.attributes.http@status_code":200,"span.attributes.http@client_ip":"127.0.0.1"}
+{"index":{"_id":"3ed514d3a35fcf2f"}}
+{"traceId":"690d3c7af1a78cf89c43ef4b07c05b43","spanId":"3ed514d3a35fcf2f","traceState":"","parentSpanId":"c8fff65b158a58b0","name":"cart_sold","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:59.328946176Z","endTime":"2021-03-25T17:23:59.396863488Z","durationInNanos":67917312,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:59.497588224Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":176424960,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"a1464485edf9588e"}}
+{"traceId":"690d3c7af1a78cf89c43ef4b07c05b43","spanId":"a1464485edf9588e","traceState":"","parentSpanId":"3ed514d3a35fcf2f","name":"mysql.APM","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:59.351120384Z","endTime":"2021-03-25T17:23:59.381280256Z","durationInNanos":30159872,"serviceName":"database","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:59.497588224Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":176424960,"span.attributes.db@user":"root","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.net@peer@name":"localhost","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140307275923408","resource.attributes.service@name":"database","span.attributes.component":"mysql","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.mysql","span.attributes.db@type":"sql","span.attributes.net@peer@port":3306,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.db@instance":"APM","span.attributes.db@statement":"TRUNCATE TABLE User_Carts","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal"}
+{"index":{"_id":"05d70136fe1f5159"}}
+{"traceId":"690d3c7af1a78cf89c43ef4b07c05b43","spanId":"05d70136fe1f5159","traceState":"","parentSpanId":"e2ab54f8e8a03c99","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:59.447067904Z","endTime":"2021-03-25T17:23:59.466000896Z","durationInNanos":18932992,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:59.497588224Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":176424960,"span.attributes.http@url":"http://localhost:8087/logs","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"e2ab54f8e8a03c99"}}
+{"traceId":"690d3c7af1a78cf89c43ef4b07c05b43","spanId":"e2ab54f8e8a03c99","traceState":"","parentSpanId":"f9d9427c810291d8","name":"pay_order","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:59.324906496Z","endTime":"2021-03-25T17:23:59.473705472Z","durationInNanos":148798976,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:59.497588224Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":176424960,"resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.telemetry@sdk@language":"python","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","status.code":0,"instrumentationLibrary.name":"__main__"}
+{"index":{"_id":"7df5609a6d104736"}}
+{"traceId":"690d3c7af1a78cf89c43ef4b07c05b43","spanId":"7df5609a6d104736","traceState":"","parentSpanId":"542385797ac7122c","name":"HTTP POST","kind":"SPAN_KIND_CLIENT","startTime":"2021-03-25T17:23:59.321473280Z","endTime":"2021-03-25T17:23:59.490911488Z","durationInNanos":169438208,"serviceName":"frontend-client","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:59.497588224Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":176424960,"span.attributes.http@url":"http://localhost:8088/pay_order","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.http@status_text":"OK","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@name":"frontend-client","span.attributes.component":"http","status.code":0,"instrumentationLibrary.name":"opentelemetry.instrumentation.requests","span.attributes.http@method":"POST","resource.attributes.telemetry@sdk@name":"opentelemetry","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@status_code":200}
+{"index":{"_id":"05ef9498724dc42f"}}
+{"traceId":"690d3c7af1a78cf89c43ef4b07c05b43","spanId":"05ef9498724dc42f","traceState":"","parentSpanId":"ba677184b5efee9c","name":"LoggingController.save","kind":"SPAN_KIND_INTERNAL","startTime":"2021-03-25T17:23:59.461838595Z","endTime":"2021-03-25T17:23:59.463482824Z","durationInNanos":1644229,"serviceName":"analytics-service","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"client_pay_order","traceGroupFields.endTime":"2021-03-25T17:23:59.497588224Z","traceGroupFields.statusCode":0,"traceGroupFields.durationInNanos":176424960,"span.attributes.thread@name":"http-nio-8087-exec-8","resource.attributes.telemetry@sdk@name":"opentelemetry","instrumentationLibrary.version":"0.10.1","resource.attributes.telemetry@sdk@language":"java","span.attributes.thread@id":135,"resource.attributes.telemetry@auto@version":"0.10.1","resource.attributes.telemetry@sdk@version":"0.10.0","resource.attributes.service@name":"analytics-service","status.code":0,"instrumentationLibrary.name":"io.opentelemetry.auto.spring-webmvc"}
+{"index":{"_id":"eea507e2c1767a48"}}
+{"traceId":"24112fdc5dfb6886638e64458220b1c8","spanId":"eea507e2c1767a48","traceState":"","parentSpanId":"","name":"HTTP POST","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:42:17.381757696Z","endTime":"2021-03-25T17:42:17.383773440Z","durationInNanos":2015744,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"HTTP POST","traceGroupFields.endTime":"2021-03-25T17:42:17.383773440Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":2015744,"span.attributes.net@peer@ip":"165.232.135.114","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"NOT FOUND","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":2,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.6.0 CPython/2.7.5 Linux/3.10.0-1160.15.2.el7.x86_64","span.attributes.net@peer@port":37610,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@host":"54.202.237.120:8088","span.attributes.http@target":"/ws/v1/cluster/apps/new-application","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":404}
+{"index":{"_id":"a32571a7f379563e"}}
+{"traceId":"f9389809a15b165300bf99ca10c1d094","spanId":"a32571a7f379563e","traceState":"","parentSpanId":"","name":"HTTP GET","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:42:42.526520320Z","endTime":"2021-03-25T17:42:42.527678720Z","durationInNanos":1158400,"serviceName":"recommendation","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"HTTP GET","traceGroupFields.endTime":"2021-03-25T17:42:42.527678720Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":1158400,"span.attributes.net@peer@ip":"139.162.75.102","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8086,"span.attributes.http@status_text":"NOT FOUND","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"140465266593744","resource.attributes.service@name":"recommendation","span.attributes.component":"http","status.code":2,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"GET","span.attributes.http@user_agent":"HTTP Banner Detection (https://security.ipip.net)","span.attributes.net@peer@port":43096,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@host":"54.202.237.120:8086","span.attributes.http@target":"/","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":404}
+{"index":{"_id":"fc11194d7d60a403"}}
+{"traceId":"5c8f22e7dce504a5b7610590d5426b16","spanId":"fc11194d7d60a403","traceState":"","parentSpanId":"","name":"HTTP POST","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:25:41.732983296Z","endTime":"2021-03-25T17:25:41.734188544Z","durationInNanos":1205248,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"HTTP POST","traceGroupFields.endTime":"2021-03-25T17:25:41.734188544Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":1205248,"span.attributes.net@peer@ip":"128.199.87.139","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"NOT FOUND","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":2,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.12.4","span.attributes.net@peer@port":59096,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@host":"54.202.237.120:8088","span.attributes.http@target":"/ws/v1/cluster/apps/new-application","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":404}
+{"index":{"_id":"8f0e5fd10849cc70"}}
+{"traceId":"f151842ced0cd956ec005da199424336","spanId":"8f0e5fd10849cc70","traceState":"","parentSpanId":"","name":"HTTP POST","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:48:05.517435904Z","endTime":"2021-03-25T17:48:05.518697728Z","durationInNanos":1261824,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"HTTP POST","traceGroupFields.endTime":"2021-03-25T17:48:05.518697728Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":1261824,"span.attributes.net@peer@ip":"165.232.135.114","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"NOT FOUND","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":2,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.6.0 CPython/2.7.5 Linux/3.10.0-1160.15.2.el7.x86_64","span.attributes.net@peer@port":59430,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@host":"54.202.237.120:8088","span.attributes.http@target":"/ws/v1/cluster/apps/new-application","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":404}
+{"index":{"_id":"244bc4ca978dd618"}}
+{"traceId":"be0a3dceda2ecf601fd2e476fef3ee07","spanId":"244bc4ca978dd618","traceState":"","parentSpanId":"","name":"HTTP POST","kind":"SPAN_KIND_SERVER","startTime":"2021-03-25T17:55:12.854892800Z","endTime":"2021-03-25T17:55:12.856072192Z","durationInNanos":1179392,"serviceName":"order","events":[],"links":[],"droppedAttributesCount":0,"droppedEventsCount":0,"droppedLinksCount":0,"traceGroup":"HTTP POST","traceGroupFields.endTime":"2021-03-25T17:55:12.856072192Z","traceGroupFields.statusCode":2,"traceGroupFields.durationInNanos":1179392,"span.attributes.net@peer@ip":"165.232.135.114","instrumentationLibrary.version":"0.14b0","resource.attributes.telemetry@sdk@language":"python","span.attributes.host@port":8088,"span.attributes.http@status_text":"NOT FOUND","resource.attributes.telemetry@sdk@version":"0.14b0","resource.attributes.service@instance@id":"139858677314952","resource.attributes.service@name":"order","span.attributes.component":"http","status.code":2,"instrumentationLibrary.name":"opentelemetry.instrumentation.flask","span.attributes.http@method":"POST","span.attributes.http@user_agent":"python-requests/2.6.0 CPython/2.7.5 Linux/3.10.0-1160.15.2.el7.x86_64","span.attributes.net@peer@port":35686,"resource.attributes.telemetry@sdk@name":"opentelemetry","span.attributes.http@server_name":"0.0.0.0","span.attributes.http@host":"54.202.237.120:8088","span.attributes.http@target":"/ws/v1/cluster/apps/new-application","span.attributes.http@scheme":"http","resource.attributes.host@hostname":"ip-172-31-10-8.us-west-2.compute.internal","span.attributes.http@flavor":"1.1","span.attributes.http@status_code":404}
+{ "index":{"_id": "fe945197d943bda9"}}
+{ "traceId": "552aa3363bf275a248b131406edf735d", "spanId": "fe945197d943bda9", "traceState": "", "parentSpanId": "2bdbeb0df10ab869", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:42.022309888Z", "endTime": "2021-04-20T20:33:42.047018752Z", "durationInNanos": 24708864, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "TRUNCATE TABLE User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "2bdbeb0df10ab869"}}
+{ "traceId": "552aa3363bf275a248b131406edf735d", "spanId": "2bdbeb0df10ab869", "traceState": "", "parentSpanId": "7a5994c2d61252d8", "name": "cart_sold", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:42.002375424Z", "endTime": "2021-04-20T20:33:42.050758400Z", "durationInNanos": 48382976, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "bae5c2ac73588d38"}}
+{ "traceId": "552aa3363bf275a248b131406edf735d", "spanId": "bae5c2ac73588d38", "traceState": "", "parentSpanId": "d6668b8cd17b28aa", "name": "pay_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:41.999037184Z", "endTime": "2021-04-20T20:33:42.070543360Z", "durationInNanos": 71506176, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "d6668b8cd17b28aa"}}
+{ "traceId": "552aa3363bf275a248b131406edf735d", "spanId": "d6668b8cd17b28aa", "traceState": "", "parentSpanId": "2786ea5cfba1d51c", "name": "pay_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:41.998258944Z", "endTime": "2021-04-20T20:33:42.073518592Z", "durationInNanos": 75259648, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 60962, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/pay_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/pay_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "de34ef4183a4705b"}}
+{ "traceId": "52190817d7eb1b6d71e66cc9b0b14124", "spanId": "de34ef4183a4705b", "traceState": "", "parentSpanId": "1e0ea651a120db7b", "name": "update_item", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:42.502849536Z", "endTime": "2021-04-20T20:33:42.529717248Z", "durationInNanos": 26867712, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "cdf9197db50c18a4"}}
+{ "traceId": "52190817d7eb1b6d71e66cc9b0b14124", "spanId": "cdf9197db50c18a4", "traceState": "", "parentSpanId": "baa1e8371ec989bd", "name": "updateItem", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:42.543471872Z", "endTime": "2021-04-20T20:33:42.573529344Z", "durationInNanos": 30057472, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58602, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_item", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/update_item", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "baa1e8371ec989bd"}}
+{ "traceId": "52190817d7eb1b6d71e66cc9b0b14124", "spanId": "baa1e8371ec989bd", "traceState": "", "parentSpanId": "0791aa225a461844", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:42.541210624Z", "endTime": "2021-04-20T20:33:42.578594816Z", "durationInNanos": 37384192, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/update_item", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "a545017537d582f9"}}
+{ "traceId": "52190817d7eb1b6d71e66cc9b0b14124", "spanId": "a545017537d582f9", "traceState": "", "parentSpanId": "48ab22a6aa9ead3d", "name": "updateItem", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:42.583665664Z", "endTime": "2021-04-20T20:33:42.615355392Z", "durationInNanos": 31689728, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58606, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_item", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/update_item", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "868f60191f3524c9"}}
+{ "traceId": "52190817d7eb1b6d71e66cc9b0b14124", "spanId": "868f60191f3524c9", "traceState": "", "parentSpanId": "007459ff1ddd5dfb", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:42.496294144Z", "endTime": "2021-04-20T20:33:42.638115584Z", "durationInNanos": 141821440, "serviceName": "payment", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8082/update_inventory", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "139782029922256", "resource.attributes.service@name": "payment", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "5e7bc4f9aae01a8f"}}
+{ "traceId": "c5eabf09201ab4df116e1881d0756035", "spanId": "5e7bc4f9aae01a8f", "traceState": "", "parentSpanId": "", "name": "client_cancel_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:43.385450240Z", "endTime": "2021-04-20T20:33:43.469037824Z", "durationInNanos": 83587584, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_cancel_order", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "5d8912365e6688f3"}}
+{ "traceId": "1ca5c1d52ca730f16872553cde6933c0", "spanId": "5d8912365e6688f3", "traceState": "", "parentSpanId": "e272f67b8738c361", "name": "cart_empty", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:43.826181376Z", "endTime": "2021-04-20T20:33:43.875000320Z", "durationInNanos": 48818944, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "7e35eb6c56afcde0"}}
+{ "traceId": "1ca5c1d52ca730f16872553cde6933c0", "spanId": "7e35eb6c56afcde0", "traceState": "", "parentSpanId": "5b366e385260a8f1", "name": "clear_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:43.822093312Z", "endTime": "2021-04-20T20:33:43.896168448Z", "durationInNanos": 74075136, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "DELETE", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 32772, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/clear_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/clear_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "5b366e385260a8f1"}}
+{ "traceId": "1ca5c1d52ca730f16872553cde6933c0", "spanId": "5b366e385260a8f1", "traceState": "", "parentSpanId": "c785f8a4fa3c337f", "name": "HTTP DELETE", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:43.819960576Z", "endTime": "2021-04-20T20:33:43.900840704Z", "durationInNanos": 80880128, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8088/clear_order", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "DELETE", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "c785f8a4fa3c337f"}}
+{ "traceId": "1ca5c1d52ca730f16872553cde6933c0", "spanId": "c785f8a4fa3c337f", "traceState": "", "parentSpanId": "", "name": "client_cancel_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:43.819711488Z", "endTime": "2021-04-20T20:33:43.903628288Z", "durationInNanos": 83916800, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_cancel_order", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "959d996c94b64416"}}
+{ "traceId": "b23c2f42f054fd2e3bd6602318e609ed", "spanId": "959d996c94b64416", "traceState": "", "parentSpanId": "4ed24722154a0621", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:39.000507533Z", "endTime": "2021-04-20T20:33:39.001814067Z", "durationInNanos": 1306534, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-4", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 134, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "b04dd1440b46ea4a"}}
+{ "traceId": "56280de557e9fa891bb6289d2fd53c8d", "spanId": "b04dd1440b46ea4a", "traceState": "", "parentSpanId": "1fbcd1691508fa92", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:40.859492193Z", "endTime": "2021-04-20T20:33:40.860705473Z", "durationInNanos": 1213280, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-3", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 133, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "4ed24722154a0621"}}
+{ "traceId": "b23c2f42f054fd2e3bd6602318e609ed", "spanId": "4ed24722154a0621", "traceState": "", "parentSpanId": "62acd7c17a0ba6b5", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:39.000001917Z", "endTime": "2021-04-20T20:33:39.001944606Z", "durationInNanos": 1942689, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-4", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 134, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57758, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "6dcf6a50115bf9bf"}}
+{ "traceId": "10b1ec1196741c85609a43ce435cdece", "spanId": "6dcf6a50115bf9bf", "traceState": "", "parentSpanId": "7052b8e18f95d355", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:40.293001852Z", "endTime": "2021-04-20T20:33:40.294769849Z", "durationInNanos": 1767997, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-10", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 140, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57788, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "a981fd033e3a7491"}}
+{ "traceId": "259a8226fae090c7dff75784fc8c7b17", "spanId": "a981fd033e3a7491", "traceState": "", "parentSpanId": "3d3423c981805776", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:41.248002296Z", "endTime": "2021-04-20T20:33:41.250091967Z", "durationInNanos": 2089671, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-4", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 134, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57808, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "c2bf96e64de1f749"}}
+{ "traceId": "552aa3363bf275a248b131406edf735d", "spanId": "c2bf96e64de1f749", "traceState": "", "parentSpanId": "82f2995c402620bf", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:42.064002408Z", "endTime": "2021-04-20T20:33:42.066510378Z", "durationInNanos": 2507970, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-8", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 138, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57830, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "7d14b353b41504e2"}}
+{ "traceId": "1ca5c1d52ca730f16872553cde6933c0", "spanId": "7d14b353b41504e2", "traceState": "", "parentSpanId": "66305d54c87ada37", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:43.888001836Z", "endTime": "2021-04-20T20:33:43.889846781Z", "durationInNanos": 1844945, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-6", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 136, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57872, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "638057deacc19370"}}
+{ "traceId": "96db5f125cb54111f2a95d7419df8a15", "spanId": "638057deacc19370", "traceState": "", "parentSpanId": "570073e77e68be9d", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:44.210460160Z", "endTime": "2021-04-20T20:33:44.211786496Z", "durationInNanos": 1326336, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'apple', 'Qty': '1'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "INSERT INTO User_Carts (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "72fd9aa427e26550"}}
+{ "traceId": "96db5f125cb54111f2a95d7419df8a15", "spanId": "72fd9aa427e26550", "traceState": "", "parentSpanId": "63b924688fd8e338", "name": "addItemToCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:44.184596992Z", "endTime": "2021-04-20T20:33:44.221891840Z", "durationInNanos": 37294848, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58638, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/add_item_to_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/add_item_to_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "74a72003d10b4891"}}
+{ "traceId": "96db5f125cb54111f2a95d7419df8a15", "spanId": "74a72003d10b4891", "traceState": "", "parentSpanId": "9d74d751ce8f5632", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:44.298237184Z", "endTime": "2021-04-20T20:33:44.299052800Z", "durationInNanos": 815616, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'banana', 'Qty': '2'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "9d74d751ce8f5632"}}
+{ "traceId": "96db5f125cb54111f2a95d7419df8a15", "spanId": "9d74d751ce8f5632", "traceState": "", "parentSpanId": "2311bcf70d68331c", "name": "add_item_to_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:44.278095616Z", "endTime": "2021-04-20T20:33:44.309211392Z", "durationInNanos": 31115776, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "d45da7dee8c886ed"}}
+{ "traceId": "c0ef65e0d991727dbe26a071fd10e407", "spanId": "d45da7dee8c886ed", "traceState": "", "parentSpanId": "8fb23e8fa1ec36c4", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:44.578994944Z", "endTime": "2021-04-20T20:33:44.579650560Z", "durationInNanos": 655616, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "SELECT * FROM User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "10c91a64a809f0f9"}}
+{ "traceId": "c0ef65e0d991727dbe26a071fd10e407", "spanId": "10c91a64a809f0f9", "traceState": "", "parentSpanId": "", "name": "client_delivery_status", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:44.552633344Z", "endTime": "2021-04-20T20:33:44.611744256Z", "durationInNanos": 59110912, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_delivery_status", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "7359981596903c3f"}}
+{ "traceId": "70a3f615a998b76cd973d87710572913", "spanId": "7359981596903c3f", "traceState": "", "parentSpanId": "61aa3d8d2d402633", "name": "cart_sold", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:44.946950400Z", "endTime": "2021-04-20T20:33:44.993092352Z", "durationInNanos": 46141952, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "61aa3d8d2d402633"}}
+{ "traceId": "70a3f615a998b76cd973d87710572913", "spanId": "61aa3d8d2d402633", "traceState": "", "parentSpanId": "0fcb489ad5418516", "name": "cartSold", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:44.946038528Z", "endTime": "2021-04-20T20:33:44.996396288Z", "durationInNanos": 50357760, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "DELETE", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58668, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/cart_sold", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/cart_sold", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "6f35a199b046be10"}}
+{ "traceId": "65e793c50b861f00c1534090639dd7c3", "spanId": "6f35a199b046be10", "traceState": "", "parentSpanId": "83e66a83f1a293d1", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:45.283089152Z", "endTime": "2021-04-20T20:33:45.284170496Z", "durationInNanos": 1081344, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "SELECT * FROM User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "5205b0912292faea"}}
+{ "traceId": "65e793c50b861f00c1534090639dd7c3", "spanId": "5205b0912292faea", "traceState": "", "parentSpanId": "61e11870abc59f27", "name": "getCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:45.262661120Z", "endTime": "2021-04-20T20:33:45.291168768Z", "durationInNanos": 28507648, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "GET", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58678, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/get_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/get_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "3cf94093fb7bea7c"}}
+{ "traceId": "65e793c50b861f00c1534090639dd7c3", "spanId": "3cf94093fb7bea7c", "traceState": "", "parentSpanId": "075721f8c8fe8187", "name": "get_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:45.260254208Z", "endTime": "2021-04-20T20:33:45.306146816Z", "durationInNanos": 45892608, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "075721f8c8fe8187"}}
+{ "traceId": "65e793c50b861f00c1534090639dd7c3", "spanId": "075721f8c8fe8187", "traceState": "", "parentSpanId": "6164378b120c9a33", "name": "get_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:45.259456Z", "endTime": "2021-04-20T20:33:45.308376320Z", "durationInNanos": 48920320, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "GET", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 32822, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/get_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/get_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "fe4076542b41d40b"}}
+{ "traceId": "02feb3a4f611abd81f2a53244d1278ae", "spanId": "fe4076542b41d40b", "traceState": "", "parentSpanId": "68d63100ba9ee351", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:45.613371648Z", "endTime": "2021-04-20T20:33:45.614105088Z", "durationInNanos": 733440, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'apple', 'Qty': '1'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "INSERT INTO User_Carts (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "4cc7f89e7a456e50"}}
+{ "traceId": "02feb3a4f611abd81f2a53244d1278ae", "spanId": "4cc7f89e7a456e50", "traceState": "", "parentSpanId": "8cf5c6a43ee7642e", "name": "addItemToCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:45.672583936Z", "endTime": "2021-04-20T20:33:45.701916160Z", "durationInNanos": 29332224, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58696, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/add_item_to_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/add_item_to_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "ded3687b9758bf59"}}
+{ "traceId": "02feb3a4f611abd81f2a53244d1278ae", "spanId": "ded3687b9758bf59", "traceState": "", "parentSpanId": "8ca1e3b61d66dac5", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:45.582414080Z", "endTime": "2021-04-20T20:33:45.724472064Z", "durationInNanos": 142057984, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8088/update_order", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "9a880188bcb44cda"}}
+{ "traceId": "b450e7770b6bf942d91f238f77311fbe", "spanId": "9a880188bcb44cda", "traceState": "", "parentSpanId": "22b1d496a103d5d4", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:46.193865472Z", "endTime": "2021-04-20T20:33:46.233754624Z", "durationInNanos": 39889152, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/update_item", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "Not enough storage for itemId orange", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "span.attributes.component": "http", "status.code": 2, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 422 }
+{ "index":{"_id": "211e3fa733083be7"}}
+{ "traceId": "b450e7770b6bf942d91f238f77311fbe", "spanId": "211e3fa733083be7", "traceState": "", "parentSpanId": "6f7eafee7d68115c", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:46.259891200Z", "endTime": "2021-04-20T20:33:46.260595456Z", "durationInNanos": 704256, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'apple', 'Qty': 1}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "203faf4d95696dc4"}}
+{ "traceId": "b450e7770b6bf942d91f238f77311fbe", "spanId": "203faf4d95696dc4", "traceState": "", "parentSpanId": "01e2845682343300", "name": "updateItem", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:46.239240960Z", "endTime": "2021-04-20T20:33:46.270526720Z", "durationInNanos": 31285760, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58726, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_item", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/update_item", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "30652f6f8b511470"}}
+{ "traceId": "b450e7770b6bf942d91f238f77311fbe", "spanId": "30652f6f8b511470", "traceState": "", "parentSpanId": "6abbf17273b9d804", "name": "update_inventory", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:46.151000320Z", "endTime": "2021-04-20T20:33:46.280569856Z", "durationInNanos": 129569536, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8082, "span.attributes.http@status_text": "Update inventory response contains failed items.", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 48470, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_inventory", "span.attributes.http@host": "localhost:8082", "span.attributes.http@target": "/update_inventory", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 206 }
+{ "index":{"_id": "6abbf17273b9d804"}}
+{ "traceId": "b450e7770b6bf942d91f238f77311fbe", "spanId": "6abbf17273b9d804", "traceState": "", "parentSpanId": "cadc045e30deb39c", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:46.148769024Z", "endTime": "2021-04-20T20:33:46.285116928Z", "durationInNanos": 136347904, "serviceName": "payment", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8082/update_inventory", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "Update inventory response contains failed items.", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "139782029922256", "resource.attributes.service@name": "payment", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 206 }
+{ "index":{"_id": "86582d579095a4b2"}}
+{ "traceId": "b450e7770b6bf942d91f238f77311fbe", "spanId": "86582d579095a4b2", "traceState": "", "parentSpanId": "", "name": "client_checkout", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:46.145158144Z", "endTime": "2021-04-20T20:33:46.297544448Z", "durationInNanos": 152386304, "serviceName": "frontend-client", "events": [ { "time": "2021-04-20T20:33:46.297516032Z", "name": "exception", "attributes": { "exception@message": "", "exception@type": "AssertionError", "exception@stacktrace": """Traceback (most recent call last): File "/usr/lib/python3.6/site-packages/opentelemetry/sdk/trace/__init__.py", line 804, in use_span yield span File "/app/client.py", line 179, in checkout assert checkoutAPIRequest.status_code == 200 AssertionError """ }, "droppedAttributesCount": 0 } ], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_checkout", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "status.message": "AssertionError: ", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 2, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "733fc257ce126bd9"}}
+{ "traceId": "ba5a69d5dfd1eaa4077451d452ba473b", "spanId": "733fc257ce126bd9", "traceState": "", "parentSpanId": "e270a32c23bb3d64", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:46.530245888Z", "endTime": "2021-04-20T20:33:46.552403200Z", "durationInNanos": 22157312, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "TRUNCATE TABLE User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "d3e652fe39797f07"}}
+{ "traceId": "ba5a69d5dfd1eaa4077451d452ba473b", "spanId": "d3e652fe39797f07", "traceState": "", "parentSpanId": "e35c1a3d860c70aa", "name": "HTTP PUT", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:46.501878016Z", "endTime": "2021-04-20T20:33:46.563703296Z", "durationInNanos": 61825280, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/cart_empty", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "PUT", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "93a311e112248f38"}}
+{ "traceId": "ba5a69d5dfd1eaa4077451d452ba473b", "spanId": "93a311e112248f38", "traceState": "", "parentSpanId": "7d9e1df2e1915cb1", "name": "HTTP DELETE", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:46.498651904Z", "endTime": "2021-04-20T20:33:46.581459456Z", "durationInNanos": 82807552, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8088/clear_order", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "DELETE", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "13738600ae869fe9"}}
+{ "traceId": "95b27b5462c0dccc7e08126a25e64d3f", "spanId": "13738600ae869fe9", "traceState": "", "parentSpanId": "7c37927033d44c5c", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:46.905734912Z", "endTime": "2021-04-20T20:33:46.906381056Z", "durationInNanos": 646144, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'banana', 'Qty': '2'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "7c37927033d44c5c"}}
+{ "traceId": "95b27b5462c0dccc7e08126a25e64d3f", "spanId": "7c37927033d44c5c", "traceState": "", "parentSpanId": "704ecef0adc44ed2", "name": "add_item_to_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:46.885713920Z", "endTime": "2021-04-20T20:33:46.910141696Z", "durationInNanos": 24427776, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "4bac6e5bfd5892b4"}}
+{ "traceId": "95b27b5462c0dccc7e08126a25e64d3f", "spanId": "4bac6e5bfd5892b4", "traceState": "", "parentSpanId": "51c0b6f4525f8ce7", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:46.921752064Z", "endTime": "2021-04-20T20:33:46.926354688Z", "durationInNanos": 4602624, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "ceb7f50ca3f6e4d8"}}
+{ "traceId": "c0d5be4cfded4677b472caeb6dced6eb", "spanId": "ceb7f50ca3f6e4d8", "traceState": "", "parentSpanId": "5f0f95a6e744be7f", "name": "updateItem", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:47.191190528Z", "endTime": "2021-04-20T20:33:47.221020672Z", "durationInNanos": 29830144, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "Not enough storage for itemId banana", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 2, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58764, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_item", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/update_item", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 422 }
+{ "index":{"_id": "5f0f95a6e744be7f"}}
+{ "traceId": "c0d5be4cfded4677b472caeb6dced6eb", "spanId": "5f0f95a6e744be7f", "traceState": "", "parentSpanId": "3e1ca23a1316a089", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:47.188976640Z", "endTime": "2021-04-20T20:33:47.225834496Z", "durationInNanos": 36857856, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/update_item", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "Not enough storage for itemId banana", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "span.attributes.component": "http", "status.code": 2, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 422 }
+{ "index":{"_id": "c321930cea7a01b8"}}
+{ "traceId": "c0d5be4cfded4677b472caeb6dced6eb", "spanId": "c321930cea7a01b8", "traceState": "", "parentSpanId": "45b57a8187c98ac7", "name": "update_item", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:47.285538560Z", "endTime": "2021-04-20T20:33:47.310507008Z", "durationInNanos": 24968448, "serviceName": "database", "events": [ { "time": "2021-04-20T20:33:47.310474496Z", "name": "exception", "attributes": { "exception@message": "", "exception@type": "InvalidItemUpdate", "exception@stacktrace": """Traceback (most recent call last): File "/usr/lib/python3.6/site-packages/opentelemetry/sdk/trace/__init__.py", line 804, in use_span yield span File "databaseService.py", line 162, in updateItem raise InvalidItemUpdate("Not enough storage for itemId {}".format(data[ "ItemId" ])) InvalidItemUpdate """ }, "droppedAttributesCount": 0 } ], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "status.message": "InvalidItemUpdate: ", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 2, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "f707df9bafaf7974"}}
+{ "traceId": "c0d5be4cfded4677b472caeb6dced6eb", "spanId": "f707df9bafaf7974", "traceState": "", "parentSpanId": "1d9787eae41fc84d", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:47.182018048Z", "endTime": "2021-04-20T20:33:47.339902976Z", "durationInNanos": 157884928, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8084/checkout", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "PARTIAL CONTENT", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 206 }
+{ "index":{"_id": "1d9787eae41fc84d"}}
+{ "traceId": "c0d5be4cfded4677b472caeb6dced6eb", "spanId": "1d9787eae41fc84d", "traceState": "", "parentSpanId": "", "name": "client_checkout", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:47.181764352Z", "endTime": "2021-04-20T20:33:47.342982400Z", "durationInNanos": 161218048, "serviceName": "frontend-client", "events": [ { "time": "2021-04-20T20:33:47.342953472Z", "name": "exception", "attributes": { "exception@message": "", "exception@type": "AssertionError", "exception@stacktrace": """Traceback (most recent call last): File "/usr/lib/python3.6/site-packages/opentelemetry/sdk/trace/__init__.py", line 804, in use_span yield span File "/app/client.py", line 179, in checkout assert checkoutAPIRequest.status_code == 200 AssertionError """ }, "droppedAttributesCount": 0 } ], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_checkout", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "status.message": "AssertionError: ", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 2, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "ad97f94c920dd63a"}}
+{ "traceId": "e48a85b3dc34426059aa1347ea4171a5", "spanId": "ad97f94c920dd63a", "traceState": "", "parentSpanId": "5b03c5aa49169de7", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:47.481642240Z", "endTime": "2021-04-20T20:33:47.486791168Z", "durationInNanos": 5148928, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "526236d61de39741"}}
+{ "traceId": "16f5176887289baa94c27f12604b5163", "spanId": "526236d61de39741", "traceState": "", "parentSpanId": "556b9dbb760a1f55", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:47.798135808Z", "endTime": "2021-04-20T20:33:47.798772480Z", "durationInNanos": 636672, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'apple', 'Qty': '1'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "556b9dbb760a1f55"}}
+{ "traceId": "16f5176887289baa94c27f12604b5163", "spanId": "556b9dbb760a1f55", "traceState": "", "parentSpanId": "a0333ab0c0fb425e", "name": "add_item_to_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:47.778251008Z", "endTime": "2021-04-20T20:33:47.802673152Z", "durationInNanos": 24422144, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "48c5f132edd1dce1"}}
+{ "traceId": "16f5176887289baa94c27f12604b5163", "spanId": "48c5f132edd1dce1", "traceState": "", "parentSpanId": "8d13c5fb5cb910ab", "name": "update_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:47.773860864Z", "endTime": "2021-04-20T20:33:47.903245568Z", "durationInNanos": 129384704, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 32932, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/update_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "f4fb15e340c39da3"}}
+{ "traceId": "2aa556a9a859155d7f578aacf259588f", "spanId": "f4fb15e340c39da3", "traceState": "", "parentSpanId": "36362df397ac500d", "name": "getCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:48.095176192Z", "endTime": "2021-04-20T20:33:48.123719936Z", "durationInNanos": 28543744, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "GET", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58806, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/get_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/get_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "9a8427df12be8522"}}
+{ "traceId": "2aa556a9a859155d7f578aacf259588f", "spanId": "9a8427df12be8522", "traceState": "", "parentSpanId": "60b801fae48abf9b", "name": "get_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:48.091967488Z", "endTime": "2021-04-20T20:33:48.140747776Z", "durationInNanos": 48780288, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "GET", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 32950, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/get_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/get_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "a23201e2aa2bf778"}}
+{ "traceId": "ecfe3ff116a31b4c5ec107289b615ff3", "spanId": "a23201e2aa2bf778", "traceState": "", "parentSpanId": "e2ce196e32791fa8", "name": "cartSold", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:48.390765568Z", "endTime": "2021-04-20T20:33:48.446376192Z", "durationInNanos": 55610624, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "DELETE", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58816, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/cart_sold", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/cart_sold", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "e2ce196e32791fa8"}}
+{ "traceId": "ecfe3ff116a31b4c5ec107289b615ff3", "spanId": "e2ce196e32791fa8", "traceState": "", "parentSpanId": "33de151285a224b8", "name": "HTTP DELETE", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:48.388591104Z", "endTime": "2021-04-20T20:33:48.451160064Z", "durationInNanos": 62568960, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/cart_sold", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "DELETE", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "5d15d016d2efc520"}}
+{ "traceId": "a7e35e333fe32a4fa0448bf258fff8e9", "spanId": "5d15d016d2efc520", "traceState": "", "parentSpanId": "", "name": "client_delivery_status", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:48.724736768Z", "endTime": "2021-04-20T20:33:48.783604992Z", "durationInNanos": 58868224, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_delivery_status", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "1ceb1ee0c0c5a3d7"}}
+{ "traceId": "25af475f804ec5edbfab9d1ba4018ce5", "spanId": "1ceb1ee0c0c5a3d7", "traceState": "", "parentSpanId": "81de5d2c6aa0859e", "name": "add_item_to_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:49.042982400Z", "endTime": "2021-04-20T20:33:49.067498752Z", "durationInNanos": 24516352, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "8397412a4368c536"}}
+{ "traceId": "96db5f125cb54111f2a95d7419df8a15", "spanId": "8397412a4368c536", "traceState": "", "parentSpanId": "b3e2c3a351f4d833", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:44.322510254Z", "endTime": "2021-04-20T20:33:44.323607252Z", "durationInNanos": 1096998, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-8", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 138, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "1b7829585cbc0b01"}}
+{ "traceId": "c0ef65e0d991727dbe26a071fd10e407", "spanId": "1b7829585cbc0b01", "traceState": "", "parentSpanId": "552e8512fb52ccb5", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:44.596480225Z", "endTime": "2021-04-20T20:33:44.597655556Z", "durationInNanos": 1175331, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-10", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 140, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "5610211164d655f6"}}
+{ "traceId": "70a3f615a998b76cd973d87710572913", "spanId": "5610211164d655f6", "traceState": "", "parentSpanId": "d2025fa5bde68d4c", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:45.006493344Z", "endTime": "2021-04-20T20:33:45.007802848Z", "durationInNanos": 1309504, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-3", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 133, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "e8af87596517f6bf"}}
+{ "traceId": "e48a85b3dc34426059aa1347ea4171a5", "spanId": "e8af87596517f6bf", "traceState": "", "parentSpanId": "934a3522bd05ed13", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:47.484509396Z", "endTime": "2021-04-20T20:33:47.485676993Z", "durationInNanos": 1167597, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-4", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 134, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "d2025fa5bde68d4c"}}
+{ "traceId": "70a3f615a998b76cd973d87710572913", "spanId": "d2025fa5bde68d4c", "traceState": "", "parentSpanId": "5ce9b5237f2b2bbd", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:45.006001630Z", "endTime": "2021-04-20T20:33:45.007923360Z", "durationInNanos": 1921730, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-3", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 133, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57912, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "fec494ea1cd015e3"}}
+{ "traceId": "65e793c50b861f00c1534090639dd7c3", "spanId": "fec494ea1cd015e3", "traceState": "", "parentSpanId": "04f07ddda2ec832d", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:45.301002074Z", "endTime": "2021-04-20T20:33:45.302720699Z", "durationInNanos": 1718625, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-4", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 134, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57922, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "2ac8b4cda3c0f1f9"}}
+{ "traceId": "02feb3a4f611abd81f2a53244d1278ae", "spanId": "2ac8b4cda3c0f1f9", "traceState": "", "parentSpanId": "d7ae88514a0b9617", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:45.711001942Z", "endTime": "2021-04-20T20:33:45.712721718Z", "durationInNanos": 1719776, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-6", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 136, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57940, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "e4f2d38e4f128be7"}}
+{ "traceId": "95b27b5462c0dccc7e08126a25e64d3f", "spanId": "e4f2d38e4f128be7", "traceState": "", "parentSpanId": "4bac6e5bfd5892b4", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:46.924001969Z", "endTime": "2021-04-20T20:33:46.925747176Z", "durationInNanos": 1745207, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-3", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 133, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57996, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "74dbc2be658b50d8"}}
+{ "traceId": "ecfe3ff116a31b4c5ec107289b615ff3", "spanId": "74dbc2be658b50d8", "traceState": "", "parentSpanId": "d3bce0f9acda8b4e", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:48.456001869Z", "endTime": "2021-04-20T20:33:48.457554150Z", "durationInNanos": 1552281, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-10", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 140, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58060, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "0c1e1c234af592e4"}}
+{ "traceId": "25af475f804ec5edbfab9d1ba4018ce5", "spanId": "0c1e1c234af592e4", "traceState": "", "parentSpanId": "c6c238ba3d8255f4", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:49.039726592Z", "endTime": "2021-04-20T20:33:49.077204224Z", "durationInNanos": 37477632, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/add_item_to_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "c6c238ba3d8255f4"}}
+{ "traceId": "25af475f804ec5edbfab9d1ba4018ce5", "spanId": "c6c238ba3d8255f4", "traceState": "", "parentSpanId": "27d4fe07134ea308", "name": "update_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:49.000050176Z", "endTime": "2021-04-20T20:33:49.130614784Z", "durationInNanos": 130564608, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "fb628320c3bd92c1"}}
+{ "traceId": "da0666d73c1645d392576e56619d8c6e", "spanId": "fb628320c3bd92c1", "traceState": "", "parentSpanId": "c7c175f4366ce130", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:49.312768512Z", "endTime": "2021-04-20T20:33:49.313572864Z", "durationInNanos": 804352, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "SELECT ItemId, TotalQty FROM User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "d03fde256c0d5e87"}}
+{ "traceId": "da0666d73c1645d392576e56619d8c6e", "spanId": "d03fde256c0d5e87", "traceState": "", "parentSpanId": "1e3aecf00776002e", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:49.354710528Z", "endTime": "2021-04-20T20:33:49.359258880Z", "durationInNanos": 4548352, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "8979ca2f03690516"}}
+{ "traceId": "da0666d73c1645d392576e56619d8c6e", "spanId": "8979ca2f03690516", "traceState": "", "parentSpanId": "f79bee55c88da9dd", "name": "HTTP DELETE", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:49.282687488Z", "endTime": "2021-04-20T20:33:49.369189632Z", "durationInNanos": 86502144, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8088/clear_order", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "DELETE", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "b5e9c2df83b5c950"}}
+{ "traceId": "c1bd83b99e3992292daa0888489e618c", "spanId": "b5e9c2df83b5c950", "traceState": "", "parentSpanId": "28991f1d3a174ce4", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:49.604470016Z", "endTime": "2021-04-20T20:33:49.642110208Z", "durationInNanos": 37640192, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/update_item", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "Not enough storage for itemId apple", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "span.attributes.component": "http", "status.code": 2, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 422 }
+{ "index":{"_id": "4167f155e728b1bf"}}
+{ "traceId": "c1bd83b99e3992292daa0888489e618c", "spanId": "4167f155e728b1bf", "traceState": "", "parentSpanId": "bb41f245f32492e4", "name": "payment", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:49.519380224Z", "endTime": "2021-04-20T20:33:49.656816384Z", "durationInNanos": 137436160, "serviceName": "payment", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8084, "span.attributes.http@status_text": "PARTIAL CONTENT", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "139782029922256", "resource.attributes.service@name": "payment", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 60116, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/checkout", "span.attributes.http@host": "localhost:8084", "span.attributes.http@target": "/checkout", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 206 }
+{ "index":{"_id": "5175f8f67d791920"}}
+{ "traceId": "7a3182e62d533fa1e0617f21f5681a37", "spanId": "5175f8f67d791920", "traceState": "", "parentSpanId": "cc39a5b2d98e4127", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:49.871913728Z", "endTime": "2021-04-20T20:33:49.873131008Z", "durationInNanos": 1217280, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "SELECT ItemId, TotalQty FROM User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "ecc02e73350ce790"}}
+{ "traceId": "7a3182e62d533fa1e0617f21f5681a37", "spanId": "ecc02e73350ce790", "traceState": "", "parentSpanId": "de9f1128bf12b7b9", "name": "HTTP PUT", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:49.848557312Z", "endTime": "2021-04-20T20:33:49.907510272Z", "durationInNanos": 58952960, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/cart_empty", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "PUT", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "1861602b0fed74c0"}}
+{ "traceId": "7a3182e62d533fa1e0617f21f5681a37", "spanId": "1861602b0fed74c0", "traceState": "", "parentSpanId": "a9019c51b85c9ac6", "name": "clear_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:49.847567872Z", "endTime": "2021-04-20T20:33:49.920374784Z", "durationInNanos": 72806912, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "DELETE", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 33026, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/clear_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/clear_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "a9019c51b85c9ac6"}}
+{ "traceId": "7a3182e62d533fa1e0617f21f5681a37", "spanId": "a9019c51b85c9ac6", "traceState": "", "parentSpanId": "034ed8cfb8ba682a", "name": "HTTP DELETE", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:49.845530624Z", "endTime": "2021-04-20T20:33:49.925377792Z", "durationInNanos": 79847168, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8088/clear_order", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "DELETE", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "d6737261234573e3"}}
+{ "traceId": "247d610dcbd05da1c7902081b6bec1f6", "spanId": "d6737261234573e3", "traceState": "", "parentSpanId": "0fa03fca5ea8c051", "name": "addItemToCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:50.143993600Z", "endTime": "2021-04-20T20:33:50.172754688Z", "durationInNanos": 28761088, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58892, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/add_item_to_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/add_item_to_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "e684414d71481506"}}
+{ "traceId": "247d610dcbd05da1c7902081b6bec1f6", "spanId": "e684414d71481506", "traceState": "", "parentSpanId": "55b6879fed1f14b7", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:50.242910208Z", "endTime": "2021-04-20T20:33:50.243621632Z", "durationInNanos": 711424, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'banana', 'Qty': '2'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "25d2d59e3e627ee7"}}
+{ "traceId": "eef4554373e188267b38928e2dabeab4", "spanId": "25d2d59e3e627ee7", "traceState": "", "parentSpanId": "6a539e36635daed1", "name": "get_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:50.481526016Z", "endTime": "2021-04-20T20:33:50.506380544Z", "durationInNanos": 24854528, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "13bed71d66dcc038"}}
+{ "traceId": "eef4554373e188267b38928e2dabeab4", "spanId": "13bed71d66dcc038", "traceState": "", "parentSpanId": "9232ae83ea33fee8", "name": "HTTP GET", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:50.478371840Z", "endTime": "2021-04-20T20:33:50.514467584Z", "durationInNanos": 36095744, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/get_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "GET", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "c29268a1fd31d7d1"}}
+{ "traceId": "eef4554373e188267b38928e2dabeab4", "spanId": "c29268a1fd31d7d1", "traceState": "", "parentSpanId": "9232ae83ea33fee8", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:50.517328128Z", "endTime": "2021-04-20T20:33:50.522111488Z", "durationInNanos": 4783360, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "7ca71ea50061e17a"}}
+{ "traceId": "20eabd650f3a068d9f590786f56885e7", "spanId": "7ca71ea50061e17a", "traceState": "", "parentSpanId": "2e36371a9ffe2dc0", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:50.751403008Z", "endTime": "2021-04-20T20:33:50.752038912Z", "durationInNanos": 635904, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'apple', 'Qty': '1'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "c7c7d4012d81b142"}}
+{ "traceId": "20eabd650f3a068d9f590786f56885e7", "spanId": "c7c7d4012d81b142", "traceState": "", "parentSpanId": "e7287e116f07049d", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:50.792653056Z", "endTime": "2021-04-20T20:33:50.793349632Z", "durationInNanos": 696576, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'orange', 'Qty': '3'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "ecc0e3f8be5250dd"}}
+{ "traceId": "20eabd650f3a068d9f590786f56885e7", "spanId": "ecc0e3f8be5250dd", "traceState": "", "parentSpanId": "cebaa948cfa4cc19", "name": "addItemToCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:50.811156480Z", "endTime": "2021-04-20T20:33:50.840189440Z", "durationInNanos": 29032960, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58930, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/add_item_to_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/add_item_to_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "534023ef492ea75d"}}
+{ "traceId": "c48260d3774d6c2d4ba77c9e813eadec", "spanId": "534023ef492ea75d", "traceState": "", "parentSpanId": "c5ab512bce3105ef", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:51.158956032Z", "endTime": "2021-04-20T20:33:51.159533568Z", "durationInNanos": 577536, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "SELECT * FROM User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "e9893407bba95bf0"}}
+{ "traceId": "c48260d3774d6c2d4ba77c9e813eadec", "spanId": "e9893407bba95bf0", "traceState": "", "parentSpanId": "76dfb45c3ba7873f", "name": "HTTP GET", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:51.136340992Z", "endTime": "2021-04-20T20:33:51.171475200Z", "durationInNanos": 35134208, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/get_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "GET", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "608bd5e547e88e3e"}}
+{ "traceId": "56127a0a4f362cfb605a907e6c419c6e", "spanId": "608bd5e547e88e3e", "traceState": "", "parentSpanId": "2b7af871bd8cd43f", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:51.475266048Z", "endTime": "2021-04-20T20:33:51.480210688Z", "durationInNanos": 4944640, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "bd638d2bf13e4f41"}}
+{ "traceId": "56127a0a4f362cfb605a907e6c419c6e", "spanId": "bd638d2bf13e4f41", "traceState": "", "parentSpanId": "8defb053817ab655", "name": "pay_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:51.412930816Z", "endTime": "2021-04-20T20:33:51.485616640Z", "durationInNanos": 72685824, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 33094, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/pay_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/pay_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "dcab66f931f7fc5b"}}
+{ "traceId": "56127a0a4f362cfb605a907e6c419c6e", "spanId": "dcab66f931f7fc5b", "traceState": "", "parentSpanId": "", "name": "client_pay_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:51.410483968Z", "endTime": "2021-04-20T20:33:51.493332480Z", "durationInNanos": 82848512, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_pay_order", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "9b81a0201a53b84c"}}
+{ "traceId": "7f63958e2172b12500e40eed557a31c7", "spanId": "9b81a0201a53b84c", "traceState": "", "parentSpanId": "de85f1e0d746da28", "name": "getCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:51.682416128Z", "endTime": "2021-04-20T20:33:51.712218624Z", "durationInNanos": 29802496, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "GET", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58960, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/get_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/get_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "e2a28bb8e6bf64ca"}}
+{ "traceId": "7f63958e2172b12500e40eed557a31c7", "spanId": "e2a28bb8e6bf64ca", "traceState": "", "parentSpanId": "3301dd384d83dc66", "name": "get_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:51.680000512Z", "endTime": "2021-04-20T20:33:51.727677440Z", "durationInNanos": 47676928, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "9de35fba7cb7c4a3"}}
+{ "traceId": "7f63958e2172b12500e40eed557a31c7", "spanId": "9de35fba7cb7c4a3", "traceState": "", "parentSpanId": "637cedb12aa88454", "name": "HTTP GET", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:51.677016320Z", "endTime": "2021-04-20T20:33:51.734535680Z", "durationInNanos": 57519360, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8088/get_order", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "GET", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "637cedb12aa88454"}}
+{ "traceId": "7f63958e2172b12500e40eed557a31c7", "spanId": "637cedb12aa88454", "traceState": "", "parentSpanId": "", "name": "client_delivery_status", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:51.676719872Z", "endTime": "2021-04-20T20:33:51.737385984Z", "durationInNanos": 60666112, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_delivery_status", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "06f27e83cdad4af6"}}
+{ "traceId": "340a6c6f70a21d1bc8456dbbe5c79929", "spanId": "06f27e83cdad4af6", "traceState": "", "parentSpanId": "439eff3f753e8e67", "name": "addItemToCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:51.995934208Z", "endTime": "2021-04-20T20:33:52.024369152Z", "durationInNanos": 28434944, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58974, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/add_item_to_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/add_item_to_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "1fdfb0d6a0c76960"}}
+{ "traceId": "261f4f9f6d49c04588ddfc0b22d167c6", "spanId": "1fdfb0d6a0c76960", "traceState": "", "parentSpanId": "a748c29eeb1d7e59", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:52.231162624Z", "endTime": "2021-04-20T20:33:52.231785216Z", "durationInNanos": 622592, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "SELECT ItemId, TotalQty FROM User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "18172e3a91f55d39"}}
+{ "traceId": "261f4f9f6d49c04588ddfc0b22d167c6", "spanId": "18172e3a91f55d39", "traceState": "", "parentSpanId": "a748c29eeb1d7e59", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:52.235772416Z", "endTime": "2021-04-20T20:33:52.256177152Z", "durationInNanos": 20404736, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "TRUNCATE TABLE User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "a748c29eeb1d7e59"}}
+{ "traceId": "261f4f9f6d49c04588ddfc0b22d167c6", "spanId": "a748c29eeb1d7e59", "traceState": "", "parentSpanId": "adbedfaf38a87985", "name": "cart_empty", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:52.211242240Z", "endTime": "2021-04-20T20:33:52.259230720Z", "durationInNanos": 47988480, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "adbedfaf38a87985"}}
+{ "traceId": "261f4f9f6d49c04588ddfc0b22d167c6", "spanId": "adbedfaf38a87985", "traceState": "", "parentSpanId": "ba003d4618b074f7", "name": "cartEmpty", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:52.210340352Z", "endTime": "2021-04-20T20:33:52.262700032Z", "durationInNanos": 52359680, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "PUT", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58988, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/cart_empty", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/cart_empty", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "66dd3959b912162c"}}
+{ "traceId": "261f4f9f6d49c04588ddfc0b22d167c6", "spanId": "66dd3959b912162c", "traceState": "", "parentSpanId": "", "name": "client_cancel_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:52.204713472Z", "endTime": "2021-04-20T20:33:52.288004096Z", "durationInNanos": 83290624, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_cancel_order", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "4543b1bfbb5964c3"}}
+{ "traceId": "5be8370207cbb002a165d369fbc57b57", "spanId": "4543b1bfbb5964c3", "traceState": "", "parentSpanId": "702250f453a02be6", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:52.497326080Z", "endTime": "2021-04-20T20:33:52.532990720Z", "durationInNanos": 35664640, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/add_item_to_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "45c65220620defaf"}}
+{ "traceId": "5be8370207cbb002a165d369fbc57b57", "spanId": "45c65220620defaf", "traceState": "", "parentSpanId": "b4e1a6127d470651", "name": "add_item_to_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:52.539106304Z", "endTime": "2021-04-20T20:33:52.563575552Z", "durationInNanos": 24469248, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "179c014a060ab428"}}
+{ "traceId": "5be8370207cbb002a165d369fbc57b57", "spanId": "179c014a060ab428", "traceState": "", "parentSpanId": "f6691ab391b0e350", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:52.598380800Z", "endTime": "2021-04-20T20:33:52.599080704Z", "durationInNanos": 699904, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'banana', 'Qty': '2'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "f6691ab391b0e350"}}
+{ "traceId": "5be8370207cbb002a165d369fbc57b57", "spanId": "f6691ab391b0e350", "traceState": "", "parentSpanId": "f3dc908cffab10fe", "name": "add_item_to_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:52.578200832Z", "endTime": "2021-04-20T20:33:52.603235328Z", "durationInNanos": 25034496, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "6a8149f2f3269df9"}}
+{ "traceId": "5be8370207cbb002a165d369fbc57b57", "spanId": "6a8149f2f3269df9", "traceState": "", "parentSpanId": "702250f453a02be6", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:52.614755328Z", "endTime": "2021-04-20T20:33:52.619177472Z", "durationInNanos": 4422144, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "c52d1f54270c1a88"}}
+{ "traceId": "5be8370207cbb002a165d369fbc57b57", "spanId": "c52d1f54270c1a88", "traceState": "", "parentSpanId": "", "name": "client_create_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:52.493635840Z", "endTime": "2021-04-20T20:33:52.632568064Z", "durationInNanos": 138932224, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_create_order", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "5b1ed6116a19ebcc"}}
+{ "traceId": "4216a647a4396e50fc12cc78d571557e", "spanId": "5b1ed6116a19ebcc", "traceState": "", "parentSpanId": "14148032cdebd6e5", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:52.698918400Z", "endTime": "2021-04-20T20:33:52.699564800Z", "durationInNanos": 646400, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'apple', 'Qty': '1'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "680639d2b7681a2a"}}
+{ "traceId": "4216a647a4396e50fc12cc78d571557e", "spanId": "680639d2b7681a2a", "traceState": "", "parentSpanId": "d85ef60c6b05ea1e", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:52.675642368Z", "endTime": "2021-04-20T20:33:52.711814144Z", "durationInNanos": 36171776, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/add_item_to_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "f30e9c92926901d9"}}
+{ "traceId": "4216a647a4396e50fc12cc78d571557e", "spanId": "f30e9c92926901d9", "traceState": "", "parentSpanId": "70e7adcb0023b919", "name": "addItemToCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:52.756263936Z", "endTime": "2021-04-20T20:33:52.785140224Z", "durationInNanos": 28876288, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 59024, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/add_item_to_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/add_item_to_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "1aa4ab0af82bbbb2"}}
+{ "traceId": "e447ed617aa651a7593c720d7e976625", "spanId": "1aa4ab0af82bbbb2", "traceState": "", "parentSpanId": "b6b76ad0ea7a18e0", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:52.954985472Z", "endTime": "2021-04-20T20:33:52.978256896Z", "durationInNanos": 23271424, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "TRUNCATE TABLE User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "b6b76ad0ea7a18e0"}}
+{ "traceId": "e447ed617aa651a7593c720d7e976625", "spanId": "b6b76ad0ea7a18e0", "traceState": "", "parentSpanId": "bffbe84728e92b6d", "name": "cart_empty", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:52.930167040Z", "endTime": "2021-04-20T20:33:52.981641472Z", "durationInNanos": 51474432, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "68f6536a0523f7f3"}}
+{ "traceId": "0bda4f69a15675f56069fa7b677f1c74", "spanId": "68f6536a0523f7f3", "traceState": "", "parentSpanId": "2badcc8448bd5c5b", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:53.215277568Z", "endTime": "2021-04-20T20:33:53.253143808Z", "durationInNanos": 37866240, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/update_item", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "Not enough storage for itemId banana", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "span.attributes.component": "http", "status.code": 2, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 422 }
+{ "index":{"_id": "a4030e9ad85b2a92"}}
+{ "traceId": "0bda4f69a15675f56069fa7b677f1c74", "spanId": "a4030e9ad85b2a92", "traceState": "", "parentSpanId": "057ca06095200357", "name": "update_item", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:53.259318272Z", "endTime": "2021-04-20T20:33:53.284444928Z", "durationInNanos": 25126656, "serviceName": "database", "events": [ { "time": "2021-04-20T20:33:53.284412416Z", "name": "exception", "attributes": { "exception@message": "", "exception@type": "InvalidItemUpdate", "exception@stacktrace": """Traceback (most recent call last): File "/usr/lib/python3.6/site-packages/opentelemetry/sdk/trace/__init__.py", line 804, in use_span yield span File "databaseService.py", line 162, in updateItem raise InvalidItemUpdate("Not enough storage for itemId {}".format(data[ "ItemId" ])) InvalidItemUpdate """ }, "droppedAttributesCount": 0 } ], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "status.message": "InvalidItemUpdate: ", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 2, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "4244f688b5a95a26"}}
+{ "traceId": "0bda4f69a15675f56069fa7b677f1c74", "spanId": "4244f688b5a95a26", "traceState": "", "parentSpanId": "49bd0e3a571e477d", "name": "update_item", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:53.301197056Z", "endTime": "2021-04-20T20:33:53.326327296Z", "durationInNanos": 25130240, "serviceName": "database", "events": [ { "time": "2021-04-20T20:33:53.326294016Z", "name": "exception", "attributes": { "exception@message": "", "exception@type": "InvalidItemUpdate", "exception@stacktrace": """Traceback (most recent call last): File "/usr/lib/python3.6/site-packages/opentelemetry/sdk/trace/__init__.py", line 804, in use_span yield span File "databaseService.py", line 162, in updateItem raise InvalidItemUpdate("Not enough storage for itemId {}".format(data[ "ItemId" ])) InvalidItemUpdate """ }, "droppedAttributesCount": 0 } ], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "status.message": "InvalidItemUpdate: ", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 2, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "49bd0e3a571e477d"}}
+{ "traceId": "0bda4f69a15675f56069fa7b677f1c74", "spanId": "49bd0e3a571e477d", "traceState": "", "parentSpanId": "06d1242a51405187", "name": "updateItem", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:53.300201216Z", "endTime": "2021-04-20T20:33:53.330773248Z", "durationInNanos": 30572032, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "Not enough storage for itemId apple", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 2, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 59056, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_item", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/update_item", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 422 }
+{ "index":{"_id": "a03d0ff09010abc3"}}
+{ "traceId": "0bda4f69a15675f56069fa7b677f1c74", "spanId": "a03d0ff09010abc3", "traceState": "", "parentSpanId": "66a2144a58008463", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:53.211857408Z", "endTime": "2021-04-20T20:33:53.345646848Z", "durationInNanos": 133789440, "serviceName": "payment", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8082/update_inventory", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "Update inventory response contains failed items.", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "139782029922256", "resource.attributes.service@name": "payment", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 206 }
+{ "index":{"_id": "1baf1e42d2eaae2a"}}
+{ "traceId": "d5bc99166e521eec173bcb7f9b0d3c43", "spanId": "1baf1e42d2eaae2a", "traceState": "", "parentSpanId": "cefea796ccf54813", "name": "HTTP PUT", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:53.429764096Z", "endTime": "2021-04-20T20:33:53.493248256Z", "durationInNanos": 63484160, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/cart_empty", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "PUT", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "1dc7b46c2357c388"}}
+{ "traceId": "d5bc99166e521eec173bcb7f9b0d3c43", "spanId": "1dc7b46c2357c388", "traceState": "", "parentSpanId": "2aec9c6345d7c6b3", "name": "HTTP DELETE", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:53.426487808Z", "endTime": "2021-04-20T20:33:53.509910016Z", "durationInNanos": 83422208, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8088/clear_order", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "DELETE", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "86b490f5558fa709"}}
+{ "traceId": "25af475f804ec5edbfab9d1ba4018ce5", "spanId": "86b490f5558fa709", "traceState": "", "parentSpanId": "32c7b65db72d6298", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:49.125418594Z", "endTime": "2021-04-20T20:33:49.126411716Z", "durationInNanos": 993122, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-4", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 134, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "f8d135e17dd59043"}}
+{ "traceId": "7f63958e2172b12500e40eed557a31c7", "spanId": "f8d135e17dd59043", "traceState": "", "parentSpanId": "1fe046d4f9f3bd13", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:51.722447259Z", "endTime": "2021-04-20T20:33:51.723605629Z", "durationInNanos": 1158370, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-10", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 140, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "32c7b65db72d6298"}}
+{ "traceId": "25af475f804ec5edbfab9d1ba4018ce5", "spanId": "32c7b65db72d6298", "traceState": "", "parentSpanId": "d74d48bf3431c487", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:49.125001550Z", "endTime": "2021-04-20T20:33:49.126513995Z", "durationInNanos": 1512445, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-4", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 134, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58088, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "50347b6be84490e4"}}
+{ "traceId": "da0666d73c1645d392576e56619d8c6e", "spanId": "50347b6be84490e4", "traceState": "", "parentSpanId": "d03fde256c0d5e87", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:49.356001691Z", "endTime": "2021-04-20T20:33:49.357803832Z", "durationInNanos": 1802141, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-6", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 136, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58098, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "d0c7228a8eb81715"}}
+{ "traceId": "20eabd650f3a068d9f590786f56885e7", "spanId": "d0c7228a8eb81715", "traceState": "", "parentSpanId": "268c00835c4cc7ac", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:50.850001822Z", "endTime": "2021-04-20T20:33:50.851659846Z", "durationInNanos": 1658024, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-4", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 134, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58174, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "0f929cd09feb717a"}}
+{ "traceId": "4216a647a4396e50fc12cc78d571557e", "spanId": "0f929cd09feb717a", "traceState": "", "parentSpanId": "84584d9e50950ea5", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:52.818001824Z", "endTime": "2021-04-20T20:33:52.819591628Z", "durationInNanos": 1589804, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-8", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 138, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58268, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "b272143e732a91e9"}}
+{ "traceId": "e447ed617aa651a7593c720d7e976625", "spanId": "b272143e732a91e9", "traceState": "", "parentSpanId": "477408f3368f28af", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:52.995002208Z", "endTime": "2021-04-20T20:33:52.996554316Z", "durationInNanos": 1552108, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-10", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 140, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58278, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "06e4387a53eec8ae"}}
+{ "traceId": "4626b16656c8131c17bef721f94f39d0", "spanId": "06e4387a53eec8ae", "traceState": "", "parentSpanId": "", "name": "HTTP GET", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:19.541728768Z", "endTime": "2021-04-20T20:33:19.544739584Z", "durationInNanos": 3010816, "serviceName": "recommendation", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "HTTP GET", "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8086, "span.attributes.http@status_text": "NOT FOUND", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140018306314192", "resource.attributes.service@name": "recommendation", "span.attributes.component": "http", "status.code": 2, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "GET", "span.attributes.http@user_agent": "curl/7.61.1", "span.attributes.net@peer@port": 42362, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@host": "localhost:8086", "span.attributes.http@target": "/", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 404 }
+{ "index":{"_id": "60393741cd2ba5da"}}
+{ "traceId": "5a551c574ba60b0fddee0a98150ad7c6", "spanId": "60393741cd2ba5da", "traceState": "", "parentSpanId": "", "name": "HTTP GET", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:20.558674688Z", "endTime": "2021-04-20T20:33:20.561958656Z", "durationInNanos": 3283968, "serviceName": "authentication", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "HTTP GET", "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8085, "span.attributes.http@status_text": "NOT FOUND", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "139949516139040", "resource.attributes.service@name": "authentication", "span.attributes.component": "http", "status.code": 2, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "GET", "span.attributes.http@user_agent": "curl/7.61.1", "span.attributes.net@peer@port": 37624, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@host": "localhost:8085", "span.attributes.http@target": "/", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 404 }
+{ "index":{"_id": "840eaf798fcd7d6a"}}
+{ "traceId": "513e4f752e4411aa6d4b6b35878172f3", "spanId": "840eaf798fcd7d6a", "traceState": "", "parentSpanId": "d3c888f442bdf005", "name": "payment", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:29.225169408Z", "endTime": "2021-04-20T20:33:29.237534464Z", "durationInNanos": 12365056, "serviceName": "payment", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8084, "span.attributes.http@status_text": "SERVICE UNAVAILABLE", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "139782029922256", "resource.attributes.service@name": "payment", "span.attributes.component": "http", "status.code": 2, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 59546, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/checkout", "span.attributes.http@host": "localhost:8084", "span.attributes.http@target": "/checkout", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 503 }
+{ "index":{"_id": "647e42f1b60baba6"}}
+{ "traceId": "d37d709d5695f213e4ca41ac874c00bc", "spanId": "647e42f1b60baba6", "traceState": "", "parentSpanId": "8e7e103a2e3a040f", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:32.582873344Z", "endTime": "2021-04-20T20:33:32.583549440Z", "durationInNanos": 676096, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "SELECT * FROM Inventory_Items", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "519baeb3e108614d"}}
+{ "traceId": "d37d709d5695f213e4ca41ac874c00bc", "spanId": "519baeb3e108614d", "traceState": "", "parentSpanId": "65bcaf9c16235fec", "name": "getIntentory", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:32.557999360Z", "endTime": "2021-04-20T20:33:32.590999808Z", "durationInNanos": 33000448, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "GET", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58316, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/get_inventory", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/get_inventory", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "caed30931d6c8826"}}
+{ "traceId": "d37d709d5695f213e4ca41ac874c00bc", "spanId": "caed30931d6c8826", "traceState": "", "parentSpanId": "88484a1ee3c170cd", "name": "recommend", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:32.547260416Z", "endTime": "2021-04-20T20:33:32.628968960Z", "durationInNanos": 81708544, "serviceName": "recommendation", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8086, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140018306314192", "resource.attributes.service@name": "recommendation", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "GET", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 42416, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/recommend", "span.attributes.http@host": "localhost:8086", "span.attributes.http@target": "/recommend", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "40c037eaae087000"}}
+{ "traceId": "509da2ddfc1a3d9fc88ed4b62f3cd079", "spanId": "40c037eaae087000", "traceState": "", "parentSpanId": "55d7f80c6aff4ec7", "name": "addItemToCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:34.314483968Z", "endTime": "2021-04-20T20:33:34.349315328Z", "durationInNanos": 34831360, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58344, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/add_item_to_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/add_item_to_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "ec44bfc9b38f6faf"}}
+{ "traceId": "c17023ed734d4daa5f97bb7972f0c935", "spanId": "ec44bfc9b38f6faf", "traceState": "", "parentSpanId": "ab460c6800da22bf", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:34.727146240Z", "endTime": "2021-04-20T20:33:34.727824384Z", "durationInNanos": 678144, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "SELECT * FROM User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "ab460c6800da22bf"}}
+{ "traceId": "c17023ed734d4daa5f97bb7972f0c935", "spanId": "ab460c6800da22bf", "traceState": "", "parentSpanId": "066eee06004804d5", "name": "get_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:34.707429632Z", "endTime": "2021-04-20T20:33:34.731620608Z", "durationInNanos": 24190976, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "066eee06004804d5"}}
+{ "traceId": "c17023ed734d4daa5f97bb7972f0c935", "spanId": "066eee06004804d5", "traceState": "", "parentSpanId": "bb8e3a8935263a0e", "name": "getCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:34.706544640Z", "endTime": "2021-04-20T20:33:34.734942208Z", "durationInNanos": 28397568, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "GET", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58354, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/get_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/get_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "bb8e3a8935263a0e"}}
+{ "traceId": "c17023ed734d4daa5f97bb7972f0c935", "spanId": "bb8e3a8935263a0e", "traceState": "", "parentSpanId": "60845ba7d8c2aaf0", "name": "HTTP GET", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:34.704376320Z", "endTime": "2021-04-20T20:33:34.739784704Z", "durationInNanos": 35408384, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/get_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "GET", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "99d7b8673d19932d"}}
+{ "traceId": "c17023ed734d4daa5f97bb7972f0c935", "spanId": "99d7b8673d19932d", "traceState": "", "parentSpanId": "60845ba7d8c2aaf0", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:34.742878464Z", "endTime": "2021-04-20T20:33:34.748727296Z", "durationInNanos": 5848832, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "174b6e4f69dd2d18"}}
+{ "traceId": "9cc5c0acce9b9acc05b1c8d082709609", "spanId": "174b6e4f69dd2d18", "traceState": "", "parentSpanId": "9b3c0b3ed5c876e6", "name": "cart_sold", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:35.171959296Z", "endTime": "2021-04-20T20:33:35.219812352Z", "durationInNanos": 47853056, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "6f9eca809cfd10f4"}}
+{ "traceId": "7df67f7205abe19319bad85babb04ca9", "spanId": "6f9eca809cfd10f4", "traceState": "", "parentSpanId": "1cfde34b0e64708d", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:35.738551040Z", "endTime": "2021-04-20T20:33:35.739376640Z", "durationInNanos": 825600, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'orange', 'Qty': '3'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "INSERT INTO User_Carts (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "cc1bd6dba046b476"}}
+{ "traceId": "7df67f7205abe19319bad85babb04ca9", "spanId": "cc1bd6dba046b476", "traceState": "", "parentSpanId": "bb9e8ac613f9c314", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:35.783496704Z", "endTime": "2021-04-20T20:33:35.784163328Z", "durationInNanos": 666624, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'banana', 'Qty': '2'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "INSERT INTO User_Carts (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "17573d14a639e1d1"}}
+{ "traceId": "7df67f7205abe19319bad85babb04ca9", "spanId": "17573d14a639e1d1", "traceState": "", "parentSpanId": "285b2f9d476d9a6f", "name": "update_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:35.663353600Z", "endTime": "2021-04-20T20:33:35.810676480Z", "durationInNanos": 147322880, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 60752, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/update_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "c2340bad2c8d7620"}}
+{ "traceId": "7df67f7205abe19319bad85babb04ca9", "spanId": "c2340bad2c8d7620", "traceState": "", "parentSpanId": "", "name": "client_create_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:35.660813824Z", "endTime": "2021-04-20T20:33:35.818663168Z", "durationInNanos": 157849344, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_create_order", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "7fe759e9e512c8ff"}}
+{ "traceId": "19b592faebd7e10a4824b919bcd3bd89", "spanId": "7fe759e9e512c8ff", "traceState": "", "parentSpanId": "42b721754a8f6168", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:36.099666432Z", "endTime": "2021-04-20T20:33:36.100590592Z", "durationInNanos": 924160, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'apple', 'Qty': 1}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "INSERT INTO Inventory_Items (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "3c71472fb76ad5e6"}}
+{ "traceId": "19b592faebd7e10a4824b919bcd3bd89", "spanId": "3c71472fb76ad5e6", "traceState": "", "parentSpanId": "42b721754a8f6168", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:36.107451904Z", "endTime": "2021-04-20T20:33:36.108079616Z", "durationInNanos": 627712, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'orange', 'Qty': 3}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "INSERT INTO Inventory_Items (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "8e2e0e3da163fc3b"}}
+{ "traceId": "19b592faebd7e10a4824b919bcd3bd89", "spanId": "8e2e0e3da163fc3b", "traceState": "", "parentSpanId": "42b721754a8f6168", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:36.113731328Z", "endTime": "2021-04-20T20:33:36.139224064Z", "durationInNanos": 25492736, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "TRUNCATE TABLE User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "42b721754a8f6168"}}
+{ "traceId": "19b592faebd7e10a4824b919bcd3bd89", "spanId": "42b721754a8f6168", "traceState": "", "parentSpanId": "cb2b82acca479730", "name": "cart_empty", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:36.074103296Z", "endTime": "2021-04-20T20:33:36.142439680Z", "durationInNanos": 68336384, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "ad7845eabc7145cd"}}
+{ "traceId": "19b592faebd7e10a4824b919bcd3bd89", "spanId": "ad7845eabc7145cd", "traceState": "", "parentSpanId": "db173bc10299861f", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:36.155145984Z", "endTime": "2021-04-20T20:33:36.160770816Z", "durationInNanos": 5624832, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "ac0d61f7be00cc09"}}
+{ "traceId": "cb077f0c195ce825befded0fb71c76f1", "spanId": "ac0d61f7be00cc09", "traceState": "", "parentSpanId": "4f70367bf3c97d0e", "name": "updateItem", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:36.574601472Z", "endTime": "2021-04-20T20:33:36.606697728Z", "durationInNanos": 32096256, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58414, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_item", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/update_item", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "4f70367bf3c97d0e"}}
+{ "traceId": "cb077f0c195ce825befded0fb71c76f1", "spanId": "4f70367bf3c97d0e", "traceState": "", "parentSpanId": "b5eb104616d427e5", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:36.572322816Z", "endTime": "2021-04-20T20:33:36.611627264Z", "durationInNanos": 39304448, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/update_item", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "375cb3ef27c46997"}}
+{ "traceId": "cb077f0c195ce825befded0fb71c76f1", "spanId": "375cb3ef27c46997", "traceState": "", "parentSpanId": "b5ef9ef1ecddda5e", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:36.485675264Z", "endTime": "2021-04-20T20:33:36.629994496Z", "durationInNanos": 144319232, "serviceName": "payment", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8082/update_inventory", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "139782029922256", "resource.attributes.service@name": "payment", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "60019ca1c2f5ab8e"}}
+{ "traceId": "cb077f0c195ce825befded0fb71c76f1", "spanId": "60019ca1c2f5ab8e", "traceState": "", "parentSpanId": "d3911d8b057539bb", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:36.481851648Z", "endTime": "2021-04-20T20:33:36.647876864Z", "durationInNanos": 166025216, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8084/checkout", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "a7fcdbe2bf6d6d75"}}
+{ "traceId": "ec830c13f81efb5082f6e40b4dedce71", "spanId": "a7fcdbe2bf6d6d75", "traceState": "", "parentSpanId": "7c058c08a86fc5a8", "name": "clear_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:36.996497920Z", "endTime": "2021-04-20T20:33:37.070610176Z", "durationInNanos": 74112256, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "7c058c08a86fc5a8"}}
+{ "traceId": "ec830c13f81efb5082f6e40b4dedce71", "spanId": "7c058c08a86fc5a8", "traceState": "", "parentSpanId": "68cf95323b3af152", "name": "clear_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:36.995693312Z", "endTime": "2021-04-20T20:33:37.072949248Z", "durationInNanos": 77255936, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "DELETE", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 60802, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/clear_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/clear_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "68cf95323b3af152"}}
+{ "traceId": "ec830c13f81efb5082f6e40b4dedce71", "spanId": "68cf95323b3af152", "traceState": "", "parentSpanId": "bfcda24f22004149", "name": "HTTP DELETE", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:36.993572608Z", "endTime": "2021-04-20T20:33:37.077576704Z", "durationInNanos": 84004096, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8088/clear_order", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "DELETE", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "bfcda24f22004149"}}
+{ "traceId": "ec830c13f81efb5082f6e40b4dedce71", "spanId": "bfcda24f22004149", "traceState": "", "parentSpanId": "", "name": "client_cancel_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:36.993322752Z", "endTime": "2021-04-20T20:33:37.080295680Z", "durationInNanos": 86972928, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_cancel_order", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "8fd6fd77a11f4983"}}
+{ "traceId": "1730cc8687cb4b504cd934560111d5a1", "spanId": "8fd6fd77a11f4983", "traceState": "", "parentSpanId": "b4f529ee6fed4e49", "name": "addItemToCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:37.408389376Z", "endTime": "2021-04-20T20:33:37.443986176Z", "durationInNanos": 35596800, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58436, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/add_item_to_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/add_item_to_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "71529953e9aa20e1"}}
+{ "traceId": "1730cc8687cb4b504cd934560111d5a1", "spanId": "71529953e9aa20e1", "traceState": "", "parentSpanId": "67a615bb3d2aef86", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:37.544745216Z", "endTime": "2021-04-20T20:33:37.549624064Z", "durationInNanos": 4878848, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "523a0808d6e0be58"}}
+{ "traceId": "c9f83a98e8f1826c3a822eeb7b85a9d6", "spanId": "523a0808d6e0be58", "traceState": "", "parentSpanId": "", "name": "client_cancel_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:37.780772864Z", "endTime": "2021-04-20T20:33:37.882267392Z", "durationInNanos": 101494528, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_cancel_order", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "aaa95e9f50a4baa3"}}
+{ "traceId": "22bdfd493901782340e7eea9e077acb9", "spanId": "aaa95e9f50a4baa3", "traceState": "", "parentSpanId": "7bc2fe0a60e01dba", "name": "update_item", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:38.200260352Z", "endTime": "2021-04-20T20:33:38.226785024Z", "durationInNanos": 26524672, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "56925faca063f848"}}
+{ "traceId": "22bdfd493901782340e7eea9e077acb9", "spanId": "56925faca063f848", "traceState": "", "parentSpanId": "1b26c8058d3cd7b6", "name": "updateItem", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:38.240576512Z", "endTime": "2021-04-20T20:33:38.272510720Z", "durationInNanos": 31934208, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58474, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_item", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/update_item", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "36883585e85d1b73"}}
+{ "traceId": "82c7cf3d3540450a3acc00c41b7a9562", "spanId": "36883585e85d1b73", "traceState": "", "parentSpanId": "0f425b86cb459271", "name": "updateItem", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:38.619970304Z", "endTime": "2021-04-20T20:33:38.653283072Z", "durationInNanos": 33312768, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58498, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_item", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/update_item", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "e8365c37ca6c41a9"}}
+{ "traceId": "82c7cf3d3540450a3acc00c41b7a9562", "spanId": "e8365c37ca6c41a9", "traceState": "", "parentSpanId": "95441fc1d382e48d", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:38.702615040Z", "endTime": "2021-04-20T20:33:38.707414784Z", "durationInNanos": 4799744, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "cc87be09db83951c"}}
+{ "traceId": "82c7cf3d3540450a3acc00c41b7a9562", "spanId": "cc87be09db83951c", "traceState": "", "parentSpanId": "eb63409f597c3607", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:38.557328128Z", "endTime": "2021-04-20T20:33:38.718940928Z", "durationInNanos": 161612800, "serviceName": "payment", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8082/update_inventory", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "139782029922256", "resource.attributes.service@name": "payment", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "eb63409f597c3607"}}
+{ "traceId": "82c7cf3d3540450a3acc00c41b7a9562", "spanId": "eb63409f597c3607", "traceState": "", "parentSpanId": "07b4d48cb660e9cc", "name": "checkout", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:38.556882688Z", "endTime": "2021-04-20T20:33:38.734543616Z", "durationInNanos": 177660928, "serviceName": "payment", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "139782029922256", "resource.attributes.service@name": "payment", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "d250018f35242056"}}
+{ "traceId": "ec830c13f81efb5082f6e40b4dedce71", "spanId": "d250018f35242056", "traceState": "", "parentSpanId": "c9b6a51576561f98", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:37.065582317Z", "endTime": "2021-04-20T20:33:37.066913Z", "durationInNanos": 1330683, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-8", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 138, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "7b78d2bea411b2fe"}}
+{ "traceId": "509da2ddfc1a3d9fc88ed4b62f3cd079", "spanId": "7b78d2bea411b2fe", "traceState": "", "parentSpanId": "0a9ab07c9f5e7d29", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:34.359002058Z", "endTime": "2021-04-20T20:33:34.361727904Z", "durationInNanos": 2725846, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-4", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 134, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57588, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "7145d5e8e15acfb7"}}
+{ "traceId": "c17023ed734d4daa5f97bb7972f0c935", "spanId": "7145d5e8e15acfb7", "traceState": "", "parentSpanId": "99d7b8673d19932d", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:34.745001766Z", "endTime": "2021-04-20T20:33:34.747694532Z", "durationInNanos": 2692766, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-6", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 136, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57598, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "474039eb574aec04"}}
+{ "traceId": "19b592faebd7e10a4824b919bcd3bd89", "spanId": "474039eb574aec04", "traceState": "", "parentSpanId": "ad7845eabc7145cd", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:36.157001583Z", "endTime": "2021-04-20T20:33:36.159234806Z", "durationInNanos": 2233223, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-3", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 133, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57638, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "77243c434c2fcb1f"}}
+{ "traceId": "cb077f0c195ce825befded0fb71c76f1", "spanId": "77243c434c2fcb1f", "traceState": "", "parentSpanId": "937fb8345b252adb", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:36.617002014Z", "endTime": "2021-04-20T20:33:36.619561838Z", "durationInNanos": 2559824, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-4", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 134, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57658, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "fd955727cb8de558"}}
+{ "traceId": "22bdfd493901782340e7eea9e077acb9", "spanId": "fd955727cb8de558", "traceState": "", "parentSpanId": "f211085459dee231", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:38.284002091Z", "endTime": "2021-04-20T20:33:38.286466012Z", "durationInNanos": 2463921, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-4", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 134, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57720, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "c1e60aa906af446c"}}
+{ "traceId": "22bdfd493901782340e7eea9e077acb9", "spanId": "c1e60aa906af446c", "traceState": "", "parentSpanId": "c5280d05b1704e38", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:38.302001808Z", "endTime": "2021-04-20T20:33:38.303866754Z", "durationInNanos": 1864946, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-6", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 136, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57722, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "f251b6b23136a553"}}
+{ "traceId": "82c7cf3d3540450a3acc00c41b7a9562", "spanId": "f251b6b23136a553", "traceState": "", "parentSpanId": "76ac0909a315d25c", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:38.726001732Z", "endTime": "2021-04-20T20:33:38.728225906Z", "durationInNanos": 2224174, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-3", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 133, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57748, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "3746bae316ced457"}}
+{ "traceId": "17af7b8dee49e8258b8b5ab82dd0235a", "spanId": "3746bae316ced457", "traceState": "", "parentSpanId": "8eafdbb08ef33fac", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:39.773298688Z", "endTime": "2021-04-20T20:33:39.775022848Z", "durationInNanos": 1724160, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "SELECT * FROM User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "0afb5a2b1848c74b"}}
+{ "traceId": "17af7b8dee49e8258b8b5ab82dd0235a", "spanId": "0afb5a2b1848c74b", "traceState": "", "parentSpanId": "", "name": "client_delivery_status", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:39.747136Z", "endTime": "2021-04-20T20:33:39.807513856Z", "durationInNanos": 60377856, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_delivery_status", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "669d2b7892e6854c"}}
+{ "traceId": "10b1ec1196741c85609a43ce435cdece", "spanId": "669d2b7892e6854c", "traceState": "", "parentSpanId": "9253cd2f27e55a6f", "name": "clear_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:40.228339200Z", "endTime": "2021-04-20T20:33:40.299048192Z", "durationInNanos": 70708992, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "59443367c68e77d9"}}
+{ "traceId": "259a8226fae090c7dff75784fc8c7b17", "spanId": "59443367c68e77d9", "traceState": "", "parentSpanId": "c3bb9b0cacfb19ea", "name": "cart_sold", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:41.185568512Z", "endTime": "2021-04-20T20:33:41.234750208Z", "durationInNanos": 49181696, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "3d3423c981805776"}}
+{ "traceId": "259a8226fae090c7dff75784fc8c7b17", "spanId": "3d3423c981805776", "traceState": "", "parentSpanId": "a4ba523cda11d1d3", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:41.246229760Z", "endTime": "2021-04-20T20:33:41.251002880Z", "durationInNanos": 4773120, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "e3496923e8587b46"}}
+{ "traceId": "5bf7f62e1215df5526664ec45dd9ad63", "spanId": "e3496923e8587b46", "traceState": "", "parentSpanId": "6b60bf20aca25776", "name": "getCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:41.625234688Z", "endTime": "2021-04-20T20:33:41.654554624Z", "durationInNanos": 29319936, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "GET", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58576, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/get_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/get_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "18af310c32c71ea5"}}
+{ "traceId": "5bf7f62e1215df5526664ec45dd9ad63", "spanId": "18af310c32c71ea5", "traceState": "", "parentSpanId": "915cceedf89bd5f3", "name": "HTTP GET", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:41.619891200Z", "endTime": "2021-04-20T20:33:41.677285120Z", "durationInNanos": 57393920, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8088/get_order", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "GET", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "7a5994c2d61252d8"}}
+{ "traceId": "552aa3363bf275a248b131406edf735d", "spanId": "7a5994c2d61252d8", "traceState": "", "parentSpanId": "903ebe485e8ce58d", "name": "cartSold", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:42.001465600Z", "endTime": "2021-04-20T20:33:42.054217216Z", "durationInNanos": 52751616, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "DELETE", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58586, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/cart_sold", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/cart_sold", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "2786ea5cfba1d51c"}}
+{ "traceId": "552aa3363bf275a248b131406edf735d", "spanId": "2786ea5cfba1d51c", "traceState": "", "parentSpanId": "e8aeb63bfa118068", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:41.996101888Z", "endTime": "2021-04-20T20:33:42.080325120Z", "durationInNanos": 84223232, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8088/pay_order", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "694e40f773666591"}}
+{ "traceId": "52190817d7eb1b6d71e66cc9b0b14124", "spanId": "694e40f773666591", "traceState": "", "parentSpanId": "de34ef4183a4705b", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:42.522945280Z", "endTime": "2021-04-20T20:33:42.523687680Z", "durationInNanos": 742400, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'banana', 'Qty': 2}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "7cd34262856a4d72"}}
+{ "traceId": "52190817d7eb1b6d71e66cc9b0b14124", "spanId": "7cd34262856a4d72", "traceState": "", "parentSpanId": "d2b2b41a16075705", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:42.604768512Z", "endTime": "2021-04-20T20:33:42.605615360Z", "durationInNanos": 846848, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'apple', 'Qty': 1}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "5bd2b2161742dcd5"}}
+{ "traceId": "52190817d7eb1b6d71e66cc9b0b14124", "spanId": "5bd2b2161742dcd5", "traceState": "", "parentSpanId": "0791aa225a461844", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:42.623602688Z", "endTime": "2021-04-20T20:33:42.628299008Z", "durationInNanos": 4696320, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "4eaffcf10b0ddc1b"}}
+{ "traceId": "52190817d7eb1b6d71e66cc9b0b14124", "spanId": "4eaffcf10b0ddc1b", "traceState": "", "parentSpanId": "5204fe33a94fc5e5", "name": "payment", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:42.495094784Z", "endTime": "2021-04-20T20:33:42.651653888Z", "durationInNanos": 156559104, "serviceName": "payment", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8084, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "139782029922256", "resource.attributes.service@name": "payment", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 59848, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/checkout", "span.attributes.http@host": "localhost:8084", "span.attributes.http@target": "/checkout", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "9645c99068238c29"}}
+{ "traceId": "52190817d7eb1b6d71e66cc9b0b14124", "spanId": "9645c99068238c29", "traceState": "", "parentSpanId": "", "name": "client_checkout", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:42.492572416Z", "endTime": "2021-04-20T20:33:42.660122112Z", "durationInNanos": 167549696, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_checkout", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "080f360f30d5f04d"}}
+{ "traceId": "c5eabf09201ab4df116e1881d0756035", "spanId": "080f360f30d5f04d", "traceState": "", "parentSpanId": "01b11afabc7fdc7f", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:43.411759104Z", "endTime": "2021-04-20T20:33:43.413591296Z", "durationInNanos": 1832192, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "SELECT ItemId, TotalQty FROM User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "01b11afabc7fdc7f"}}
+{ "traceId": "c5eabf09201ab4df116e1881d0756035", "spanId": "01b11afabc7fdc7f", "traceState": "", "parentSpanId": "54419fc75e901eee", "name": "cart_empty", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:43.391958528Z", "endTime": "2021-04-20T20:33:43.440197888Z", "durationInNanos": 48239360, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "54419fc75e901eee"}}
+{ "traceId": "c5eabf09201ab4df116e1881d0756035", "spanId": "54419fc75e901eee", "traceState": "", "parentSpanId": "85fb245e31172689", "name": "cartEmpty", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:43.391038976Z", "endTime": "2021-04-20T20:33:43.443544064Z", "durationInNanos": 52505088, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "PUT", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58618, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/cart_empty", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/cart_empty", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "85fb245e31172689"}}
+{ "traceId": "c5eabf09201ab4df116e1881d0756035", "spanId": "85fb245e31172689", "traceState": "", "parentSpanId": "a0bed7d434593b60", "name": "HTTP PUT", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:43.388828416Z", "endTime": "2021-04-20T20:33:43.448487936Z", "durationInNanos": 59659520, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/cart_empty", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "PUT", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "36695d818f9b4e9a"}}
+{ "traceId": "c5eabf09201ab4df116e1881d0756035", "spanId": "36695d818f9b4e9a", "traceState": "", "parentSpanId": "5268497625ace4e0", "name": "clear_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:43.387825664Z", "endTime": "2021-04-20T20:33:43.460932608Z", "durationInNanos": 73106944, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "DELETE", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 60994, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/clear_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/clear_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "2bacaf900ae368c7"}}
+{ "traceId": "1ca5c1d52ca730f16872553cde6933c0", "spanId": "2bacaf900ae368c7", "traceState": "", "parentSpanId": "5d8912365e6688f3", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:43.845935616Z", "endTime": "2021-04-20T20:33:43.847112448Z", "durationInNanos": 1176832, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "SELECT ItemId, TotalQty FROM User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "cf38f810fff59bb3"}}
+{ "traceId": "1ca5c1d52ca730f16872553cde6933c0", "spanId": "cf38f810fff59bb3", "traceState": "", "parentSpanId": "5d8912365e6688f3", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:43.850872832Z", "endTime": "2021-04-20T20:33:43.871734272Z", "durationInNanos": 20861440, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "TRUNCATE TABLE User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "37628f7fdcf79dbb"}}
+{ "traceId": "17af7b8dee49e8258b8b5ab82dd0235a", "spanId": "37628f7fdcf79dbb", "traceState": "", "parentSpanId": "cf2a67c23dc23bab", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:39.791471041Z", "endTime": "2021-04-20T20:33:39.792596934Z", "durationInNanos": 1125893, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-8", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 138, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "dd0a9b2bcbdcdbb6"}}
+{ "traceId": "259a8226fae090c7dff75784fc8c7b17", "spanId": "dd0a9b2bcbdcdbb6", "traceState": "", "parentSpanId": "a981fd033e3a7491", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:41.248690371Z", "endTime": "2021-04-20T20:33:41.249957195Z", "durationInNanos": 1266824, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-4", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 134, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "3230880363166a80"}}
+{ "traceId": "52190817d7eb1b6d71e66cc9b0b14124", "spanId": "3230880363166a80", "traceState": "", "parentSpanId": "f405f62e61d4181f", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:42.643464807Z", "endTime": "2021-04-20T20:33:42.644564500Z", "durationInNanos": 1099693, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-3", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 133, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "1fbcd1691508fa92"}}
+{ "traceId": "56280de557e9fa891bb6289d2fd53c8d", "spanId": "1fbcd1691508fa92", "traceState": "", "parentSpanId": "c519a467435258a0", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:40.859001828Z", "endTime": "2021-04-20T20:33:40.860862299Z", "durationInNanos": 1860471, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-3", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 133, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57798, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "570073e77e68be9d"}}
+{ "traceId": "96db5f125cb54111f2a95d7419df8a15", "spanId": "570073e77e68be9d", "traceState": "", "parentSpanId": "72fd9aa427e26550", "name": "add_item_to_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:44.185529088Z", "endTime": "2021-04-20T20:33:44.218529024Z", "durationInNanos": 32999936, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "2311bcf70d68331c"}}
+{ "traceId": "96db5f125cb54111f2a95d7419df8a15", "spanId": "2311bcf70d68331c", "traceState": "", "parentSpanId": "c63088be2f211cf7", "name": "addItemToCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:44.277222400Z", "endTime": "2021-04-20T20:33:44.312690432Z", "durationInNanos": 35468032, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58648, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/add_item_to_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/add_item_to_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "885e54cf2034b9f4"}}
+{ "traceId": "96db5f125cb54111f2a95d7419df8a15", "spanId": "885e54cf2034b9f4", "traceState": "", "parentSpanId": "104a8f2719108aaf", "name": "update_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:44.181856512Z", "endTime": "2021-04-20T20:33:44.328167424Z", "durationInNanos": 146310912, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "104a8f2719108aaf"}}
+{ "traceId": "96db5f125cb54111f2a95d7419df8a15", "spanId": "104a8f2719108aaf", "traceState": "", "parentSpanId": "c85e5dec4106a06a", "name": "update_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:44.181052672Z", "endTime": "2021-04-20T20:33:44.330511104Z", "durationInNanos": 149458432, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 32782, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/update_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "504e26f11e5bb1ae"}}
+{ "traceId": "c0ef65e0d991727dbe26a071fd10e407", "spanId": "504e26f11e5bb1ae", "traceState": "", "parentSpanId": "0ee38170cee8fb5c", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:44.594721792Z", "endTime": "2021-04-20T20:33:44.599331328Z", "durationInNanos": 4609536, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "93047965b18da903"}}
+{ "traceId": "70a3f615a998b76cd973d87710572913", "spanId": "93047965b18da903", "traceState": "", "parentSpanId": "7359981596903c3f", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:44.966868736Z", "endTime": "2021-04-20T20:33:44.989101312Z", "durationInNanos": 22232576, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "TRUNCATE TABLE User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "9ca0bf86196899bc"}}
+{ "traceId": "70a3f615a998b76cd973d87710572913", "spanId": "9ca0bf86196899bc", "traceState": "", "parentSpanId": "ead17a7f0d4e34ed", "name": "pay_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:44.943505664Z", "endTime": "2021-04-20T20:33:45.011987456Z", "durationInNanos": 68481792, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "92e84113ddc59da5"}}
+{ "traceId": "02feb3a4f611abd81f2a53244d1278ae", "spanId": "92e84113ddc59da5", "traceState": "", "parentSpanId": "dcf70445f2a2cd40", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:45.654626048Z", "endTime": "2021-04-20T20:33:45.655334912Z", "durationInNanos": 708864, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'orange', 'Qty': '3'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "dcf70445f2a2cd40"}}
+{ "traceId": "02feb3a4f611abd81f2a53244d1278ae", "spanId": "dcf70445f2a2cd40", "traceState": "", "parentSpanId": "0c64ae315abfd656", "name": "add_item_to_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:45.634566144Z", "endTime": "2021-04-20T20:33:45.659138816Z", "durationInNanos": 24572672, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "0c64ae315abfd656"}}
+{ "traceId": "02feb3a4f611abd81f2a53244d1278ae", "spanId": "0c64ae315abfd656", "traceState": "", "parentSpanId": "cf25277706dc2439", "name": "addItemToCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:45.633674752Z", "endTime": "2021-04-20T20:33:45.662507776Z", "durationInNanos": 28833024, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58692, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/add_item_to_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/add_item_to_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "9bdbac7482af31f3"}}
+{ "traceId": "02feb3a4f611abd81f2a53244d1278ae", "spanId": "9bdbac7482af31f3", "traceState": "", "parentSpanId": "ded3687b9758bf59", "name": "update_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:45.584570112Z", "endTime": "2021-04-20T20:33:45.719764480Z", "durationInNanos": 135194368, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 32832, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/update_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "8e8e5e8bd88c11b5"}}
+{ "traceId": "97551ce4600c334d4ab8fb8725ac1e67", "spanId": "8e8e5e8bd88c11b5", "traceState": "", "parentSpanId": "69af53e3494bca1c", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:45.943921408Z", "endTime": "2021-04-20T20:33:45.965064192Z", "durationInNanos": 21142784, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "TRUNCATE TABLE User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "69af53e3494bca1c"}}
+{ "traceId": "97551ce4600c334d4ab8fb8725ac1e67", "spanId": "69af53e3494bca1c", "traceState": "", "parentSpanId": "3a025025e0a3b1fa", "name": "cart_empty", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:45.913632256Z", "endTime": "2021-04-20T20:33:45.968429568Z", "durationInNanos": 54797312, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "ea4bcbaf2a9a6fa3"}}
+{ "traceId": "97551ce4600c334d4ab8fb8725ac1e67", "spanId": "ea4bcbaf2a9a6fa3", "traceState": "", "parentSpanId": "", "name": "client_cancel_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:45.907184128Z", "endTime": "2021-04-20T20:33:45.997188352Z", "durationInNanos": 90004224, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_cancel_order", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "5edd047783ce31e6"}}
+{ "traceId": "b450e7770b6bf942d91f238f77311fbe", "spanId": "5edd047783ce31e6", "traceState": "", "parentSpanId": "9a880188bcb44cda", "name": "updateItem", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:46.196210944Z", "endTime": "2021-04-20T20:33:46.228526592Z", "durationInNanos": 32315648, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "Not enough storage for itemId orange", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 2, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58722, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_item", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/update_item", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 422 }
+{ "index":{"_id": "6f7eafee7d68115c"}}
+{ "traceId": "b450e7770b6bf942d91f238f77311fbe", "spanId": "6f7eafee7d68115c", "traceState": "", "parentSpanId": "203faf4d95696dc4", "name": "update_item", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:46.240107008Z", "endTime": "2021-04-20T20:33:46.267194368Z", "durationInNanos": 27087360, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "22b1d496a103d5d4"}}
+{ "traceId": "b450e7770b6bf942d91f238f77311fbe", "spanId": "22b1d496a103d5d4", "traceState": "", "parentSpanId": "30652f6f8b511470", "name": "update_inventory", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:46.151774720Z", "endTime": "2021-04-20T20:33:46.278444288Z", "durationInNanos": 126669568, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "e270a32c23bb3d64"}}
+{ "traceId": "ba5a69d5dfd1eaa4077451d452ba473b", "spanId": "e270a32c23bb3d64", "traceState": "", "parentSpanId": "b9eb99e7f12a273f", "name": "cart_empty", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:46.505004800Z", "endTime": "2021-04-20T20:33:46.555533056Z", "durationInNanos": 50528256, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "a3ff3a8683434406"}}
+{ "traceId": "95b27b5462c0dccc7e08126a25e64d3f", "spanId": "a3ff3a8683434406", "traceState": "", "parentSpanId": "c78ae9d1aa24d379", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:46.821765888Z", "endTime": "2021-04-20T20:33:46.822455808Z", "durationInNanos": 689920, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'apple', 'Qty': '1'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "63f9d7eb1b86d29a"}}
+{ "traceId": "95b27b5462c0dccc7e08126a25e64d3f", "spanId": "63f9d7eb1b86d29a", "traceState": "", "parentSpanId": "43dc7bc2e05bfa0f", "name": "addItemToCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:46.800928512Z", "endTime": "2021-04-20T20:33:46.835864064Z", "durationInNanos": 34935552, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58744, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/add_item_to_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/add_item_to_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "43dc7bc2e05bfa0f"}}
+{ "traceId": "95b27b5462c0dccc7e08126a25e64d3f", "spanId": "43dc7bc2e05bfa0f", "traceState": "", "parentSpanId": "51c0b6f4525f8ce7", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:46.798465280Z", "endTime": "2021-04-20T20:33:46.840932096Z", "durationInNanos": 42466816, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/add_item_to_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "fddac8b6501344bf"}}
+{ "traceId": "95b27b5462c0dccc7e08126a25e64d3f", "spanId": "fddac8b6501344bf", "traceState": "", "parentSpanId": "3b2b065511029f95", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:46.866892288Z", "endTime": "2021-04-20T20:33:46.867537408Z", "durationInNanos": 645120, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'orange', 'Qty': '3'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "759ba13f98ab3fc6"}}
+{ "traceId": "95b27b5462c0dccc7e08126a25e64d3f", "spanId": "759ba13f98ab3fc6", "traceState": "", "parentSpanId": "fa4a423fd5b1089d", "name": "addItemToCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:46.846178304Z", "endTime": "2021-04-20T20:33:46.874823424Z", "durationInNanos": 28645120, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58748, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/add_item_to_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/add_item_to_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "fa4a423fd5b1089d"}}
+{ "traceId": "95b27b5462c0dccc7e08126a25e64d3f", "spanId": "fa4a423fd5b1089d", "traceState": "", "parentSpanId": "51c0b6f4525f8ce7", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:46.843851264Z", "endTime": "2021-04-20T20:33:46.879571200Z", "durationInNanos": 35719936, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/add_item_to_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "f0aeb9700f457880"}}
+{ "traceId": "95b27b5462c0dccc7e08126a25e64d3f", "spanId": "f0aeb9700f457880", "traceState": "", "parentSpanId": "51c0b6f4525f8ce7", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:46.882574848Z", "endTime": "2021-04-20T20:33:46.918776576Z", "durationInNanos": 36201728, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/add_item_to_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "51c0b6f4525f8ce7"}}
+{ "traceId": "95b27b5462c0dccc7e08126a25e64d3f", "spanId": "51c0b6f4525f8ce7", "traceState": "", "parentSpanId": "46804b074d510e22", "name": "update_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:46.798070016Z", "endTime": "2021-04-20T20:33:46.929501952Z", "durationInNanos": 131431936, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "4fb9849a6b80b6f2"}}
+{ "traceId": "c0d5be4cfded4677b472caeb6dced6eb", "spanId": "4fb9849a6b80b6f2", "traceState": "", "parentSpanId": "8d4b7a48cb7ee8e9", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:47.263351552Z", "endTime": "2021-04-20T20:33:47.264209664Z", "durationInNanos": 858112, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'orange', 'Qty': 3}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "f78dbd14cda8862e"}}
+{ "traceId": "c0d5be4cfded4677b472caeb6dced6eb", "spanId": "f78dbd14cda8862e", "traceState": "", "parentSpanId": "b974c6840493462f", "name": "updateItem", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:47.230816768Z", "endTime": "2021-04-20T20:33:47.274358784Z", "durationInNanos": 43542016, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "Not enough storage for itemId orange", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 2, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58768, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_item", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/update_item", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 422 }
+{ "index":{"_id": "3e1ca23a1316a089"}}
+{ "traceId": "c0d5be4cfded4677b472caeb6dced6eb", "spanId": "3e1ca23a1316a089", "traceState": "", "parentSpanId": "9995da51cebe7887", "name": "update_inventory", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:47.188528128Z", "endTime": "2021-04-20T20:33:47.323207424Z", "durationInNanos": 134679296, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "35a5641a51a07620"}}
+{ "traceId": "c0d5be4cfded4677b472caeb6dced6eb", "spanId": "35a5641a51a07620", "traceState": "", "parentSpanId": "f707df9bafaf7974", "name": "payment", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:47.184227840Z", "endTime": "2021-04-20T20:33:47.335330816Z", "durationInNanos": 151102976, "serviceName": "payment", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8084, "span.attributes.http@status_text": "PARTIAL CONTENT", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "139782029922256", "resource.attributes.service@name": "payment", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 60014, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/checkout", "span.attributes.http@host": "localhost:8084", "span.attributes.http@target": "/checkout", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 206 }
+{ "index":{"_id": "5b03c5aa49169de7"}}
+{ "traceId": "e48a85b3dc34426059aa1347ea4171a5", "spanId": "5b03c5aa49169de7", "traceState": "", "parentSpanId": "153b191f5bba208f", "name": "clear_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:47.480588800Z", "endTime": "2021-04-20T20:33:47.490298112Z", "durationInNanos": 9709312, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "SERVICE UNAVAILABLE", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 2, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "DELETE", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 32926, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/clear_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/clear_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 503 }
+{ "index":{"_id": "a0333ab0c0fb425e"}}
+{ "traceId": "16f5176887289baa94c27f12604b5163", "spanId": "a0333ab0c0fb425e", "traceState": "", "parentSpanId": "e36a01c310db6537", "name": "addItemToCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:47.777365760Z", "endTime": "2021-04-20T20:33:47.806075648Z", "durationInNanos": 28709888, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58788, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/add_item_to_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/add_item_to_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "e36a01c310db6537"}}
+{ "traceId": "16f5176887289baa94c27f12604b5163", "spanId": "e36a01c310db6537", "traceState": "", "parentSpanId": "b7db1195f7777f37", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:47.775088640Z", "endTime": "2021-04-20T20:33:47.810972160Z", "durationInNanos": 35883520, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/add_item_to_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "246d5a128abc0323"}}
+{ "traceId": "16f5176887289baa94c27f12604b5163", "spanId": "246d5a128abc0323", "traceState": "", "parentSpanId": "0adbc627a3ff01db", "name": "add_item_to_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:47.856003328Z", "endTime": "2021-04-20T20:33:47.880837376Z", "durationInNanos": 24834048, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "b7db1195f7777f37"}}
+{ "traceId": "16f5176887289baa94c27f12604b5163", "spanId": "b7db1195f7777f37", "traceState": "", "parentSpanId": "48c5f132edd1dce1", "name": "update_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:47.774677248Z", "endTime": "2021-04-20T20:33:47.900943872Z", "durationInNanos": 126266624, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "8d13c5fb5cb910ab"}}
+{ "traceId": "16f5176887289baa94c27f12604b5163", "spanId": "8d13c5fb5cb910ab", "traceState": "", "parentSpanId": "ebfe1ad9b112ca2a", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:47.771634688Z", "endTime": "2021-04-20T20:33:47.907790080Z", "durationInNanos": 136155392, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8088/update_order", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "36362df397ac500d"}}
+{ "traceId": "2aa556a9a859155d7f578aacf259588f", "spanId": "36362df397ac500d", "traceState": "", "parentSpanId": "29749eb615c7cf76", "name": "HTTP GET", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:48.093012480Z", "endTime": "2021-04-20T20:33:48.128655104Z", "durationInNanos": 35642624, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/get_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "GET", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "29749eb615c7cf76"}}
+{ "traceId": "2aa556a9a859155d7f578aacf259588f", "spanId": "29749eb615c7cf76", "traceState": "", "parentSpanId": "9a8427df12be8522", "name": "get_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:48.092771840Z", "endTime": "2021-04-20T20:33:48.138572032Z", "durationInNanos": 45800192, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "60b801fae48abf9b"}}
+{ "traceId": "2aa556a9a859155d7f578aacf259588f", "spanId": "60b801fae48abf9b", "traceState": "", "parentSpanId": "3e916e70241c5f31", "name": "HTTP GET", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:48.089861120Z", "endTime": "2021-04-20T20:33:48.145265920Z", "durationInNanos": 55404800, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8088/get_order", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "GET", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "fc52a63dddb6c78e"}}
+{ "traceId": "a7e35e333fe32a4fa0448bf258fff8e9", "spanId": "fc52a63dddb6c78e", "traceState": "", "parentSpanId": "a7ef8140aea6adc9", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:48.767165440Z", "endTime": "2021-04-20T20:33:48.771305728Z", "durationInNanos": 4140288, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "a7ef8140aea6adc9"}}
+{ "traceId": "a7e35e333fe32a4fa0448bf258fff8e9", "spanId": "a7ef8140aea6adc9", "traceState": "", "parentSpanId": "f0839669f041b029", "name": "get_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:48.727941632Z", "endTime": "2021-04-20T20:33:48.774041600Z", "durationInNanos": 46099968, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "e038c5aba828ea58"}}
+{ "traceId": "25af475f804ec5edbfab9d1ba4018ce5", "spanId": "e038c5aba828ea58", "traceState": "", "parentSpanId": "658da2faba59acd9", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:49.023798016Z", "endTime": "2021-04-20T20:33:49.024448256Z", "durationInNanos": 650240, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'apple', 'Qty': '1'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "81de5d2c6aa0859e"}}
+{ "traceId": "25af475f804ec5edbfab9d1ba4018ce5", "spanId": "81de5d2c6aa0859e", "traceState": "", "parentSpanId": "0c1e1c234af592e4", "name": "addItemToCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:49.042136064Z", "endTime": "2021-04-20T20:33:49.071018496Z", "durationInNanos": 28882432, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58840, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/add_item_to_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/add_item_to_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "e25b39ceacb30b75"}}
+{ "traceId": "65e793c50b861f00c1534090639dd7c3", "spanId": "e25b39ceacb30b75", "traceState": "", "parentSpanId": "fec494ea1cd015e3", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:45.301444832Z", "endTime": "2021-04-20T20:33:45.302604111Z", "durationInNanos": 1159279, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-4", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 134, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "a1339d62f81ccd32"}}
+{ "traceId": "02feb3a4f611abd81f2a53244d1278ae", "spanId": "a1339d62f81ccd32", "traceState": "", "parentSpanId": "2ac8b4cda3c0f1f9", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:45.711423559Z", "endTime": "2021-04-20T20:33:45.712615012Z", "durationInNanos": 1191453, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-6", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 136, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "fdbb1f2f7b488e87"}}
+{ "traceId": "97551ce4600c334d4ab8fb8725ac1e67", "spanId": "fdbb1f2f7b488e87", "traceState": "", "parentSpanId": "75432a4e251c77c6", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:45.982518483Z", "endTime": "2021-04-20T20:33:45.983665774Z", "durationInNanos": 1147291, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-8", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 138, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "3ee4a8601f798b23"}}
+{ "traceId": "ecfe3ff116a31b4c5ec107289b615ff3", "spanId": "3ee4a8601f798b23", "traceState": "", "parentSpanId": "74dbc2be658b50d8", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:48.456438616Z", "endTime": "2021-04-20T20:33:48.457460497Z", "durationInNanos": 1021881, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-10", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 140, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "552e8512fb52ccb5"}}
+{ "traceId": "c0ef65e0d991727dbe26a071fd10e407", "spanId": "552e8512fb52ccb5", "traceState": "", "parentSpanId": "504e26f11e5bb1ae", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:44.596001537Z", "endTime": "2021-04-20T20:33:44.597771774Z", "durationInNanos": 1770237, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-10", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 140, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57902, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "11f0fc7fd6fc8ef7"}}
+{ "traceId": "2aa556a9a859155d7f578aacf259588f", "spanId": "11f0fc7fd6fc8ef7", "traceState": "", "parentSpanId": "b45e32302ccd4555", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:48.133001853Z", "endTime": "2021-04-20T20:33:48.134747430Z", "durationInNanos": 1745577, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-8", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 138, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58050, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "6436b12426e22058"}}
+{ "traceId": "a7e35e333fe32a4fa0448bf258fff8e9", "spanId": "6436b12426e22058", "traceState": "", "parentSpanId": "fc52a63dddb6c78e", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:48.769001550Z", "endTime": "2021-04-20T20:33:48.770509554Z", "durationInNanos": 1508004, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-3", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 133, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58070, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "be8803ab43db27ca"}}
+{ "traceId": "25af475f804ec5edbfab9d1ba4018ce5", "spanId": "be8803ab43db27ca", "traceState": "", "parentSpanId": "1ca472e346ee563d", "name": "add_item_to_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:49.084217344Z", "endTime": "2021-04-20T20:33:49.111971584Z", "durationInNanos": 27754240, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "27d4fe07134ea308"}}
+{ "traceId": "25af475f804ec5edbfab9d1ba4018ce5", "spanId": "27d4fe07134ea308", "traceState": "", "parentSpanId": "6de234553c12cdd0", "name": "update_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:48.999261952Z", "endTime": "2021-04-20T20:33:49.132644864Z", "durationInNanos": 133382912, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 32980, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/update_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "7ab01768aa773b1c"}}
+{ "traceId": "da0666d73c1645d392576e56619d8c6e", "spanId": "7ab01768aa773b1c", "traceState": "", "parentSpanId": "c7c175f4366ce130", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:49.318971392Z", "endTime": "2021-04-20T20:33:49.340009216Z", "durationInNanos": 21037824, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "TRUNCATE TABLE User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "1e69961f46e59586"}}
+{ "traceId": "da0666d73c1645d392576e56619d8c6e", "spanId": "1e69961f46e59586", "traceState": "", "parentSpanId": "73d85e6251f927f6", "name": "cartEmpty", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:49.288094720Z", "endTime": "2021-04-20T20:33:49.346589952Z", "durationInNanos": 58495232, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "PUT", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58854, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/cart_empty", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/cart_empty", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "a4790e6461fa0d5d"}}
+{ "traceId": "da0666d73c1645d392576e56619d8c6e", "spanId": "a4790e6461fa0d5d", "traceState": "", "parentSpanId": "8979ca2f03690516", "name": "clear_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:49.284838912Z", "endTime": "2021-04-20T20:33:49.364374528Z", "durationInNanos": 79535616, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "DELETE", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 32998, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/clear_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/clear_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "c4eb12c87b56bbaf"}}
+{ "traceId": "c1bd83b99e3992292daa0888489e618c", "spanId": "c4eb12c87b56bbaf", "traceState": "", "parentSpanId": "b7362733de8bfa9c", "name": "update_item", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:49.527205120Z", "endTime": "2021-04-20T20:33:49.551947008Z", "durationInNanos": 24741888, "serviceName": "database", "events": [ { "time": "2021-04-20T20:33:49.551908096Z", "name": "exception", "attributes": { "exception@message": "", "exception@type": "InvalidItemUpdate", "exception@stacktrace": """Traceback (most recent call last): File "/usr/lib/python3.6/site-packages/opentelemetry/sdk/trace/__init__.py", line 804, in use_span yield span File "databaseService.py", line 162, in updateItem raise InvalidItemUpdate("Not enough storage for itemId {}".format(data[ "ItemId" ])) InvalidItemUpdate """ }, "droppedAttributesCount": 0 } ], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "status.message": "InvalidItemUpdate: ", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 2, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "b7362733de8bfa9c"}}
+{ "traceId": "c1bd83b99e3992292daa0888489e618c", "spanId": "b7362733de8bfa9c", "traceState": "", "parentSpanId": "9be2ff98ca6d0261", "name": "updateItem", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:49.526326272Z", "endTime": "2021-04-20T20:33:49.556307200Z", "durationInNanos": 29980928, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "Not enough storage for itemId banana", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 2, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58866, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_item", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/update_item", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 422 }
+{ "index":{"_id": "9be2ff98ca6d0261"}}
+{ "traceId": "c1bd83b99e3992292daa0888489e618c", "spanId": "9be2ff98ca6d0261", "traceState": "", "parentSpanId": "28991f1d3a174ce4", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:49.523984384Z", "endTime": "2021-04-20T20:33:49.561157120Z", "durationInNanos": 37172736, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/update_item", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "Not enough storage for itemId banana", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "span.attributes.component": "http", "status.code": 2, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 422 }
+{ "index":{"_id": "bb41f245f32492e4"}}
+{ "traceId": "c1bd83b99e3992292daa0888489e618c", "spanId": "bb41f245f32492e4", "traceState": "", "parentSpanId": "6025c3c1f9ee5054", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:49.517226496Z", "endTime": "2021-04-20T20:33:49.661549056Z", "durationInNanos": 144322560, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8084/checkout", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "PARTIAL CONTENT", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 206 }
+{ "index":{"_id": "2c3fe2ecd7602e0b"}}
+{ "traceId": "7a3182e62d533fa1e0617f21f5681a37", "spanId": "2c3fe2ecd7602e0b", "traceState": "", "parentSpanId": "ecc02e73350ce790", "name": "cartEmpty", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:49.850896896Z", "endTime": "2021-04-20T20:33:49.902683392Z", "durationInNanos": 51786496, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "PUT", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58882, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/cart_empty", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/cart_empty", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "3b0e8b5888901f7b"}}
+{ "traceId": "7a3182e62d533fa1e0617f21f5681a37", "spanId": "3b0e8b5888901f7b", "traceState": "", "parentSpanId": "de9f1128bf12b7b9", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:49.910390784Z", "endTime": "2021-04-20T20:33:49.915180544Z", "durationInNanos": 4789760, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "c6621138316a73b8"}}
+{ "traceId": "247d610dcbd05da1c7902081b6bec1f6", "spanId": "c6621138316a73b8", "traceState": "", "parentSpanId": "6f5a1a55f4c950f0", "name": "addItemToCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:50.221707008Z", "endTime": "2021-04-20T20:33:50.250929920Z", "durationInNanos": 29222912, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58900, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/add_item_to_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/add_item_to_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "6f5a1a55f4c950f0"}}
+{ "traceId": "247d610dcbd05da1c7902081b6bec1f6", "spanId": "6f5a1a55f4c950f0", "traceState": "", "parentSpanId": "d18bdbb97967e206", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:50.219329024Z", "endTime": "2021-04-20T20:33:50.255876352Z", "durationInNanos": 36547328, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/add_item_to_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "d18bdbb97967e206"}}
+{ "traceId": "247d610dcbd05da1c7902081b6bec1f6", "spanId": "d18bdbb97967e206", "traceState": "", "parentSpanId": "3b639def2d6ec40f", "name": "update_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:50.141257984Z", "endTime": "2021-04-20T20:33:50.267165184Z", "durationInNanos": 125907200, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "6a539e36635daed1"}}
+{ "traceId": "eef4554373e188267b38928e2dabeab4", "spanId": "6a539e36635daed1", "traceState": "", "parentSpanId": "13bed71d66dcc038", "name": "getCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:50.480547328Z", "endTime": "2021-04-20T20:33:50.509742080Z", "durationInNanos": 29194752, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "GET", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58912, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/get_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/get_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "e282094546b98e61"}}
+{ "traceId": "eef4554373e188267b38928e2dabeab4", "spanId": "e282094546b98e61", "traceState": "", "parentSpanId": "3a565f7129913c17", "name": "get_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:50.477368832Z", "endTime": "2021-04-20T20:33:50.527277568Z", "durationInNanos": 49908736, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "GET", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 33056, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/get_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/get_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "c80dc4c948d060d2"}}
+{ "traceId": "20eabd650f3a068d9f590786f56885e7", "spanId": "c80dc4c948d060d2", "traceState": "", "parentSpanId": "7e0f8516534902ba", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:50.727715584Z", "endTime": "2021-04-20T20:33:50.764667904Z", "durationInNanos": 36952320, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/add_item_to_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "e6af061aa53f5621"}}
+{ "traceId": "20eabd650f3a068d9f590786f56885e7", "spanId": "e6af061aa53f5621", "traceState": "", "parentSpanId": "ecc0e3f8be5250dd", "name": "add_item_to_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:50.812071936Z", "endTime": "2021-04-20T20:33:50.836778496Z", "durationInNanos": 24706560, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "268c00835c4cc7ac"}}
+{ "traceId": "20eabd650f3a068d9f590786f56885e7", "spanId": "268c00835c4cc7ac", "traceState": "", "parentSpanId": "7e0f8516534902ba", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:50.848304640Z", "endTime": "2021-04-20T20:33:50.852795392Z", "durationInNanos": 4490752, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "aaa75101bed92d1a"}}
+{ "traceId": "c48260d3774d6c2d4ba77c9e813eadec", "spanId": "aaa75101bed92d1a", "traceState": "", "parentSpanId": "e9893407bba95bf0", "name": "getCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:51.138495232Z", "endTime": "2021-04-20T20:33:51.166544384Z", "durationInNanos": 28049152, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "GET", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58940, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/get_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/get_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "bf2482df930950bb"}}
+{ "traceId": "c48260d3774d6c2d4ba77c9e813eadec", "spanId": "bf2482df930950bb", "traceState": "", "parentSpanId": "0068b98ffc99f9ea", "name": "get_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:51.135342336Z", "endTime": "2021-04-20T20:33:51.183588864Z", "durationInNanos": 48246528, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "GET", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 33084, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/get_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/get_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "93330439f7f89167"}}
+{ "traceId": "7f63958e2172b12500e40eed557a31c7", "spanId": "93330439f7f89167", "traceState": "", "parentSpanId": "9b81a0201a53b84c", "name": "get_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:51.683300864Z", "endTime": "2021-04-20T20:33:51.708692992Z", "durationInNanos": 25392128, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "a9ed253bbf36e70e"}}
+{ "traceId": "340a6c6f70a21d1bc8456dbbe5c79929", "spanId": "a9ed253bbf36e70e", "traceState": "", "parentSpanId": "a5a0c83096c8fa20", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:52.016589056Z", "endTime": "2021-04-20T20:33:52.017283328Z", "durationInNanos": 694272, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'orange', 'Qty': '3'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "6576e80159aee6b8"}}
+{ "traceId": "340a6c6f70a21d1bc8456dbbe5c79929", "spanId": "6576e80159aee6b8", "traceState": "", "parentSpanId": "71e8453fb0ed5faf", "name": "update_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:51.953919744Z", "endTime": "2021-04-20T20:33:52.078983680Z", "durationInNanos": 125063936, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "f8aedbcbab807a78"}}
+{ "traceId": "261f4f9f6d49c04588ddfc0b22d167c6", "spanId": "f8aedbcbab807a78", "traceState": "", "parentSpanId": "ed7415d8c9c25969", "name": "clear_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:52.207869440Z", "endTime": "2021-04-20T20:33:52.278209280Z", "durationInNanos": 70339840, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "ed7415d8c9c25969"}}
+{ "traceId": "261f4f9f6d49c04588ddfc0b22d167c6", "spanId": "ed7415d8c9c25969", "traceState": "", "parentSpanId": "0db04213ba31cb79", "name": "clear_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:52.207073792Z", "endTime": "2021-04-20T20:33:52.280379136Z", "durationInNanos": 73305344, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "DELETE", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 33132, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/clear_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/clear_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "702250f453a02be6"}}
+{ "traceId": "5be8370207cbb002a165d369fbc57b57", "spanId": "702250f453a02be6", "traceState": "", "parentSpanId": "4acae5e4234f52f8", "name": "update_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:52.496930560Z", "endTime": "2021-04-20T20:33:52.623046656Z", "durationInNanos": 126116096, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "84584d9e50950ea5"}}
+{ "traceId": "4216a647a4396e50fc12cc78d571557e", "spanId": "84584d9e50950ea5", "traceState": "", "parentSpanId": "d85ef60c6b05ea1e", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:52.815784192Z", "endTime": "2021-04-20T20:33:52.820143872Z", "durationInNanos": 4359680, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "e0514a47c90c0ead"}}
+{ "traceId": "4216a647a4396e50fc12cc78d571557e", "spanId": "e0514a47c90c0ead", "traceState": "", "parentSpanId": "d620278613ba1273", "name": "update_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:52.674479616Z", "endTime": "2021-04-20T20:33:52.825445632Z", "durationInNanos": 150966016, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 33160, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/update_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "dfd4cc33b9f49d74"}}
+{ "traceId": "4216a647a4396e50fc12cc78d571557e", "spanId": "dfd4cc33b9f49d74", "traceState": "", "parentSpanId": "", "name": "client_create_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:52.672014080Z", "endTime": "2021-04-20T20:33:52.833018624Z", "durationInNanos": 161004544, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_create_order", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "84e395f144998c01"}}
+{ "traceId": "e447ed617aa651a7593c720d7e976625", "spanId": "84e395f144998c01", "traceState": "", "parentSpanId": "b6b76ad0ea7a18e0", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:52.949800192Z", "endTime": "2021-04-20T20:33:52.951031040Z", "durationInNanos": 1230848, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "SELECT ItemId, TotalQty FROM User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "7e35a93ae1f1d3dc"}}
+{ "traceId": "e447ed617aa651a7593c720d7e976625", "spanId": "7e35a93ae1f1d3dc", "traceState": "", "parentSpanId": "a77612b8a846894a", "name": "clear_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:52.926126336Z", "endTime": "2021-04-20T20:33:53.003924224Z", "durationInNanos": 77797888, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "DELETE", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 33178, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/clear_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/clear_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "a77612b8a846894a"}}
+{ "traceId": "e447ed617aa651a7593c720d7e976625", "spanId": "a77612b8a846894a", "traceState": "", "parentSpanId": "36bf8ffe6bfab949", "name": "HTTP DELETE", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:52.923979776Z", "endTime": "2021-04-20T20:33:53.008655360Z", "durationInNanos": 84675584, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8088/clear_order", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "DELETE", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "36bf8ffe6bfab949"}}
+{ "traceId": "e447ed617aa651a7593c720d7e976625", "spanId": "36bf8ffe6bfab949", "traceState": "", "parentSpanId": "", "name": "client_cancel_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:52.923733504Z", "endTime": "2021-04-20T20:33:53.011512832Z", "durationInNanos": 87779328, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_cancel_order", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "057ca06095200357"}}
+{ "traceId": "0bda4f69a15675f56069fa7b677f1c74", "spanId": "057ca06095200357", "traceState": "", "parentSpanId": "ab2cfda3f66cd29a", "name": "updateItem", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:53.258444032Z", "endTime": "2021-04-20T20:33:53.288954112Z", "durationInNanos": 30510080, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "Not enough storage for itemId orange", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 2, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 59050, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_item", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/update_item", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 422 }
+{ "index":{"_id": "66a2144a58008463"}}
+{ "traceId": "0bda4f69a15675f56069fa7b677f1c74", "spanId": "66a2144a58008463", "traceState": "", "parentSpanId": "79e7e8f4a6b9cfd6", "name": "checkout", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:53.211445504Z", "endTime": "2021-04-20T20:33:53.348402432Z", "durationInNanos": 136956928, "serviceName": "payment", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "139782029922256", "resource.attributes.service@name": "payment", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "7c1551bf8ecff1e9"}}
+{ "traceId": "d5bc99166e521eec173bcb7f9b0d3c43", "spanId": "7c1551bf8ecff1e9", "traceState": "", "parentSpanId": "1baf1e42d2eaae2a", "name": "cartEmpty", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:53.432177920Z", "endTime": "2021-04-20T20:33:53.488074240Z", "durationInNanos": 55896320, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "PUT", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 59064, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/cart_empty", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/cart_empty", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "d074c89b98685510"}}
+{ "traceId": "7a3182e62d533fa1e0617f21f5681a37", "spanId": "d074c89b98685510", "traceState": "", "parentSpanId": "7b337ab41060959b", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:49.912560857Z", "endTime": "2021-04-20T20:33:49.913841981Z", "durationInNanos": 1281124, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-8", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 138, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "8d1a3be816dc5afe"}}
+{ "traceId": "340a6c6f70a21d1bc8456dbbe5c79929", "spanId": "8d1a3be816dc5afe", "traceState": "", "parentSpanId": "391c448e02ace429", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:52.073446568Z", "endTime": "2021-04-20T20:33:52.074477704Z", "durationInNanos": 1031136, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-3", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 133, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "92b74f59ddd54783"}}
+{ "traceId": "588f0d3438674277899b1f0bf2f2ebf2", "spanId": "92b74f59ddd54783", "traceState": "", "parentSpanId": "", "name": "mysql", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:15.007993856Z", "endTime": "2021-04-20T20:33:15.024957696Z", "durationInNanos": 16963840, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "mysql", "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "", "span.attributes.db@statement": "CREATE TABLE `User_Carts` ( `ItemId` varchar(16) NOT NULL, `TotalQty` int(11) NOT NULL, PRIMARY KEY (`ItemId`)) ENGINE=InnoDB", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "25af21b469c032b3"}}
+{ "traceId": "64398afff83d4ce40feb342b493d03cf", "spanId": "25af21b469c032b3", "traceState": "", "parentSpanId": "", "name": "HTTP GET", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:17.441215232Z", "endTime": "2021-04-20T20:33:17.444359680Z", "durationInNanos": 3144448, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "HTTP GET", "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8082, "span.attributes.http@status_text": "NOT FOUND", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "span.attributes.component": "http", "status.code": 2, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "GET", "span.attributes.http@user_agent": "curl/7.61.1", "span.attributes.net@peer@port": 47996, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@host": "localhost:8082", "span.attributes.http@target": "/", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 404 }
+{ "index":{"_id": "6c89443d5e23abf3"}}
+{ "traceId": "df5948afbb8aa0bdd587a5b81d7589da", "spanId": "6c89443d5e23abf3", "traceState": "", "parentSpanId": "c9ffe4c0af278e39", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:28.392941824Z", "endTime": "2021-04-20T20:33:28.467089152Z", "durationInNanos": 74147328, "serviceName": "authentication", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "139949516139040", "resource.attributes.service@name": "authentication", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "96e7fdedd82ab53c"}}
+{ "traceId": "d37d709d5695f213e4ca41ac874c00bc", "spanId": "96e7fdedd82ab53c", "traceState": "", "parentSpanId": "2c122c9d8977d38d", "name": "verify_login", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:32.542609152Z", "endTime": "2021-04-20T20:33:32.542644224Z", "durationInNanos": 35072, "serviceName": "authentication", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "139949516139040", "resource.attributes.service@name": "authentication", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "71869e6acbd9b84e"}}
+{ "traceId": "d37d709d5695f213e4ca41ac874c00bc", "spanId": "71869e6acbd9b84e", "traceState": "", "parentSpanId": "6921db03f367dc79", "name": "HTTP GET", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:32.548511744Z", "endTime": "2021-04-20T20:33:32.614019584Z", "durationInNanos": 65507840, "serviceName": "recommendation", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8082/read_inventory", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140018306314192", "resource.attributes.service@name": "recommendation", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "GET", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "39d9f21d9865f9e6"}}
+{ "traceId": "d37d709d5695f213e4ca41ac874c00bc", "spanId": "39d9f21d9865f9e6", "traceState": "", "parentSpanId": "", "name": "load_main_screen", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:32.538752Z", "endTime": "2021-04-20T20:33:32.652837376Z", "durationInNanos": 114085376, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "load_main_screen", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "2a1b45c16eaad09c"}}
+{ "traceId": "a80cb852f0c27762cfa923836bc5fe88", "spanId": "2a1b45c16eaad09c", "traceState": "", "parentSpanId": "9ba40f97c2ae86a7", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:33.447434240Z", "endTime": "2021-04-20T20:33:33.454592512Z", "durationInNanos": 7158272, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "9ba40f97c2ae86a7"}}
+{ "traceId": "a80cb852f0c27762cfa923836bc5fe88", "spanId": "9ba40f97c2ae86a7", "traceState": "", "parentSpanId": "daf5a14650228970", "name": "clear_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:33.446325504Z", "endTime": "2021-04-20T20:33:33.457898240Z", "durationInNanos": 11572736, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "SERVICE UNAVAILABLE", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 2, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "DELETE", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 60706, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/clear_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/clear_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 503 }
+{ "index":{"_id": "84fe46385d17b02c"}}
+{ "traceId": "d37d709d5695f213e4ca41ac874c00bc", "spanId": "84fe46385d17b02c", "traceState": "", "parentSpanId": "e1bc8cfc3ceb0aaf", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:32.601002072Z", "endTime": "2021-04-20T20:33:32.603410081Z", "durationInNanos": 2408009, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-6", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 136, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57560, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "2a5ae161952463e2"}}
+{ "traceId": "d37d709d5695f213e4ca41ac874c00bc", "spanId": "2a5ae161952463e2", "traceState": "", "parentSpanId": "ff013ccfd9d58cec", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:32.638002124Z", "endTime": "2021-04-20T20:33:32.640473313Z", "durationInNanos": 2471189, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-10", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 140, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57564, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "d4255abf68ac0402"}}
+{ "traceId": "509da2ddfc1a3d9fc88ed4b62f3cd079", "spanId": "d4255abf68ac0402", "traceState": "", "parentSpanId": "31a0c82890fa754b", "name": "add_item_to_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:34.222288128Z", "endTime": "2021-04-20T20:33:34.254911488Z", "durationInNanos": 32623360, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "be5b2f7a197c64cf"}}
+{ "traceId": "509da2ddfc1a3d9fc88ed4b62f3cd079", "spanId": "be5b2f7a197c64cf", "traceState": "", "parentSpanId": "97aa186489e038e0", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:34.219140864Z", "endTime": "2021-04-20T20:33:34.263220992Z", "durationInNanos": 44080128, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/add_item_to_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "e46a02e7b9ed8ecf"}}
+{ "traceId": "509da2ddfc1a3d9fc88ed4b62f3cd079", "spanId": "e46a02e7b9ed8ecf", "traceState": "", "parentSpanId": "c17b37664943c0a0", "name": "add_item_to_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:34.269251584Z", "endTime": "2021-04-20T20:33:34.300863232Z", "durationInNanos": 31611648, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "c17b37664943c0a0"}}
+{ "traceId": "509da2ddfc1a3d9fc88ed4b62f3cd079", "spanId": "c17b37664943c0a0", "traceState": "", "parentSpanId": "e5fd4823e84df1a0", "name": "addItemToCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:34.268306688Z", "endTime": "2021-04-20T20:33:34.304210944Z", "durationInNanos": 35904256, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58340, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/add_item_to_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/add_item_to_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "55d7f80c6aff4ec7"}}
+{ "traceId": "509da2ddfc1a3d9fc88ed4b62f3cd079", "spanId": "55d7f80c6aff4ec7", "traceState": "", "parentSpanId": "97aa186489e038e0", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:34.312219392Z", "endTime": "2021-04-20T20:33:34.354283520Z", "durationInNanos": 42064128, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/add_item_to_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "c0cb4dc5b7b1db59"}}
+{ "traceId": "9cc5c0acce9b9acc05b1c8d082709609", "spanId": "c0cb4dc5b7b1db59", "traceState": "", "parentSpanId": "16d6fb920c980921", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:35.231047680Z", "endTime": "2021-04-20T20:33:35.236322816Z", "durationInNanos": 5275136, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "6f3b8af3574d67d8"}}
+{ "traceId": "7df67f7205abe19319bad85babb04ca9", "spanId": "6f3b8af3574d67d8", "traceState": "", "parentSpanId": "d7d09b29635c42d0", "name": "add_item_to_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:35.667787520Z", "endTime": "2021-04-20T20:33:35.699713792Z", "durationInNanos": 31926272, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "1cfde34b0e64708d"}}
+{ "traceId": "7df67f7205abe19319bad85babb04ca9", "spanId": "1cfde34b0e64708d", "traceState": "", "parentSpanId": "16a087ca75a1c1ae", "name": "add_item_to_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:35.714154496Z", "endTime": "2021-04-20T20:33:35.744516352Z", "durationInNanos": 30361856, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "c607c3f259c8a65b"}}
+{ "traceId": "7df67f7205abe19319bad85babb04ca9", "spanId": "c607c3f259c8a65b", "traceState": "", "parentSpanId": "bb9e8ac613f9c314", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:35.778753792Z", "endTime": "2021-04-20T20:33:35.779580160Z", "durationInNanos": 826368, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'banana', 'Qty': '2'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "bb9e8ac613f9c314"}}
+{ "traceId": "7df67f7205abe19319bad85babb04ca9", "spanId": "bb9e8ac613f9c314", "traceState": "", "parentSpanId": "f756b2ab52d63952", "name": "add_item_to_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:35.758739968Z", "endTime": "2021-04-20T20:33:35.789022208Z", "durationInNanos": 30282240, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "f19d16050494663f"}}
+{ "traceId": "7df67f7205abe19319bad85babb04ca9", "spanId": "f19d16050494663f", "traceState": "", "parentSpanId": "7d7dc4421190f8f1", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:35.755664896Z", "endTime": "2021-04-20T20:33:35.797313792Z", "durationInNanos": 41648896, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/add_item_to_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "4d9ad162398612ca"}}
+{ "traceId": "19b592faebd7e10a4824b919bcd3bd89", "spanId": "4d9ad162398612ca", "traceState": "", "parentSpanId": "db173bc10299861f", "name": "HTTP PUT", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:36.071021056Z", "endTime": "2021-04-20T20:33:36.151107328Z", "durationInNanos": 80086272, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/cart_empty", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "PUT", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "de9f05334009f30f"}}
+{ "traceId": "19b592faebd7e10a4824b919bcd3bd89", "spanId": "de9f05334009f30f", "traceState": "", "parentSpanId": "9e8cf0411a1b61f8", "name": "clear_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:36.069997312Z", "endTime": "2021-04-20T20:33:36.166950656Z", "durationInNanos": 96953344, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "DELETE", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 60770, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/clear_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/clear_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "7aa2821664832544"}}
+{ "traceId": "cb077f0c195ce825befded0fb71c76f1", "spanId": "7aa2821664832544", "traceState": "", "parentSpanId": "bb004c0fd4fe0458", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:36.512588032Z", "endTime": "2021-04-20T20:33:36.513520384Z", "durationInNanos": 932352, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'banana', 'Qty': 2}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "b515153fd36d853a"}}
+{ "traceId": "cb077f0c195ce825befded0fb71c76f1", "spanId": "b515153fd36d853a", "traceState": "", "parentSpanId": "b5eb104616d427e5", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:36.489266944Z", "endTime": "2021-04-20T20:33:36.528014080Z", "durationInNanos": 38747136, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/update_item", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "41b5cf2346593387"}}
+{ "traceId": "cb077f0c195ce825befded0fb71c76f1", "spanId": "41b5cf2346593387", "traceState": "", "parentSpanId": "9835a28e768c1334", "name": "updateItem", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:36.533314304Z", "endTime": "2021-04-20T20:33:36.564330496Z", "durationInNanos": 31016192, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58410, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_item", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/update_item", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "937fb8345b252adb"}}
+{ "traceId": "cb077f0c195ce825befded0fb71c76f1", "spanId": "937fb8345b252adb", "traceState": "", "parentSpanId": "b5eb104616d427e5", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:36.614607616Z", "endTime": "2021-04-20T20:33:36.620131584Z", "durationInNanos": 5523968, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "b5eb104616d427e5"}}
+{ "traceId": "cb077f0c195ce825befded0fb71c76f1", "spanId": "b5eb104616d427e5", "traceState": "", "parentSpanId": "702b587891032394", "name": "update_inventory", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:36.488680960Z", "endTime": "2021-04-20T20:33:36.622967040Z", "durationInNanos": 134286080, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "702b587891032394"}}
+{ "traceId": "cb077f0c195ce825befded0fb71c76f1", "spanId": "702b587891032394", "traceState": "", "parentSpanId": "375cb3ef27c46997", "name": "update_inventory", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:36.487866112Z", "endTime": "2021-04-20T20:33:36.625204992Z", "durationInNanos": 137338880, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8082, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 48158, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_inventory", "span.attributes.http@host": "localhost:8082", "span.attributes.http@target": "/update_inventory", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "d3911d8b057539bb"}}
+{ "traceId": "cb077f0c195ce825befded0fb71c76f1", "spanId": "d3911d8b057539bb", "traceState": "", "parentSpanId": "", "name": "client_checkout", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:36.481575424Z", "endTime": "2021-04-20T20:33:36.650631936Z", "durationInNanos": 169056512, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_checkout", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "e71642d4deaf046a"}}
+{ "traceId": "ec830c13f81efb5082f6e40b4dedce71", "spanId": "e71642d4deaf046a", "traceState": "", "parentSpanId": "3d1fe27819634f95", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:37.024145664Z", "endTime": "2021-04-20T20:33:37.047470592Z", "durationInNanos": 23324928, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "TRUNCATE TABLE User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "c978b33c59a54196"}}
+{ "traceId": "ec830c13f81efb5082f6e40b4dedce71", "spanId": "c978b33c59a54196", "traceState": "", "parentSpanId": "a7fcdbe2bf6d6d75", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:37.062592256Z", "endTime": "2021-04-20T20:33:37.067854080Z", "durationInNanos": 5261824, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "a00565be802b54b4"}}
+{ "traceId": "1730cc8687cb4b504cd934560111d5a1", "spanId": "a00565be802b54b4", "traceState": "", "parentSpanId": "dfbc0ecddf9324b7", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:37.480550912Z", "endTime": "2021-04-20T20:33:37.481288960Z", "durationInNanos": 738048, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'orange', 'Qty': '3'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "INSERT INTO User_Carts (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "67e273104da42d94"}}
+{ "traceId": "1730cc8687cb4b504cd934560111d5a1", "spanId": "67e273104da42d94", "traceState": "", "parentSpanId": "e1f71dfda83b894c", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:37.527881984Z", "endTime": "2021-04-20T20:33:37.528583168Z", "durationInNanos": 701184, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'banana', 'Qty': '2'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "INSERT INTO User_Carts (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "965c5d8b0b6276c0"}}
+{ "traceId": "1730cc8687cb4b504cd934560111d5a1", "spanId": "965c5d8b0b6276c0", "traceState": "", "parentSpanId": "67a615bb3d2aef86", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:37.500228096Z", "endTime": "2021-04-20T20:33:37.541810176Z", "durationInNanos": 41582080, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/add_item_to_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "6bf6fc5237230c42"}}
+{ "traceId": "1730cc8687cb4b504cd934560111d5a1", "spanId": "6bf6fc5237230c42", "traceState": "", "parentSpanId": "1eda1c86b53778f8", "name": "update_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:37.404817152Z", "endTime": "2021-04-20T20:33:37.554722304Z", "durationInNanos": 149905152, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 60812, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/update_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "91921c51d51c884f"}}
+{ "traceId": "c9f83a98e8f1826c3a822eeb7b85a9d6", "spanId": "91921c51d51c884f", "traceState": "", "parentSpanId": "fa65816f2428a950", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:37.806868480Z", "endTime": "2021-04-20T20:33:37.807457792Z", "durationInNanos": 589312, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "SELECT ItemId, TotalQty FROM User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "8aa7fc60f5c7d6b9"}}
+{ "traceId": "c9f83a98e8f1826c3a822eeb7b85a9d6", "spanId": "8aa7fc60f5c7d6b9", "traceState": "", "parentSpanId": "fa65816f2428a950", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:37.810970624Z", "endTime": "2021-04-20T20:33:37.811611392Z", "durationInNanos": 640768, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'apple', 'Qty': 1}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "INSERT INTO Inventory_Items (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "6e1dcac7d59fac91"}}
+{ "traceId": "c9f83a98e8f1826c3a822eeb7b85a9d6", "spanId": "6e1dcac7d59fac91", "traceState": "", "parentSpanId": "fa65816f2428a950", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:37.823713280Z", "endTime": "2021-04-20T20:33:37.843032832Z", "durationInNanos": 19319552, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "TRUNCATE TABLE User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "921202e7eca9c5be"}}
+{ "traceId": "c9f83a98e8f1826c3a822eeb7b85a9d6", "spanId": "921202e7eca9c5be", "traceState": "", "parentSpanId": "3b8fd25db26f6336", "name": "HTTP PUT", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:37.784199936Z", "endTime": "2021-04-20T20:33:37.854919424Z", "durationInNanos": 70719488, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/cart_empty", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "PUT", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "d65f4119e3d35c6f"}}
+{ "traceId": "22bdfd493901782340e7eea9e077acb9", "spanId": "d65f4119e3d35c6f", "traceState": "", "parentSpanId": "b8440d5b592650f2", "name": "update_item", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:38.157860352Z", "endTime": "2021-04-20T20:33:38.185885952Z", "durationInNanos": 28025600, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "1b26c8058d3cd7b6"}}
+{ "traceId": "22bdfd493901782340e7eea9e077acb9", "spanId": "1b26c8058d3cd7b6", "traceState": "", "parentSpanId": "2fa45786a2e85af4", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:38.238149632Z", "endTime": "2021-04-20T20:33:38.277396480Z", "durationInNanos": 39246848, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/update_item", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "952b9f3e06ee5533"}}
+{ "traceId": "22bdfd493901782340e7eea9e077acb9", "spanId": "952b9f3e06ee5533", "traceState": "", "parentSpanId": "45ff7de69dace1d6", "name": "update_inventory", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:38.153484288Z", "endTime": "2021-04-20T20:33:38.292515584Z", "durationInNanos": 139031296, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8082, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 48218, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_inventory", "span.attributes.http@host": "localhost:8082", "span.attributes.http@target": "/update_inventory", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "45ff7de69dace1d6"}}
+{ "traceId": "22bdfd493901782340e7eea9e077acb9", "spanId": "45ff7de69dace1d6", "traceState": "", "parentSpanId": "67c3240b15bfc41a", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:38.151339520Z", "endTime": "2021-04-20T20:33:38.297237504Z", "durationInNanos": 145897984, "serviceName": "payment", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8082/update_inventory", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "139782029922256", "resource.attributes.service@name": "payment", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "03699d100410017f"}}
+{ "traceId": "82c7cf3d3540450a3acc00c41b7a9562", "spanId": "03699d100410017f", "traceState": "", "parentSpanId": "e65cbb55e80306bb", "name": "update_item", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:38.578456320Z", "endTime": "2021-04-20T20:33:38.605642496Z", "durationInNanos": 27186176, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "7d1c23fc87c00b35"}}
+{ "traceId": "82c7cf3d3540450a3acc00c41b7a9562", "spanId": "7d1c23fc87c00b35", "traceState": "", "parentSpanId": "d3449d96433ef65b", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:38.641069568Z", "endTime": "2021-04-20T20:33:38.641892096Z", "durationInNanos": 822528, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'orange', 'Qty': 3}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "07b4d48cb660e9cc"}}
+{ "traceId": "82c7cf3d3540450a3acc00c41b7a9562", "spanId": "07b4d48cb660e9cc", "traceState": "", "parentSpanId": "bde992160f31f631", "name": "payment", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:38.556106240Z", "endTime": "2021-04-20T20:33:38.737072384Z", "durationInNanos": 180966144, "serviceName": "payment", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8084, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "139782029922256", "resource.attributes.service@name": "payment", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 59740, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/checkout", "span.attributes.http@host": "localhost:8084", "span.attributes.http@target": "/checkout", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "9aa1509f5e191508"}}
+{ "traceId": "509da2ddfc1a3d9fc88ed4b62f3cd079", "spanId": "9aa1509f5e191508", "traceState": "", "parentSpanId": "7b78d2bea411b2fe", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:34.359700428Z", "endTime": "2021-04-20T20:33:34.361556108Z", "durationInNanos": 1855680, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-4", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 134, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "e1dfd31ab1a2b193"}}
+{ "traceId": "c17023ed734d4daa5f97bb7972f0c935", "spanId": "e1dfd31ab1a2b193", "traceState": "", "parentSpanId": "7145d5e8e15acfb7", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:34.745707353Z", "endTime": "2021-04-20T20:33:34.747566050Z", "durationInNanos": 1858697, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-6", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 136, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "2751e720b71a60a4"}}
+{ "traceId": "1730cc8687cb4b504cd934560111d5a1", "spanId": "2751e720b71a60a4", "traceState": "", "parentSpanId": "31f5aad7d2ea1fcb", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:37.547512262Z", "endTime": "2021-04-20T20:33:37.548630086Z", "durationInNanos": 1117824, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-10", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 140, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "4b7e5e41b0e7fd04"}}
+{ "traceId": "7df67f7205abe19319bad85babb04ca9", "spanId": "4b7e5e41b0e7fd04", "traceState": "", "parentSpanId": "d11da5c9c394bde8", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:35.802002385Z", "endTime": "2021-04-20T20:33:35.804283108Z", "durationInNanos": 2280723, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-10", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 140, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57628, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "74e54ea9fdbf735f"}}
+{ "traceId": "cb077f0c195ce825befded0fb71c76f1", "spanId": "74e54ea9fdbf735f", "traceState": "", "parentSpanId": "900fb4b6271869ab", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:36.635002138Z", "endTime": "2021-04-20T20:33:36.637319816Z", "durationInNanos": 2317678, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-6", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 136, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57660, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "75b7e359c49acf55"}}
+{ "traceId": "82c7cf3d3540450a3acc00c41b7a9562", "spanId": "75b7e359c49acf55", "traceState": "", "parentSpanId": "02d508caf899367c", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:38.562002009Z", "endTime": "2021-04-20T20:33:38.563741689Z", "durationInNanos": 1739680, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-8", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 138, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57730, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "e1300ec1802ecc3c"}}
+{ "traceId": "b23c2f42f054fd2e3bd6602318e609ed", "spanId": "e1300ec1802ecc3c", "traceState": "", "parentSpanId": "913de07418b7eed7", "name": "cart_empty", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:38.931558144Z", "endTime": "2021-04-20T20:33:38.984496640Z", "durationInNanos": 52938496, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "8c03b29267586319"}}
+{ "traceId": "b23c2f42f054fd2e3bd6602318e609ed", "spanId": "8c03b29267586319", "traceState": "", "parentSpanId": "a03543bce133747e", "name": "clear_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:38.927511808Z", "endTime": "2021-04-20T20:33:39.006228736Z", "durationInNanos": 78716928, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "f5fe5f65731875d1"}}
+{ "traceId": "a371f923b4967cb722e563725cc2a91d", "spanId": "f5fe5f65731875d1", "traceState": "", "parentSpanId": "3ed24d73086e3a5c", "name": "cartSold", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:39.432419840Z", "endTime": "2021-04-20T20:33:39.482711808Z", "durationInNanos": 50291968, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "DELETE", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58524, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/cart_sold", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/cart_sold", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "3ed24d73086e3a5c"}}
+{ "traceId": "a371f923b4967cb722e563725cc2a91d", "spanId": "3ed24d73086e3a5c", "traceState": "", "parentSpanId": "e2ca5dbb18427bbc", "name": "HTTP DELETE", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:39.430222336Z", "endTime": "2021-04-20T20:33:39.487606272Z", "durationInNanos": 57383936, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/cart_sold", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "DELETE", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "8eafdbb08ef33fac"}}
+{ "traceId": "17af7b8dee49e8258b8b5ab82dd0235a", "spanId": "8eafdbb08ef33fac", "traceState": "", "parentSpanId": "f69d6486408d5ceb", "name": "get_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:39.753607936Z", "endTime": "2021-04-20T20:33:39.778727168Z", "durationInNanos": 25119232, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "6f9b9156dc914a59"}}
+{ "traceId": "10b1ec1196741c85609a43ce435cdece", "spanId": "6f9b9156dc914a59", "traceState": "", "parentSpanId": "027e1f4686076d5e", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:40.251508736Z", "endTime": "2021-04-20T20:33:40.252164096Z", "durationInNanos": 655360, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "SELECT ItemId, TotalQty FROM User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "7052b8e18f95d355"}}
+{ "traceId": "10b1ec1196741c85609a43ce435cdece", "spanId": "7052b8e18f95d355", "traceState": "", "parentSpanId": "669d2b7892e6854c", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:40.291585280Z", "endTime": "2021-04-20T20:33:40.296150784Z", "durationInNanos": 4565504, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "9253cd2f27e55a6f"}}
+{ "traceId": "10b1ec1196741c85609a43ce435cdece", "spanId": "9253cd2f27e55a6f", "traceState": "", "parentSpanId": "517b250c6b019d50", "name": "clear_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:40.227543040Z", "endTime": "2021-04-20T20:33:40.301341184Z", "durationInNanos": 73798144, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "DELETE", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 60920, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/clear_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/clear_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "517b250c6b019d50"}}
+{ "traceId": "10b1ec1196741c85609a43ce435cdece", "spanId": "517b250c6b019d50", "traceState": "", "parentSpanId": "883dff4473fb6cb2", "name": "HTTP DELETE", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:40.225460992Z", "endTime": "2021-04-20T20:33:40.305951232Z", "durationInNanos": 80490240, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8088/clear_order", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "DELETE", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "883dff4473fb6cb2"}}
+{ "traceId": "10b1ec1196741c85609a43ce435cdece", "spanId": "883dff4473fb6cb2", "traceState": "", "parentSpanId": "", "name": "client_cancel_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:40.225210368Z", "endTime": "2021-04-20T20:33:40.308697600Z", "durationInNanos": 83487232, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_cancel_order", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "1bf5449206413fa6"}}
+{ "traceId": "56280de557e9fa891bb6289d2fd53c8d", "spanId": "1bf5449206413fa6", "traceState": "", "parentSpanId": "8ac46543c6308b05", "name": "pay_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:40.794464Z", "endTime": "2021-04-20T20:33:40.866789376Z", "durationInNanos": 72325376, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 60930, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/pay_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/pay_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "a4ba523cda11d1d3"}}
+{ "traceId": "259a8226fae090c7dff75784fc8c7b17", "spanId": "a4ba523cda11d1d3", "traceState": "", "parentSpanId": "d10b1e24cdce1630", "name": "pay_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:41.182262528Z", "endTime": "2021-04-20T20:33:41.253643520Z", "durationInNanos": 71380992, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "1c5f7bbfcfc2fd9c"}}
+{ "traceId": "259a8226fae090c7dff75784fc8c7b17", "spanId": "1c5f7bbfcfc2fd9c", "traceState": "", "parentSpanId": "", "name": "client_pay_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:41.179067136Z", "endTime": "2021-04-20T20:33:41.262793216Z", "durationInNanos": 83726080, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_pay_order", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "83033b37b8934e4d"}}
+{ "traceId": "5bf7f62e1215df5526664ec45dd9ad63", "spanId": "83033b37b8934e4d", "traceState": "", "parentSpanId": "74ac44c4e08e204b", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:41.646461440Z", "endTime": "2021-04-20T20:33:41.647615744Z", "durationInNanos": 1154304, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "SELECT * FROM User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "6b60bf20aca25776"}}
+{ "traceId": "5bf7f62e1215df5526664ec45dd9ad63", "spanId": "6b60bf20aca25776", "traceState": "", "parentSpanId": "7b17041367225c99", "name": "HTTP GET", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:41.623079680Z", "endTime": "2021-04-20T20:33:41.659422720Z", "durationInNanos": 36343040, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/get_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "GET", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "b88a8903d68855ac"}}
+{ "traceId": "5bf7f62e1215df5526664ec45dd9ad63", "spanId": "b88a8903d68855ac", "traceState": "", "parentSpanId": "7b17041367225c99", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:41.662379264Z", "endTime": "2021-04-20T20:33:41.667096576Z", "durationInNanos": 4717312, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "7b17041367225c99"}}
+{ "traceId": "5bf7f62e1215df5526664ec45dd9ad63", "spanId": "7b17041367225c99", "traceState": "", "parentSpanId": "1abf21fef72f18ff", "name": "get_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:41.622877440Z", "endTime": "2021-04-20T20:33:41.669995776Z", "durationInNanos": 47118336, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "1e0ea651a120db7b"}}
+{ "traceId": "52190817d7eb1b6d71e66cc9b0b14124", "spanId": "1e0ea651a120db7b", "traceState": "", "parentSpanId": "46c91104e47a2a43", "name": "updateItem", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:42.501964032Z", "endTime": "2021-04-20T20:33:42.533108224Z", "durationInNanos": 31144192, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58598, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_item", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/update_item", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "46c91104e47a2a43"}}
+{ "traceId": "52190817d7eb1b6d71e66cc9b0b14124", "spanId": "46c91104e47a2a43", "traceState": "", "parentSpanId": "0791aa225a461844", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:42.499654144Z", "endTime": "2021-04-20T20:33:42.538212352Z", "durationInNanos": 38558208, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/update_item", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "b1622ef608acbe07"}}
+{ "traceId": "52190817d7eb1b6d71e66cc9b0b14124", "spanId": "b1622ef608acbe07", "traceState": "", "parentSpanId": "0c5d67b81c5daaa1", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:42.564037120Z", "endTime": "2021-04-20T20:33:42.564826880Z", "durationInNanos": 789760, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'orange', 'Qty': 3}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "48ab22a6aa9ead3d"}}
+{ "traceId": "52190817d7eb1b6d71e66cc9b0b14124", "spanId": "48ab22a6aa9ead3d", "traceState": "", "parentSpanId": "0791aa225a461844", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:42.581447424Z", "endTime": "2021-04-20T20:33:42.620536064Z", "durationInNanos": 39088640, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/update_item", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "0791aa225a461844"}}
+{ "traceId": "52190817d7eb1b6d71e66cc9b0b14124", "spanId": "0791aa225a461844", "traceState": "", "parentSpanId": "dd10a56f977e819c", "name": "update_inventory", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:42.499253760Z", "endTime": "2021-04-20T20:33:42.631327232Z", "durationInNanos": 132073472, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "dd10a56f977e819c"}}
+{ "traceId": "52190817d7eb1b6d71e66cc9b0b14124", "spanId": "dd10a56f977e819c", "traceState": "", "parentSpanId": "868f60191f3524c9", "name": "update_inventory", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:42.498470144Z", "endTime": "2021-04-20T20:33:42.633447680Z", "durationInNanos": 134977536, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8082, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 48350, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_inventory", "span.attributes.http@host": "localhost:8082", "span.attributes.http@target": "/update_inventory", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "3121ff83a994e9da"}}
+{ "traceId": "52190817d7eb1b6d71e66cc9b0b14124", "spanId": "3121ff83a994e9da", "traceState": "", "parentSpanId": "007459ff1ddd5dfb", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:42.640867584Z", "endTime": "2021-04-20T20:33:42.645658112Z", "durationInNanos": 4790528, "serviceName": "payment", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "139782029922256", "resource.attributes.service@name": "payment", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "007459ff1ddd5dfb"}}
+{ "traceId": "52190817d7eb1b6d71e66cc9b0b14124", "spanId": "007459ff1ddd5dfb", "traceState": "", "parentSpanId": "4eaffcf10b0ddc1b", "name": "checkout", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:42.495881472Z", "endTime": "2021-04-20T20:33:42.649110784Z", "durationInNanos": 153229312, "serviceName": "payment", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "139782029922256", "resource.attributes.service@name": "payment", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "11538c0100bd4160"}}
+{ "traceId": "c5eabf09201ab4df116e1881d0756035", "spanId": "11538c0100bd4160", "traceState": "", "parentSpanId": "a0bed7d434593b60", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:43.451381504Z", "endTime": "2021-04-20T20:33:43.455993600Z", "durationInNanos": 4612096, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "a0bed7d434593b60"}}
+{ "traceId": "c5eabf09201ab4df116e1881d0756035", "spanId": "a0bed7d434593b60", "traceState": "", "parentSpanId": "36695d818f9b4e9a", "name": "clear_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:43.388621312Z", "endTime": "2021-04-20T20:33:43.458705664Z", "durationInNanos": 70084352, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "5268497625ace4e0"}}
+{ "traceId": "c5eabf09201ab4df116e1881d0756035", "spanId": "5268497625ace4e0", "traceState": "", "parentSpanId": "5e7bc4f9aae01a8f", "name": "HTTP DELETE", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:43.385700864Z", "endTime": "2021-04-20T20:33:43.466258432Z", "durationInNanos": 80557568, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8088/clear_order", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "DELETE", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "e272f67b8738c361"}}
+{ "traceId": "1ca5c1d52ca730f16872553cde6933c0", "spanId": "e272f67b8738c361", "traceState": "", "parentSpanId": "f9e3a2177bd81a72", "name": "cartEmpty", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:43.825311744Z", "endTime": "2021-04-20T20:33:43.878611712Z", "durationInNanos": 53299968, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "PUT", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58628, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/cart_empty", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/cart_empty", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "c173a5ab72d12cca"}}
+{ "traceId": "5bf7f62e1215df5526664ec45dd9ad63", "spanId": "c173a5ab72d12cca", "traceState": "", "parentSpanId": "4dc028a0167c3cf2", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:41.664562550Z", "endTime": "2021-04-20T20:33:41.665701036Z", "durationInNanos": 1138486, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-6", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 136, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "1d6646d320f46f92"}}
+{ "traceId": "1ca5c1d52ca730f16872553cde6933c0", "spanId": "1d6646d320f46f92", "traceState": "", "parentSpanId": "7d14b353b41504e2", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:43.888482916Z", "endTime": "2021-04-20T20:33:43.889715232Z", "durationInNanos": 1232316, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-6", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 136, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "cf2a67c23dc23bab"}}
+{ "traceId": "17af7b8dee49e8258b8b5ab82dd0235a", "spanId": "cf2a67c23dc23bab", "traceState": "", "parentSpanId": "652bc8d3182b25df", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:39.791001724Z", "endTime": "2021-04-20T20:33:39.792709638Z", "durationInNanos": 1707914, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-8", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 138, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57778, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "f405f62e61d4181f"}}
+{ "traceId": "52190817d7eb1b6d71e66cc9b0b14124", "spanId": "f405f62e61d4181f", "traceState": "", "parentSpanId": "3121ff83a994e9da", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:42.643002265Z", "endTime": "2021-04-20T20:33:42.644751821Z", "durationInNanos": 1749556, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-3", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 133, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57852, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "87af24ccbde5bc6b"}}
+{ "traceId": "c5eabf09201ab4df116e1881d0756035", "spanId": "87af24ccbde5bc6b", "traceState": "", "parentSpanId": "11538c0100bd4160", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:43.453001888Z", "endTime": "2021-04-20T20:33:43.454676059Z", "durationInNanos": 1674171, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-4", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 134, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57862, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "4a2d7a09233223ec"}}
+{ "traceId": "96db5f125cb54111f2a95d7419df8a15", "spanId": "4a2d7a09233223ec", "traceState": "", "parentSpanId": "570073e77e68be9d", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:44.206169856Z", "endTime": "2021-04-20T20:33:44.206994688Z", "durationInNanos": 824832, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'apple', 'Qty': '1'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "c1ae726e0fb621b3"}}
+{ "traceId": "96db5f125cb54111f2a95d7419df8a15", "spanId": "c1ae726e0fb621b3", "traceState": "", "parentSpanId": "24d81987a47f33dc", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:44.252928256Z", "endTime": "2021-04-20T20:33:44.253720576Z", "durationInNanos": 792320, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'orange', 'Qty': '3'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "d87a0a46511625fb"}}
+{ "traceId": "96db5f125cb54111f2a95d7419df8a15", "spanId": "d87a0a46511625fb", "traceState": "", "parentSpanId": "7696d367503845f7", "name": "addItemToCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:44.232229376Z", "endTime": "2021-04-20T20:33:44.266917888Z", "durationInNanos": 34688512, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58642, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/add_item_to_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/add_item_to_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "7696d367503845f7"}}
+{ "traceId": "96db5f125cb54111f2a95d7419df8a15", "spanId": "7696d367503845f7", "traceState": "", "parentSpanId": "885e54cf2034b9f4", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:44.229940992Z", "endTime": "2021-04-20T20:33:44.272091648Z", "durationInNanos": 42150656, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/add_item_to_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "01b449260ce334f8"}}
+{ "traceId": "96db5f125cb54111f2a95d7419df8a15", "spanId": "01b449260ce334f8", "traceState": "", "parentSpanId": "885e54cf2034b9f4", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:44.320410368Z", "endTime": "2021-04-20T20:33:44.324994048Z", "durationInNanos": 4583680, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "c85e5dec4106a06a"}}
+{ "traceId": "96db5f125cb54111f2a95d7419df8a15", "spanId": "c85e5dec4106a06a", "traceState": "", "parentSpanId": "0b957c5bc548b795", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:44.178796544Z", "endTime": "2021-04-20T20:33:44.335090176Z", "durationInNanos": 156293632, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8088/update_order", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "bd67ffd1aca8ebd9"}}
+{ "traceId": "c0ef65e0d991727dbe26a071fd10e407", "spanId": "bd67ffd1aca8ebd9", "traceState": "", "parentSpanId": "0ee38170cee8fb5c", "name": "HTTP GET", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:44.555993344Z", "endTime": "2021-04-20T20:33:44.591705344Z", "durationInNanos": 35712000, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/get_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "GET", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "0ee38170cee8fb5c"}}
+{ "traceId": "c0ef65e0d991727dbe26a071fd10e407", "spanId": "0ee38170cee8fb5c", "traceState": "", "parentSpanId": "afcb84a35556aad5", "name": "get_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:44.555788544Z", "endTime": "2021-04-20T20:33:44.602074368Z", "durationInNanos": 46285824, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "afcb84a35556aad5"}}
+{ "traceId": "c0ef65e0d991727dbe26a071fd10e407", "spanId": "afcb84a35556aad5", "traceState": "", "parentSpanId": "e53a0ddf08ca7fe4", "name": "get_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:44.554990592Z", "endTime": "2021-04-20T20:33:44.604317184Z", "durationInNanos": 49326592, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "GET", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 32802, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/get_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/get_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "2131bd5f7b2bb426"}}
+{ "traceId": "70a3f615a998b76cd973d87710572913", "spanId": "2131bd5f7b2bb426", "traceState": "", "parentSpanId": "d6ed9d2f16247916", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:44.940555776Z", "endTime": "2021-04-20T20:33:45.019118848Z", "durationInNanos": 78563072, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8088/pay_order", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "83e66a83f1a293d1"}}
+{ "traceId": "65e793c50b861f00c1534090639dd7c3", "spanId": "83e66a83f1a293d1", "traceState": "", "parentSpanId": "5205b0912292faea", "name": "get_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:45.263542528Z", "endTime": "2021-04-20T20:33:45.287819520Z", "durationInNanos": 24276992, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "61e11870abc59f27"}}
+{ "traceId": "65e793c50b861f00c1534090639dd7c3", "spanId": "61e11870abc59f27", "traceState": "", "parentSpanId": "3cf94093fb7bea7c", "name": "HTTP GET", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:45.260458752Z", "endTime": "2021-04-20T20:33:45.295847168Z", "durationInNanos": 35388416, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/get_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "GET", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "80e3c195c1e1eb31"}}
+{ "traceId": "02feb3a4f611abd81f2a53244d1278ae", "spanId": "80e3c195c1e1eb31", "traceState": "", "parentSpanId": "9e64d04e62cd7e86", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:45.693580544Z", "endTime": "2021-04-20T20:33:45.694361344Z", "durationInNanos": 780800, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'banana', 'Qty': '2'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "3f748306070acb27"}}
+{ "traceId": "97551ce4600c334d4ab8fb8725ac1e67", "spanId": "3f748306070acb27", "traceState": "", "parentSpanId": "69af53e3494bca1c", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:45.937683456Z", "endTime": "2021-04-20T20:33:45.938361344Z", "durationInNanos": 677888, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'apple', 'Qty': 1}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "INSERT INTO Inventory_Items (ItemId, TotalQty) VALUES (%(ItemId)s, %(Qty)s) ON DUPLICATE KEY UPDATE TotalQty = TotalQty + %(Qty)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "3a025025e0a3b1fa"}}
+{ "traceId": "97551ce4600c334d4ab8fb8725ac1e67", "spanId": "3a025025e0a3b1fa", "traceState": "", "parentSpanId": "093bfc1b96f299dd", "name": "cartEmpty", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:45.912724480Z", "endTime": "2021-04-20T20:33:45.971964416Z", "durationInNanos": 59239936, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "PUT", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58706, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/cart_empty", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/cart_empty", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "093bfc1b96f299dd"}}
+{ "traceId": "97551ce4600c334d4ab8fb8725ac1e67", "spanId": "093bfc1b96f299dd", "traceState": "", "parentSpanId": "b5ad0d70c2c4c7d6", "name": "HTTP PUT", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:45.910498560Z", "endTime": "2021-04-20T20:33:45.977039104Z", "durationInNanos": 66540544, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/cart_empty", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "PUT", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "b5ad0d70c2c4c7d6"}}
+{ "traceId": "97551ce4600c334d4ab8fb8725ac1e67", "spanId": "b5ad0d70c2c4c7d6", "traceState": "", "parentSpanId": "04f5292ec03f47ff", "name": "clear_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:45.910301952Z", "endTime": "2021-04-20T20:33:45.987429632Z", "durationInNanos": 77127680, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "1abb073eb56f2eea"}}
+{ "traceId": "b450e7770b6bf942d91f238f77311fbe", "spanId": "1abb073eb56f2eea", "traceState": "", "parentSpanId": "b2c126fb125a3ec0", "name": "update_item", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:46.155314688Z", "endTime": "2021-04-20T20:33:46.180148224Z", "durationInNanos": 24833536, "serviceName": "database", "events": [ { "time": "2021-04-20T20:33:46.180106752Z", "name": "exception", "attributes": { "exception@message": "", "exception@type": "InvalidItemUpdate", "exception@stacktrace": """Traceback (most recent call last): File "/usr/lib/python3.6/site-packages/opentelemetry/sdk/trace/__init__.py", line 804, in use_span yield span File "databaseService.py", line 162, in updateItem raise InvalidItemUpdate("Not enough storage for itemId {}".format(data[ "ItemId" ])) InvalidItemUpdate """ }, "droppedAttributesCount": 0 } ], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "status.message": "InvalidItemUpdate: ", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 2, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "140b1c6e07ac7569"}}
+{ "traceId": "b450e7770b6bf942d91f238f77311fbe", "spanId": "140b1c6e07ac7569", "traceState": "", "parentSpanId": "5edd047783ce31e6", "name": "update_item", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:46.197120Z", "endTime": "2021-04-20T20:33:46.223479808Z", "durationInNanos": 26359808, "serviceName": "database", "events": [ { "time": "2021-04-20T20:33:46.223439872Z", "name": "exception", "attributes": { "exception@message": "", "exception@type": "InvalidItemUpdate", "exception@stacktrace": """Traceback (most recent call last): File "/usr/lib/python3.6/site-packages/opentelemetry/sdk/trace/__init__.py", line 804, in use_span yield span File "databaseService.py", line 162, in updateItem raise InvalidItemUpdate("Not enough storage for itemId {}".format(data[ "ItemId" ])) InvalidItemUpdate """ }, "droppedAttributesCount": 0 } ], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "status.message": "InvalidItemUpdate: ", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 2, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "c220b54c4e5447d7"}}
+{ "traceId": "b450e7770b6bf942d91f238f77311fbe", "spanId": "c220b54c4e5447d7", "traceState": "", "parentSpanId": "33c6e729ae31cf8e", "name": "payment", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:46.147583744Z", "endTime": "2021-04-20T20:33:46.289920512Z", "durationInNanos": 142336768, "serviceName": "payment", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8084, "span.attributes.http@status_text": "PARTIAL CONTENT", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "139782029922256", "resource.attributes.service@name": "payment", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 59968, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/checkout", "span.attributes.http@host": "localhost:8084", "span.attributes.http@target": "/checkout", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 206 }
+{ "index":{"_id": "33c6e729ae31cf8e"}}
+{ "traceId": "b450e7770b6bf942d91f238f77311fbe", "spanId": "33c6e729ae31cf8e", "traceState": "", "parentSpanId": "86582d579095a4b2", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:46.145408256Z", "endTime": "2021-04-20T20:33:46.294403840Z", "durationInNanos": 148995584, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8084/checkout", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "PARTIAL CONTENT", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 206 }
+{ "index":{"_id": "cfd7fff669823fd7"}}
+{ "traceId": "ba5a69d5dfd1eaa4077451d452ba473b", "spanId": "cfd7fff669823fd7", "traceState": "", "parentSpanId": "e270a32c23bb3d64", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:46.524823808Z", "endTime": "2021-04-20T20:33:46.526560Z", "durationInNanos": 1736192, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "SELECT ItemId, TotalQty FROM User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "3b2b065511029f95"}}
+{ "traceId": "95b27b5462c0dccc7e08126a25e64d3f", "spanId": "3b2b065511029f95", "traceState": "", "parentSpanId": "759ba13f98ab3fc6", "name": "add_item_to_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:46.847089408Z", "endTime": "2021-04-20T20:33:46.871549696Z", "durationInNanos": 24460288, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "3f5318f871490765"}}
+{ "traceId": "95b27b5462c0dccc7e08126a25e64d3f", "spanId": "3f5318f871490765", "traceState": "", "parentSpanId": "b2e9f99896086ca7", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:46.795104512Z", "endTime": "2021-04-20T20:33:46.936029952Z", "durationInNanos": 140925440, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8088/update_order", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "b2e9f99896086ca7"}}
+{ "traceId": "95b27b5462c0dccc7e08126a25e64d3f", "spanId": "b2e9f99896086ca7", "traceState": "", "parentSpanId": "", "name": "client_create_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:46.794855168Z", "endTime": "2021-04-20T20:33:46.938890240Z", "durationInNanos": 144035072, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_create_order", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "ad657e844f30d14a"}}
+{ "traceId": "c0d5be4cfded4677b472caeb6dced6eb", "spanId": "ad657e844f30d14a", "traceState": "", "parentSpanId": "e0e2f20d2c1b7308", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:47.212077312Z", "endTime": "2021-04-20T20:33:47.212736768Z", "durationInNanos": 659456, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'banana', 'Qty': 2}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "8d4b7a48cb7ee8e9"}}
+{ "traceId": "c0d5be4cfded4677b472caeb6dced6eb", "spanId": "8d4b7a48cb7ee8e9", "traceState": "", "parentSpanId": "f78dbd14cda8862e", "name": "update_item", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:47.231710720Z", "endTime": "2021-04-20T20:33:47.269911552Z", "durationInNanos": 38200832, "serviceName": "database", "events": [ { "time": "2021-04-20T20:33:47.269875456Z", "name": "exception", "attributes": { "exception@message": "", "exception@type": "InvalidItemUpdate", "exception@stacktrace": """Traceback (most recent call last): File "/usr/lib/python3.6/site-packages/opentelemetry/sdk/trace/__init__.py", line 804, in use_span yield span File "databaseService.py", line 162, in updateItem raise InvalidItemUpdate("Not enough storage for itemId {}".format(data[ "ItemId" ])) InvalidItemUpdate """ }, "droppedAttributesCount": 0 } ], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "status.message": "InvalidItemUpdate: ", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 2, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "6b10877e5ed07c99"}}
+{ "traceId": "c0d5be4cfded4677b472caeb6dced6eb", "spanId": "6b10877e5ed07c99", "traceState": "", "parentSpanId": "c321930cea7a01b8", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:47.305689344Z", "endTime": "2021-04-20T20:33:47.306357248Z", "durationInNanos": 667904, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'apple', 'Qty': 1}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "c36ca0e19d93a20e"}}
+{ "traceId": "c0d5be4cfded4677b472caeb6dced6eb", "spanId": "c36ca0e19d93a20e", "traceState": "", "parentSpanId": "1e21d6eba3353211", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:47.185514752Z", "endTime": "2021-04-20T20:33:47.329954560Z", "durationInNanos": 144439808, "serviceName": "payment", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8082/update_inventory", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "Update inventory response contains failed items.", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "139782029922256", "resource.attributes.service@name": "payment", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 206 }
+{ "index":{"_id": "385cdc02dfbd5f9c"}}
+{ "traceId": "16f5176887289baa94c27f12604b5163", "spanId": "385cdc02dfbd5f9c", "traceState": "", "parentSpanId": "b7db1195f7777f37", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:47.813824Z", "endTime": "2021-04-20T20:33:47.849940480Z", "durationInNanos": 36116480, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/add_item_to_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "728745836581a137"}}
+{ "traceId": "2aa556a9a859155d7f578aacf259588f", "spanId": "728745836581a137", "traceState": "", "parentSpanId": "f4fb15e340c39da3", "name": "get_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:48.096090880Z", "endTime": "2021-04-20T20:33:48.120184832Z", "durationInNanos": 24093952, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "30bde1e6725bc066"}}
+{ "traceId": "ecfe3ff116a31b4c5ec107289b615ff3", "spanId": "30bde1e6725bc066", "traceState": "", "parentSpanId": "2a4047a9b194cba8", "name": "pay_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:48.387603456Z", "endTime": "2021-04-20T20:33:48.463539712Z", "durationInNanos": 75936256, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 32960, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/pay_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/pay_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "f0839669f041b029"}}
+{ "traceId": "a7e35e333fe32a4fa0448bf258fff8e9", "spanId": "f0839669f041b029", "traceState": "", "parentSpanId": "8b858870f3946a12", "name": "get_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:48.727124224Z", "endTime": "2021-04-20T20:33:48.776144128Z", "durationInNanos": 49019904, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "GET", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 32970, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/get_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/get_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "8b858870f3946a12"}}
+{ "traceId": "a7e35e333fe32a4fa0448bf258fff8e9", "spanId": "8b858870f3946a12", "traceState": "", "parentSpanId": "5d15d016d2efc520", "name": "HTTP GET", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:48.725030144Z", "endTime": "2021-04-20T20:33:48.780702464Z", "durationInNanos": 55672320, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8088/get_order", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "GET", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "7ff60cf452880953"}}
+{ "traceId": "25af475f804ec5edbfab9d1ba4018ce5", "spanId": "7ff60cf452880953", "traceState": "", "parentSpanId": "c6c238ba3d8255f4", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:49.000432896Z", "endTime": "2021-04-20T20:33:49.036928768Z", "durationInNanos": 36495872, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/add_item_to_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "17ba287b7e0a55a5"}}
+{ "traceId": "2aa556a9a859155d7f578aacf259588f", "spanId": "17ba287b7e0a55a5", "traceState": "", "parentSpanId": "11f0fc7fd6fc8ef7", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:48.133449435Z", "endTime": "2021-04-20T20:33:48.134655277Z", "durationInNanos": 1205842, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-8", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 138, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "75432a4e251c77c6"}}
+{ "traceId": "97551ce4600c334d4ab8fb8725ac1e67", "spanId": "75432a4e251c77c6", "traceState": "", "parentSpanId": "3922ee10e2a02211", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:45.982001755Z", "endTime": "2021-04-20T20:33:45.983769151Z", "durationInNanos": 1767396, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-8", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 138, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 57950, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "934a3522bd05ed13"}}
+{ "traceId": "e48a85b3dc34426059aa1347ea4171a5", "spanId": "934a3522bd05ed13", "traceState": "", "parentSpanId": "ad97f94c920dd63a", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:47.484001785Z", "endTime": "2021-04-20T20:33:47.485831317Z", "durationInNanos": 1829532, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-4", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 134, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58022, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "ee28b3abcaca75b1"}}
+{ "traceId": "16f5176887289baa94c27f12604b5163", "spanId": "ee28b3abcaca75b1", "traceState": "", "parentSpanId": "4eeed8358a7d5d30", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:47.894001979Z", "endTime": "2021-04-20T20:33:47.895816736Z", "durationInNanos": 1814757, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-6", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 136, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58040, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "362c0d7748107d8f"}}
+{ "traceId": "25af475f804ec5edbfab9d1ba4018ce5", "spanId": "362c0d7748107d8f", "traceState": "", "parentSpanId": "c6c238ba3d8255f4", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:49.080640768Z", "endTime": "2021-04-20T20:33:49.120250368Z", "durationInNanos": 39609600, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/add_item_to_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "6de234553c12cdd0"}}
+{ "traceId": "25af475f804ec5edbfab9d1ba4018ce5", "spanId": "6de234553c12cdd0", "traceState": "", "parentSpanId": "7559e66e65139dc8", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:48.997068544Z", "endTime": "2021-04-20T20:33:49.137304320Z", "durationInNanos": 140235776, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8088/update_order", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "7559e66e65139dc8"}}
+{ "traceId": "25af475f804ec5edbfab9d1ba4018ce5", "spanId": "7559e66e65139dc8", "traceState": "", "parentSpanId": "", "name": "client_create_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:48.996784896Z", "endTime": "2021-04-20T20:33:49.140167168Z", "durationInNanos": 143382272, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_create_order", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "fd57eface760a3c2"}}
+{ "traceId": "c1bd83b99e3992292daa0888489e618c", "spanId": "fd57eface760a3c2", "traceState": "", "parentSpanId": "c4eb12c87b56bbaf", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:49.547070976Z", "endTime": "2021-04-20T20:33:49.547717376Z", "durationInNanos": 646400, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'banana', 'Qty': 2}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "797a61c1556157d8"}}
+{ "traceId": "c1bd83b99e3992292daa0888489e618c", "spanId": "797a61c1556157d8", "traceState": "", "parentSpanId": "5e65bb1294c655ad", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:49.586952448Z", "endTime": "2021-04-20T20:33:49.587582464Z", "durationInNanos": 630016, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'orange', 'Qty': 3}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "5e65bb1294c655ad"}}
+{ "traceId": "c1bd83b99e3992292daa0888489e618c", "spanId": "5e65bb1294c655ad", "traceState": "", "parentSpanId": "4111fb00ec1efd77", "name": "update_item", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:49.567184128Z", "endTime": "2021-04-20T20:33:49.591741696Z", "durationInNanos": 24557568, "serviceName": "database", "events": [ { "time": "2021-04-20T20:33:49.591707904Z", "name": "exception", "attributes": { "exception@message": "", "exception@type": "InvalidItemUpdate", "exception@stacktrace": """Traceback (most recent call last): File "/usr/lib/python3.6/site-packages/opentelemetry/sdk/trace/__init__.py", line 804, in use_span yield span File "databaseService.py", line 162, in updateItem raise InvalidItemUpdate("Not enough storage for itemId {}".format(data[ "ItemId" ])) InvalidItemUpdate """ }, "droppedAttributesCount": 0 } ], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "status.message": "InvalidItemUpdate: ", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 2, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "4111fb00ec1efd77"}}
+{ "traceId": "c1bd83b99e3992292daa0888489e618c", "spanId": "4111fb00ec1efd77", "traceState": "", "parentSpanId": "977b8ddb69c6d9a7", "name": "updateItem", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:49.566329344Z", "endTime": "2021-04-20T20:33:49.596302592Z", "durationInNanos": 29973248, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "Not enough storage for itemId orange", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 2, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58870, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_item", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/update_item", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 422 }
+{ "index":{"_id": "977b8ddb69c6d9a7"}}
+{ "traceId": "c1bd83b99e3992292daa0888489e618c", "spanId": "977b8ddb69c6d9a7", "traceState": "", "parentSpanId": "28991f1d3a174ce4", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:49.564026112Z", "endTime": "2021-04-20T20:33:49.601558016Z", "durationInNanos": 37531904, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/update_item", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "Not enough storage for itemId orange", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "span.attributes.component": "http", "status.code": 2, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 422 }
+{ "index":{"_id": "704f4cab0d9b5606"}}
+{ "traceId": "c1bd83b99e3992292daa0888489e618c", "spanId": "704f4cab0d9b5606", "traceState": "", "parentSpanId": "bd73a71f8d9cc289", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:49.627682304Z", "endTime": "2021-04-20T20:33:49.628331008Z", "durationInNanos": 648704, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'apple', 'Qty': 1}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "28991f1d3a174ce4"}}
+{ "traceId": "c1bd83b99e3992292daa0888489e618c", "spanId": "28991f1d3a174ce4", "traceState": "", "parentSpanId": "d0f5f8f6a9167a1c", "name": "update_inventory", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:49.523589632Z", "endTime": "2021-04-20T20:33:49.645100288Z", "durationInNanos": 121510656, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "79a8b5b769a8af40"}}
+{ "traceId": "7a3182e62d533fa1e0617f21f5681a37", "spanId": "79a8b5b769a8af40", "traceState": "", "parentSpanId": "cc39a5b2d98e4127", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:49.876797696Z", "endTime": "2021-04-20T20:33:49.896148736Z", "durationInNanos": 19351040, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "TRUNCATE TABLE User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "cc39a5b2d98e4127"}}
+{ "traceId": "7a3182e62d533fa1e0617f21f5681a37", "spanId": "cc39a5b2d98e4127", "traceState": "", "parentSpanId": "2c3fe2ecd7602e0b", "name": "cart_empty", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:49.851799296Z", "endTime": "2021-04-20T20:33:49.899272448Z", "durationInNanos": 47473152, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "de9f1128bf12b7b9"}}
+{ "traceId": "7a3182e62d533fa1e0617f21f5681a37", "spanId": "de9f1128bf12b7b9", "traceState": "", "parentSpanId": "1861602b0fed74c0", "name": "clear_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:49.848355584Z", "endTime": "2021-04-20T20:33:49.917926400Z", "durationInNanos": 69570816, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "0d15e0e38cc75348"}}
+{ "traceId": "247d610dcbd05da1c7902081b6bec1f6", "spanId": "0d15e0e38cc75348", "traceState": "", "parentSpanId": "0b9642ed51dc4523", "name": "add_item_to_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:50.183780864Z", "endTime": "2021-04-20T20:33:50.208142848Z", "durationInNanos": 24361984, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "3b639def2d6ec40f"}}
+{ "traceId": "247d610dcbd05da1c7902081b6bec1f6", "spanId": "3b639def2d6ec40f", "traceState": "", "parentSpanId": "f53b324dd57c0a67", "name": "update_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:50.140426496Z", "endTime": "2021-04-20T20:33:50.269464320Z", "durationInNanos": 129037824, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 33036, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/update_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "f53b324dd57c0a67"}}
+{ "traceId": "247d610dcbd05da1c7902081b6bec1f6", "spanId": "f53b324dd57c0a67", "traceState": "", "parentSpanId": "0721e6662945f8c1", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:50.138248960Z", "endTime": "2021-04-20T20:33:50.274230272Z", "durationInNanos": 135981312, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8088/update_order", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "0721e6662945f8c1"}}
+{ "traceId": "247d610dcbd05da1c7902081b6bec1f6", "spanId": "0721e6662945f8c1", "traceState": "", "parentSpanId": "", "name": "client_create_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:50.137996544Z", "endTime": "2021-04-20T20:33:50.276978688Z", "durationInNanos": 138982144, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_create_order", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "3a565f7129913c17"}}
+{ "traceId": "eef4554373e188267b38928e2dabeab4", "spanId": "3a565f7129913c17", "traceState": "", "parentSpanId": "59ff85f342e07d43", "name": "HTTP GET", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:50.475230464Z", "endTime": "2021-04-20T20:33:50.531948288Z", "durationInNanos": 56717824, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8088/get_order", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "GET", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "76d4028a33aa32d4"}}
+{ "traceId": "20eabd650f3a068d9f590786f56885e7", "spanId": "76d4028a33aa32d4", "traceState": "", "parentSpanId": "c80dc4c948d060d2", "name": "addItemToCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:50.730701312Z", "endTime": "2021-04-20T20:33:50.759436800Z", "durationInNanos": 28735488, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58922, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/add_item_to_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/add_item_to_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "7e0f8516534902ba"}}
+{ "traceId": "20eabd650f3a068d9f590786f56885e7", "spanId": "7e0f8516534902ba", "traceState": "", "parentSpanId": "815628d64969d668", "name": "update_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:50.727141632Z", "endTime": "2021-04-20T20:33:50.855739904Z", "durationInNanos": 128598272, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "815628d64969d668"}}
+{ "traceId": "20eabd650f3a068d9f590786f56885e7", "spanId": "815628d64969d668", "traceState": "", "parentSpanId": "f16d32410e946012", "name": "update_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:50.725899008Z", "endTime": "2021-04-20T20:33:50.857993472Z", "durationInNanos": 132094464, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 33066, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/update_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "06838c62d1f8fc52"}}
+{ "traceId": "c48260d3774d6c2d4ba77c9e813eadec", "spanId": "06838c62d1f8fc52", "traceState": "", "parentSpanId": "", "name": "client_delivery_status", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:51.133010176Z", "endTime": "2021-04-20T20:33:51.191095040Z", "durationInNanos": 58084864, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_delivery_status", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "c2c0543fe0270e38"}}
+{ "traceId": "56127a0a4f362cfb605a907e6c419c6e", "spanId": "c2c0543fe0270e38", "traceState": "", "parentSpanId": "eb593b21c00b38c7", "name": "cart_sold", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:51.416972800Z", "endTime": "2021-04-20T20:33:51.463561472Z", "durationInNanos": 46588672, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "d9dd1b7eed5760a0"}}
+{ "traceId": "56127a0a4f362cfb605a907e6c419c6e", "spanId": "d9dd1b7eed5760a0", "traceState": "", "parentSpanId": "2b7af871bd8cd43f", "name": "HTTP DELETE", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:51.413930240Z", "endTime": "2021-04-20T20:33:51.472114688Z", "durationInNanos": 58184448, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/cart_sold", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "DELETE", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "3301dd384d83dc66"}}
+{ "traceId": "7f63958e2172b12500e40eed557a31c7", "spanId": "3301dd384d83dc66", "traceState": "", "parentSpanId": "9de35fba7cb7c4a3", "name": "get_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:51.679142400Z", "endTime": "2021-04-20T20:33:51.729883904Z", "durationInNanos": 50741504, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "GET", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 33104, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/get_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/get_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "c5e70373eb296aff"}}
+{ "traceId": "340a6c6f70a21d1bc8456dbbe5c79929", "spanId": "c5e70373eb296aff", "traceState": "", "parentSpanId": "49bf3ba4725523ca", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:51.977397248Z", "endTime": "2021-04-20T20:33:51.978067200Z", "durationInNanos": 669952, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'apple', 'Qty': '1'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "91b0beabefca51d0"}}
+{ "traceId": "340a6c6f70a21d1bc8456dbbe5c79929", "spanId": "91b0beabefca51d0", "traceState": "", "parentSpanId": "a7accb6ac082369d", "name": "addItemToCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:51.956622336Z", "endTime": "2021-04-20T20:33:51.985689344Z", "durationInNanos": 29067008, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58970, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/add_item_to_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/add_item_to_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "a7accb6ac082369d"}}
+{ "traceId": "340a6c6f70a21d1bc8456dbbe5c79929", "spanId": "a7accb6ac082369d", "traceState": "", "parentSpanId": "6576e80159aee6b8", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:51.954316288Z", "endTime": "2021-04-20T20:33:51.990446336Z", "durationInNanos": 36130048, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/add_item_to_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "439eff3f753e8e67"}}
+{ "traceId": "340a6c6f70a21d1bc8456dbbe5c79929", "spanId": "439eff3f753e8e67", "traceState": "", "parentSpanId": "6576e80159aee6b8", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:51.993564672Z", "endTime": "2021-04-20T20:33:52.029644544Z", "durationInNanos": 36079872, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/add_item_to_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "e0f5b0c6a6b1bbc2"}}
+{ "traceId": "340a6c6f70a21d1bc8456dbbe5c79929", "spanId": "e0f5b0c6a6b1bbc2", "traceState": "", "parentSpanId": "7b8507bd4a5a909f", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:52.055813888Z", "endTime": "2021-04-20T20:33:52.056485632Z", "durationInNanos": 671744, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'banana', 'Qty': '2'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "ab4ac8bcf7351137"}}
+{ "traceId": "340a6c6f70a21d1bc8456dbbe5c79929", "spanId": "ab4ac8bcf7351137", "traceState": "", "parentSpanId": "1717b0bbc49c8b5c", "name": "addItemToCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:52.034881024Z", "endTime": "2021-04-20T20:33:52.063697664Z", "durationInNanos": 28816640, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58978, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/add_item_to_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/add_item_to_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "0124ac48730385cc"}}
+{ "traceId": "340a6c6f70a21d1bc8456dbbe5c79929", "spanId": "0124ac48730385cc", "traceState": "", "parentSpanId": "", "name": "client_create_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:51.950673408Z", "endTime": "2021-04-20T20:33:52.088491264Z", "durationInNanos": 137817856, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": "client_create_order", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "e978fe4781c7212b"}}
+{ "traceId": "261f4f9f6d49c04588ddfc0b22d167c6", "spanId": "e978fe4781c7212b", "traceState": "", "parentSpanId": "f8aedbcbab807a78", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:52.270512128Z", "endTime": "2021-04-20T20:33:52.275296512Z", "durationInNanos": 4784384, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "0db04213ba31cb79"}}
+{ "traceId": "261f4f9f6d49c04588ddfc0b22d167c6", "spanId": "0db04213ba31cb79", "traceState": "", "parentSpanId": "66dd3959b912162c", "name": "HTTP DELETE", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:52.205003776Z", "endTime": "2021-04-20T20:33:52.284966144Z", "durationInNanos": 79962368, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8088/clear_order", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "DELETE", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "f14b6b57d7079a58"}}
+{ "traceId": "5be8370207cbb002a165d369fbc57b57", "spanId": "f14b6b57d7079a58", "traceState": "", "parentSpanId": "9e4947190e28b8f7", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:52.520363008Z", "endTime": "2021-04-20T20:33:52.521067776Z", "durationInNanos": 704768, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'apple', 'Qty': '1'}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "2c37405ee8325196"}}
+{ "traceId": "5be8370207cbb002a165d369fbc57b57", "spanId": "2c37405ee8325196", "traceState": "", "parentSpanId": "702250f453a02be6", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:52.535895296Z", "endTime": "2021-04-20T20:33:52.571971584Z", "durationInNanos": 36076288, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/add_item_to_cart", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "14148032cdebd6e5"}}
+{ "traceId": "4216a647a4396e50fc12cc78d571557e", "spanId": "14148032cdebd6e5", "traceState": "", "parentSpanId": "d985b5239c10d8bf", "name": "add_item_to_cart", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:52.678805504Z", "endTime": "2021-04-20T20:33:52.703546112Z", "durationInNanos": 24740608, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "ec48acd974e4f4ef"}}
+{ "traceId": "4216a647a4396e50fc12cc78d571557e", "spanId": "ec48acd974e4f4ef", "traceState": "", "parentSpanId": "8873f17b55cf568a", "name": "addItemToCart", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:52.717049088Z", "endTime": "2021-04-20T20:33:52.745951744Z", "durationInNanos": 28902656, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 59020, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/add_item_to_cart", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/add_item_to_cart", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "d85ef60c6b05ea1e"}}
+{ "traceId": "4216a647a4396e50fc12cc78d571557e", "spanId": "d85ef60c6b05ea1e", "traceState": "", "parentSpanId": "e0514a47c90c0ead", "name": "update_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:52.675259392Z", "endTime": "2021-04-20T20:33:52.823244288Z", "durationInNanos": 147984896, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "a9ae73162186cc7f"}}
+{ "traceId": "e447ed617aa651a7593c720d7e976625", "spanId": "a9ae73162186cc7f", "traceState": "", "parentSpanId": "ff285f4458209cf3", "name": "HTTP PUT", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:52.927145216Z", "endTime": "2021-04-20T20:33:52.990285312Z", "durationInNanos": 63140096, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8083/cart_empty", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "PUT", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "477408f3368f28af"}}
+{ "traceId": "e447ed617aa651a7593c720d7e976625", "spanId": "477408f3368f28af", "traceState": "", "parentSpanId": "ff285f4458209cf3", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:52.993329920Z", "endTime": "2021-04-20T20:33:52.997798144Z", "durationInNanos": 4468224, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8087/logs", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "f45a94f980605697"}}
+{ "traceId": "0bda4f69a15675f56069fa7b677f1c74", "spanId": "f45a94f980605697", "traceState": "", "parentSpanId": "470ef7b1b1e8c06c", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:53.238649856Z", "endTime": "2021-04-20T20:33:53.239367680Z", "durationInNanos": 717824, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'banana', 'Qty': 2}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "c07900555826d95f"}}
+{ "traceId": "0bda4f69a15675f56069fa7b677f1c74", "spanId": "c07900555826d95f", "traceState": "", "parentSpanId": "68f6536a0523f7f3", "name": "updateItem", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:53.217669120Z", "endTime": "2021-04-20T20:33:53.248192768Z", "durationInNanos": 30523648, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8083, "span.attributes.http@status_text": "Not enough storage for itemId banana", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "http", "status.code": 2, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 59046, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/update_item", "span.attributes.http@host": "localhost:8083", "span.attributes.http@target": "/update_item", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 422 }
+{ "index":{"_id": "854e04d060d378a8"}}
+{ "traceId": "0bda4f69a15675f56069fa7b677f1c74", "spanId": "854e04d060d378a8", "traceState": "", "parentSpanId": "a4030e9ad85b2a92", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:53.279769344Z", "endTime": "2021-04-20T20:33:53.280431360Z", "durationInNanos": 662016, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.db@statement@parameters": "{'ItemId': 'orange', 'Qty': 3}", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "UPDATE Inventory_Items SET TotalQty=IF(TotalQty >= %(Qty)s, TotalQty - %(Qty)s, TotalQty) WHERE ItemId=%(ItemId)s", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "2badcc8448bd5c5b"}}
+{ "traceId": "0bda4f69a15675f56069fa7b677f1c74", "spanId": "2badcc8448bd5c5b", "traceState": "", "parentSpanId": "6dcb9bfdeb68bef1", "name": "update_inventory", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:53.214871808Z", "endTime": "2021-04-20T20:33:53.338653184Z", "durationInNanos": 123781376, "serviceName": "inventory", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140491849416656", "resource.attributes.service@name": "inventory", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "79e7e8f4a6b9cfd6"}}
+{ "traceId": "0bda4f69a15675f56069fa7b677f1c74", "spanId": "79e7e8f4a6b9cfd6", "traceState": "", "parentSpanId": "b52867ccd766e67b", "name": "payment", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:53.210643200Z", "endTime": "2021-04-20T20:33:53.350407680Z", "durationInNanos": 139764480, "serviceName": "payment", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8084, "span.attributes.http@status_text": "PARTIAL CONTENT", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "139782029922256", "resource.attributes.service@name": "payment", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 60296, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/checkout", "span.attributes.http@host": "localhost:8084", "span.attributes.http@target": "/checkout", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 206 }
+{ "index":{"_id": "b52867ccd766e67b"}}
+{ "traceId": "0bda4f69a15675f56069fa7b677f1c74", "spanId": "b52867ccd766e67b", "traceState": "", "parentSpanId": "4c7ff265c1e0c9dc", "name": "HTTP POST", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:53.208381952Z", "endTime": "2021-04-20T20:33:53.354845184Z", "durationInNanos": 146463232, "serviceName": "frontend-client", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.http@url": "http://localhost:8084/checkout", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.http@status_text": "PARTIAL CONTENT", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@name": "frontend-client", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.requests", "span.attributes.http@method": "POST", "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@status_code": 206 }
+{ "index":{"_id": "7745e3605083e150"}}
+{ "traceId": "d5bc99166e521eec173bcb7f9b0d3c43", "spanId": "7745e3605083e150", "traceState": "", "parentSpanId": "f6b9b0130d0a7765", "name": "mysql.APM", "kind": "SPAN_KIND_CLIENT", "startTime": "2021-04-20T20:33:53.454045184Z", "endTime": "2021-04-20T20:33:53.455569152Z", "durationInNanos": 1523968, "serviceName": "database", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.db@user": "root", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.net@peer@name": "localhost", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140009019686864", "resource.attributes.service@name": "database", "span.attributes.component": "mysql", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.mysql", "span.attributes.db@type": "sql", "span.attributes.net@peer@port": 3306, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.db@instance": "APM", "span.attributes.db@statement": "SELECT ItemId, TotalQty FROM User_Carts", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal" }
+{ "index":{"_id": "cefea796ccf54813"}}
+{ "traceId": "d5bc99166e521eec173bcb7f9b0d3c43", "spanId": "cefea796ccf54813", "traceState": "", "parentSpanId": "28b54e1dd64fcf7d", "name": "clear_order", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:53.429565696Z", "endTime": "2021-04-20T20:33:53.503151872Z", "durationInNanos": 73586176, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@sdk@language": "python", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "status.code": 0, "instrumentationLibrary.name": "__main__" }
+{ "index":{"_id": "28b54e1dd64fcf7d"}}
+{ "traceId": "d5bc99166e521eec173bcb7f9b0d3c43", "spanId": "28b54e1dd64fcf7d", "traceState": "", "parentSpanId": "1dc7b46c2357c388", "name": "clear_order", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:53.428727808Z", "endTime": "2021-04-20T20:33:53.505276160Z", "durationInNanos": 76548352, "serviceName": "order", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "instrumentationLibrary.version": "0.14b0", "resource.attributes.telemetry@sdk@language": "python", "span.attributes.host@port": 8088, "span.attributes.http@status_text": "OK", "resource.attributes.telemetry@sdk@version": "0.14b0", "resource.attributes.service@instance@id": "140034008389000", "resource.attributes.service@name": "order", "span.attributes.component": "http", "status.code": 0, "instrumentationLibrary.name": "opentelemetry.instrumentation.flask", "span.attributes.http@method": "DELETE", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 33208, "resource.attributes.telemetry@sdk@name": "opentelemetry", "span.attributes.http@server_name": "0.0.0.0", "span.attributes.http@route": "/clear_order", "span.attributes.http@host": "localhost:8088", "span.attributes.http@target": "/clear_order", "span.attributes.http@scheme": "http", "resource.attributes.host@hostname": "ip-172-31-68-90.ec2.internal", "span.attributes.http@flavor": "1.1", "span.attributes.http@status_code": 200 }
+{ "index":{"_id": "fc1d1ffce95a27aa"}}
+{ "traceId": "4216a647a4396e50fc12cc78d571557e", "spanId": "fc1d1ffce95a27aa", "traceState": "", "parentSpanId": "0f929cd09feb717a", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:52.818457432Z", "endTime": "2021-04-20T20:33:52.819488855Z", "durationInNanos": 1031423, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-8", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 138, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "f44426165fbba4d0"}}
+{ "traceId": "e447ed617aa651a7593c720d7e976625", "spanId": "f44426165fbba4d0", "traceState": "", "parentSpanId": "b272143e732a91e9", "name": "LoggingController.save", "kind": "SPAN_KIND_INTERNAL", "startTime": "2021-04-20T20:33:52.995465166Z", "endTime": "2021-04-20T20:33:52.996460896Z", "durationInNanos": 995730, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.thread@name": "http-nio-8087-exec-10", "resource.attributes.telemetry@sdk@name": "opentelemetry", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 140, "resource.attributes.telemetry@auto@version": "0.10.1", "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.spring-webmvc" }
+{ "index":{"_id": "9fd37843dd616fab"}}
+{ "traceId": "c48260d3774d6c2d4ba77c9e813eadec", "spanId": "9fd37843dd616fab", "traceState": "", "parentSpanId": "3ed06551056e1fa6", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:51.176001692Z", "endTime": "2021-04-20T20:33:51.177560735Z", "durationInNanos": 1559043, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-6", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 136, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58184, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
+{ "index":{"_id": "fce44d7569908ba7"}}
+{ "traceId": "56127a0a4f362cfb605a907e6c419c6e", "spanId": "fce44d7569908ba7", "traceState": "", "parentSpanId": "608bd5e547e88e3e", "name": "/logs", "kind": "SPAN_KIND_SERVER", "startTime": "2021-04-20T20:33:51.477002352Z", "endTime": "2021-04-20T20:33:51.478943130Z", "durationInNanos": 1940778, "serviceName": "analytics-service", "events": [], "links": [], "droppedAttributesCount": 0, "droppedEventsCount": 0, "droppedLinksCount": 0, "traceGroup": null, "span.attributes.net@peer@ip": "127.0.0.1", "span.attributes.http@url": "http://localhost:8087/logs", "span.attributes.thread@name": "http-nio-8087-exec-8", "instrumentationLibrary.version": "0.10.1", "resource.attributes.telemetry@sdk@language": "java", "span.attributes.thread@id": 138, "resource.attributes.telemetry@sdk@version": "0.10.0", "resource.attributes.service@name": "analytics-service", "status.code": 0, "instrumentationLibrary.name": "io.opentelemetry.auto.servlet", "span.attributes.http@method": "POST", "span.attributes.http@user_agent": "python-requests/2.25.1", "span.attributes.net@peer@port": 58194, "resource.attributes.telemetry@sdk@name": "opentelemetry", "resource.attributes.telemetry@auto@version": "0.10.1", "span.attributes.http@flavor": "HTTP/1.1", "span.attributes.http@status_code": 200, "span.attributes.http@client_ip": "127.0.0.1" }
diff --git a/.cypress/utils/panel_constants.js b/.cypress/utils/panel_constants.js
new file mode 100644
index 0000000000..987d1dc3c9
--- /dev/null
+++ b/.cypress/utils/panel_constants.js
@@ -0,0 +1,36 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const delay = 1300;
+
+export const TEST_PANEL = 'Test Panel';
+export const SAMPLE_PANEL = '[Logs] Web traffic Panel';
+
+export const SAMPLE_VISUALIZATIONS_NAMES = [
+ '[Logs] Average ram usage by operating systems',
+ '[Logs] Average ram usage per day by apple os',
+ '[Logs] Average ram usage per day by windows os',
+ '[Logs] Daily count for error response codes',
+ '[Logs] Count requests from US to CN, IN and JP',
+ '[Logs] Max and average bytes by host',
+ '[Logs] Count total requests by tags',
+ '[Logs] Daily average bytes',
+];
+
+export const PPL_VISUALIZATIONS = [
+ 'source = opensearch_dashboards_sample_data_flights | stats count() by Dest',
+ 'source = opensearch_dashboards_sample_data_flights | stats avg(FlightDelayMin) by Carrier',
+ 'source = opensearch_dashboards_sample_data_flights | stats max( DistanceKilometers ) by DestCityName',
+];
+
+export const PPL_VISUALIZATIONS_NAMES = [
+ 'Flight count by destination',
+ 'Average flight delay minutes',
+ 'Max distance by destination city',
+];
+
+export const NEW_VISUALIZATION_NAME = 'Flight count by destination airport';
+
+export const PPL_FILTER = "where Carrier = 'OpenSearch-Air' | where Dest = 'Munich Airport'";
diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 0000000000..4d8297eb33
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,14 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+module.exports = {
+ root: true,
+ extends: [
+ '@elastic/eslint-config-kibana',
+ 'plugin:@elastic/eui/recommended',
+ 'plugin:react-hooks/recommended',
+ ],
+};
+
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000000..a2f03f8c32
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,2 @@
+# This should match the owning team set up in https://github.com/orgs/opensearch-project/teams
+* @opensearch-project/trace-analytics
\ No newline at end of file
diff --git a/.github/draft-release-notes-config.yml b/.github/draft-release-notes-config.yml
new file mode 100644
index 0000000000..371f1b065e
--- /dev/null
+++ b/.github/draft-release-notes-config.yml
@@ -0,0 +1,45 @@
+# The overall template of the release notes
+template: |
+ Compatible with OpenSearch and OpenSearch Dashboards Version $RESOLVED_VERSION
+ $CHANGES
+
+# Setting the formatting and sorting for the release notes body
+name-template: Version $RESOLVED_VERSION
+change-template: "* $TITLE ([#$NUMBER](https://github.com/opensearch-project/observability/pull/$NUMBER))"
+sort-by: merged_at
+sort-direction: ascending
+replacers:
+ - search: '##'
+ replace: '###'
+
+# Organizing the tagged PRs into unified categories
+categories:
+ - title: 'Breaking Changes'
+ labels:
+ - 'Breaking Changes'
+ - title: 'Features'
+ labels:
+ - 'feature'
+ - title: 'Enhancements'
+ labels:
+ - 'enhancement'
+ - title: 'Bug Fixes'
+ labels:
+ - 'bug'
+ - title: 'Infrastructure'
+ labels:
+ - 'infra'
+ - 'test'
+ - 'dependencies'
+ - 'github actions'
+ - title: 'Documentation'
+ labels:
+ - 'documentation'
+ - title: 'Maintenance'
+ labels:
+ - "version compatibility"
+ - "maintenance"
+ - title: 'Refactoring'
+ labels:
+ - 'refactor'
+ - 'code quality'
diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml
new file mode 100644
index 0000000000..e47d8d88c0
--- /dev/null
+++ b/.github/workflows/backport.yml
@@ -0,0 +1,28 @@
+name: Backport
+on:
+ pull_request_target:
+ types:
+ - closed
+ - labeled
+
+jobs:
+ backport:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+ pull-requests: write
+ name: Backport
+ steps:
+ - name: GitHub App token
+ id: github_app_token
+ uses: tibdex/github-app-token@v1.5.0
+ with:
+ app_id: ${{ secrets.APP_ID }}
+ private_key: ${{ secrets.APP_PRIVATE_KEY }}
+ installation_id: 22958780
+
+ - name: Backport
+ uses: VachaShah/backport@v1.1.4
+ with:
+ github_token: ${{ steps.github_app_token.outputs.token }}
+ branch_name: backport/backport-${{ github.event.number }}
diff --git a/.github/workflows/test-and-build-workflow.yml b/.github/workflows/dashboards-observability-test-and-build-workflow.yml
similarity index 65%
rename from .github/workflows/test-and-build-workflow.yml
rename to .github/workflows/dashboards-observability-test-and-build-workflow.yml
index d37b5145f2..7de3170c0a 100644
--- a/.github/workflows/test-and-build-workflow.yml
+++ b/.github/workflows/dashboards-observability-test-and-build-workflow.yml
@@ -1,12 +1,12 @@
-name: Test and Build Trace Analytics
+name: Test and Build Observability Dashboards Plugin
on: [pull_request, push]
env:
- PLUGIN_NAME: trace-analytics-dashboards
- OPENSEARCH_VERSION: '1.0'
- OPENSEARCH_PLUGIN_VERSION: 1.0.0.0
+ PLUGIN_NAME: dashboards-observability
+ OPENSEARCH_VERSION: '1.3'
+ OPENSEARCH_PLUGIN_VERSION: 1.3.4.0
jobs:
@@ -15,6 +15,9 @@ jobs:
runs-on: ubuntu-latest
steps:
+ - name: Checkout Plugin
+ uses: actions/checkout@v1
+
- name: Checkout OpenSearch Dashboards
uses: actions/checkout@v2
with:
@@ -40,36 +43,36 @@ jobs:
echo "Installing yarn ${{ steps.versions_step.outputs.yarn_version }}"
npm i -g yarn@${{ steps.versions_step.outputs.yarn_version }}
- - name: Checkout Plugin
- uses: actions/checkout@v2
- with:
- path: OpenSearch-Dashboards/plugins/trace-analytics
+ - name: Move Observability to Plugins Dir
+ run: mv dashboards-observability OpenSearch-Dashboards/plugins/dashboards-observability
- name: Plugin Bootstrap
run: |
- cd OpenSearch-Dashboards/plugins/trace-analytics
+ cd OpenSearch-Dashboards/plugins/dashboards-observability
yarn osd bootstrap
- - name: Test
+ - name: Test all dashboards-observability modules
run: |
- cd OpenSearch-Dashboards/plugins/trace-analytics
+ cd OpenSearch-Dashboards/plugins/dashboards-observability
yarn test --coverage
- name: Upload coverage
uses: codecov/codecov-action@v1
with:
+ flags: dashboards-observability
+ directory: ./OpenSearch-Dashboards/plugins/dashboards-observability
token: ${{ secrets.CODECOV_TOKEN }}
- direcotry: ./OpenSearch-Dashboards/plugins/trace-analytics
+ # TODO remove hard coded version when observability is ready
- name: Build Artifact
run: |
- cd OpenSearch-Dashboards/plugins/trace-analytics
+ cd OpenSearch-Dashboards/plugins/dashboards-observability
yarn build
mv ./build/*.zip ./build/${{ env.PLUGIN_NAME }}-${{ env.OPENSEARCH_PLUGIN_VERSION }}.zip
- name: Upload Artifact
uses: actions/upload-artifact@v1
with:
- name: trace-analytics
- path: ./OpenSearch-Dashboards/plugins/trace-analytics/build
+ name: dashboards-observability
+ path: ./OpenSearch-Dashboards/plugins/dashboards-observability/build
diff --git a/.github/workflows/dco.yml b/.github/workflows/dco.yml
new file mode 100644
index 0000000000..cf30ea89dc
--- /dev/null
+++ b/.github/workflows/dco.yml
@@ -0,0 +1,18 @@
+name: Developer Certificate of Origin Check
+
+on: [pull_request]
+
+jobs:
+ check:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Get PR Commits
+ id: 'get-pr-commits'
+ uses: tim-actions/get-pr-commits@v1.1.0
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ - name: DCO Check
+ uses: tim-actions/dco@v1.1.0
+ with:
+ commits: ${{ steps.get-pr-commits.outputs.commits }}
diff --git a/.github/workflows/delete_backport_branch.yml b/.github/workflows/delete_backport_branch.yml
new file mode 100644
index 0000000000..387a124b8c
--- /dev/null
+++ b/.github/workflows/delete_backport_branch.yml
@@ -0,0 +1,15 @@
+name: Delete merged branch of the backport PRs
+on:
+ pull_request:
+ types:
+ - closed
+
+jobs:
+ delete-branch:
+ runs-on: ubuntu-latest
+ if: startsWith(github.event.pull_request.head.ref,'backport/')
+ steps:
+ - name: Delete merged branch
+ uses: SvanBoxel/delete-merged-branch@main
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/draft-release-notes-workflow.yml b/.github/workflows/draft-release-notes-workflow.yml
new file mode 100644
index 0000000000..2c4567d397
--- /dev/null
+++ b/.github/workflows/draft-release-notes-workflow.yml
@@ -0,0 +1,21 @@
+name: Release Drafter
+
+on:
+ push:
+ branches:
+ - main
+
+jobs:
+ update_release_draft:
+ name: Update draft release notes
+ runs-on: ubuntu-latest
+ steps:
+ # Drafts your next Release notes as Pull Requests are merged into "main"
+ - name: Update draft release notes
+ uses: release-drafter/release-drafter@v5
+ with:
+ config-name: draft-release-notes-config.yml
+ tag: (None)
+ version: x.x.0.0
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/link-checker.yml b/.github/workflows/link-checker.yml
index 5e6fd3942a..ed4ce699e3 100644
--- a/.github/workflows/link-checker.yml
+++ b/.github/workflows/link-checker.yml
@@ -16,7 +16,7 @@ jobs:
id: lychee
uses: lycheeverse/lychee-action@master
with:
- args: --accept=200,403,429 "**/*.html" "**/*.md" "**/*.txt"
+ args: --accept=200,403,429 "./**/*.html" "./**/*.md" "./**/*.txt"
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
- name: Fail if there were link errors
diff --git a/.github/workflows/opensearch-observability-test-and-build-workflow.yml b/.github/workflows/opensearch-observability-test-and-build-workflow.yml
new file mode 100644
index 0000000000..3b3c62f679
--- /dev/null
+++ b/.github/workflows/opensearch-observability-test-and-build-workflow.yml
@@ -0,0 +1,56 @@
+name: Test and Build OpenSearch Observability Backend Plugin
+
+on: [pull_request, push]
+
+env:
+ OPENSEARCH_VERSION: '1.3.2-SNAPSHOT'
+ OPENSEARCH_BRANCH: '1.3'
+ COMMON_UTILS_BRANCH: 'main'
+
+jobs:
+ build:
+ strategy:
+ matrix:
+ java:
+ - 8
+ - 11
+ - 14
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v1
+
+ - name: Set up JDK ${{ matrix.java }}
+ uses: actions/setup-java@v1
+ with:
+ java-version: ${{ matrix.java }}
+
+ - name: Run Backwards Compatibility Tests
+ run: |
+ cd opensearch-observability
+ echo "Running backwards compatibility tests ..."
+ ./gradlew bwcTestSuite -Dtests.security.manager=false
+
+ - name: Build with Gradle
+ run: |
+ cd opensearch-observability
+ ./gradlew build -Dopensearch.version=${{ env.OPENSEARCH_VERSION }}
+
+ - name: Upload coverage
+ uses: codecov/codecov-action@v1
+ with:
+ flags: opensearch-observability
+ directory: opensearch-observability/
+ token: ${{ secrets.CODECOV_TOKEN }}
+
+ - name: Create Artifact Path
+ run: |
+ mkdir -p opensearch-observability-builds
+ cp -r ./opensearch-observability/build/distributions/*.zip opensearch-observability-builds/
+
+ - name: Upload Artifacts
+ uses: actions/upload-artifact@v1
+ with:
+ name: opensearch-observability
+ path: opensearch-observability-builds
diff --git a/.github/workflows/release-workflow.yml b/.github/workflows/release-workflow.yml
deleted file mode 100644
index 622384075f..0000000000
--- a/.github/workflows/release-workflow.yml
+++ /dev/null
@@ -1,58 +0,0 @@
-
-name: Release Trace Analytics Artifacts
-
-on:
- push:
- tags:
- - 'v*'
-
-env:
- PLUGIN_NAME: trace-analytics-dashboards
- OPENSEARCH_VERSION: '1.0'
- OPENSEARCH_PLUGIN_VERSION: 1.0.0.0
-
-jobs:
-
- build:
-
- runs-on: ubuntu-latest
-
- steps:
-
- - name: Configure AWS Credentials
- uses: aws-actions/configure-aws-credentials@v1
- with:
- aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
- aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- aws-region: us-east-1
-
- - name: Checkout OpenSearch Dashboards
- uses: actions/checkout@v1
- with:
- repository: opensearch-project/Opensearch-Dashboards
- ref: ${{ env.OPENSEARCH_VERSION }}
- path: OpenSearch-Dashboards
-
- - name: Checkout Plugin
- uses: actions/checkout@v1
- with:
- path: OpenSearch-Dashboards/plugins/trace-analytics
-
- - name: Setup Node
- uses: actions/setup-node@v1
- with:
- node-version: '10.23.1'
-
- - name: Plugin Bootstrap
- run: |
- yarn osd bootstrap
-
- - name: Build Artifact
- run: |
- yarn build
- mv ./build/*.zip ./build/${{ env.PLUGIN_NAME }}-${{ env.OPENSEARCH_PLUGIN_VERSION }}.zip
- artifact=`ls ./build/*.zip`
-
- # TODO change to new bucket
- aws s3 cp $artifact s3://artifacts.opendistroforelasticsearch.amazon.com/downloads/kibana-plugins/opendistro-trace-analytics/
- aws cloudfront create-invalidation --distribution-id ${{ secrets.DISTRIBUTION_ID }} --paths "/downloads/*"
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000..c0fc797919
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+node_modules/
+target/
+build/
+coverage/
+.cypress/screenshots
+.cypress/videos
diff --git a/common/constants/application_analytics.ts b/common/constants/application_analytics.ts
new file mode 100644
index 0000000000..df675a7048
--- /dev/null
+++ b/common/constants/application_analytics.ts
@@ -0,0 +1,19 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const TAB_OVERVIEW_ID = 'app-analytics-overview';
+export const TAB_SERVICE_ID = 'app-analytics-service';
+export const TAB_TRACE_ID = 'app-analytics-trace';
+export const TAB_LOG_ID = 'app-analytics-log';
+export const TAB_PANEL_ID = 'app-analytics-panel';
+export const TAB_CONFIG_ID = 'app-analytics-config';
+export const TAB_OVERVIEW_TITLE = 'Overview';
+export const TAB_SERVICE_TITLE = 'Services';
+export const TAB_TRACE_TITLE = 'Traces & Spans';
+export const TAB_LOG_TITLE = 'Log Events';
+export const TAB_PANEL_TITLE = 'Panel';
+export const TAB_CONFIG_TITLE = 'Configuration';
+
+export const APP_ANALYTICS_API_PREFIX = '/api/observability/application';
diff --git a/common/constants/autocomplete.ts b/common/constants/autocomplete.ts
new file mode 100644
index 0000000000..b8c1c41b95
--- /dev/null
+++ b/common/constants/autocomplete.ts
@@ -0,0 +1,202 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable prettier/prettier */
+
+import { BaseItem } from '@algolia/autocomplete-core';
+
+export const firstCommand = [{ label: 'source' }];
+
+export const pipeCommands = [
+ { label: 'dedup' },
+ { label: 'eval' },
+ { label: 'fields' },
+ { label: 'head' },
+ { label: 'parse' },
+ { label: 'rare' },
+ { label: 'rename' },
+ { label: 'sort' },
+ { label: 'stats' },
+ { label: 'top' },
+ { label: 'where' },
+];
+
+export const statsCommands = [
+ { label: 'count()' },
+ { label: 'sum(' },
+ { label: 'avg(' },
+ { label: 'max(' },
+ { label: 'min(' },
+ { label: 'var_samp(' },
+ { label: 'var_pop(' },
+ { label: 'stddev_samp(' },
+ { label: 'stddev_pop(' },
+];
+
+export const numberTypes = [
+ 'long',
+ 'integer',
+ 'short',
+ 'byte',
+ 'double',
+ 'float',
+ 'half_float',
+ 'scaled_float',
+ 'unsigned_long',
+];
+
+export interface AutocompleteItem extends BaseItem {
+ input: string;
+ itemName: string;
+ label: string;
+ suggestion: string;
+ __autocomplete_id?: number;
+}
+
+export interface FieldItem {
+ label: string;
+ type: string;
+}
+
+export interface IndexItem {
+ label: string;
+}
+
+export interface DataItem {
+ label: string;
+ doc_count: any;
+}
+
+const JUST_SEARCH_REGEX = /\s*(search\s+source|source|index)\s*=\s*[^\\\/\?\"\<\>\|\s\,\#]*(\s*,\s*[^\\\/\?\"\<\>\|\s\,\#]+)*/;
+const SEARCH_WHERE_REGEX = /\s*(search\s+source|source|index)\s*=\s*[^\\\/\?\"\<\>\|\s\,\#]*(\s*,\s*[^\\\/\?\"\<\>\|\s\,\#]+)*\s*\|\s*where\s+\S+\s*=\s*\S+/;
+const SEARCH_MATCH_REGEX = /\s*(search\s+source|source|index)\s*=\s*[^\\\/\?\"\<\>\|\s\,\#]*(\s*,\s*[^\\\/\?\"\<\>\|\s\,\#]+)*\s*\|\s*where\s+match\(\S+,\s*\S+\)/;
+export const EMPTY_REGEX = /^\s*\S*$/;
+export const FIELD_AFTER_COMMAND = /^\s*(dedup|eval|rare|top|rename|where\s+match\()\s+\S*$/;
+
+// Regex for where command
+export const MATCH_FIELD_AFTER_WHERE = /^\s*where\s+\S*$/;
+export const EQUAL_AFTER_WHERE_FIELD = /^\s*where\s+(\S+)\s+$/;
+export const DATA_AFTER_WHERE_EQUAL = /^\s*where\s+\S+\s*=\s*(("(\w|\s|')*)|(\d*\.?\d*)|\w*)$/;
+export const PIPE_AFTER_WHERE = /^\s*where\s+\S+\s*=\s*(("(\w|\s|')+")|(\d+\.?\d*)|\w+)\s+$/;
+export const COMMA_AFTER_FIELD = /^\s*where\s+match\(\s*([^\s,]+)\s*$/;
+export const DATA_AFTER_COMMA = /^\s*where\s+match\(\s*\S+\s*,\s*(("(\w|\s|')*)|(\d*\.?\d*)|\w*)$/;
+export const CLOSE_AFTER_DATA = /^\s*where\s+match\(\s*\S+\s*,\s*(("(\w|\s|')+")|(\d+\.?\d*)|\w+)\s+$/;
+export const PIPE_AFTER_MATCH = /^\s*where\s+match\(\s*\S+\s*,\s*(("(\w|\s|')+")|(\d+\.?\d*)|\w+)\s*\)\s*$/;
+
+// Regex for dedup command
+export const FIELD_IN_FIELD_LOOP = /^\s*dedup\s*\d*\s+\S+\s*(,\s*\S+\s*)*,\s*([^\s,]*)$/;
+export const COMMA_PIPE_AFTER_FIELD = /^\s*dedup\s*\d*\s+\S+\s*(,\s*\S+\s*)*\s+$/;
+export const PIPE_AFTER_KEEP_EMPTY = /^\s*dedup\s*\d*\s+\S+\s*(,\s*\S+\s*)*\s*keepempty=true\s+$/;
+export const PIPE_AFTER_CONSECUTIVE = /^\s*dedup\s*\d*\s+\S+\s*(,\s*\S+\s*)*\s*consecutive=true\s+$/;
+
+// Regex for eval command
+export const EQUAL_AFTER_EVAL_FIELD = /^\s*eval\s+(\S+)\s+$/;
+export const FIELD_AFTER_EVAL_EQUAL = /^\s*eval\s+\S+\s*=\s*\S*$/;
+export const MATH_AFTER_FIELD = /^\s*eval\s+\S+\s*=\s*\S+\s+$/;
+export const PIPE_MATH_AFTER_EXPRESSIONS = /^\s*eval\s+(\S+\s*=\s*\S+(\s*(\+|\-|\*|\/)\s*\S+)+)+\s+$/;
+
+// Regex for fields command
+export const PLUS_MINUS_FIELD_AFTER_FIELDS = /^\s*fields\s+\S*$/;
+export const FIELD_AFTER_PLUS_MINUS = /^\s*fields\s+(\+|\-)\s*\S*$/;
+export const COMMA_PIPE_AFTER_FIELDS = /^\s*fields\s+((\+|\-)\s+)?\S+\s*(,\s*\S+\s*)*\s+$/;
+export const FIELD_IN_FIELDS_LOOP = /^\s*fields\s+((\+|\-)\s+)?\S+\s*(,\s*\S+\s*)*,\s*\S*$/;
+
+// Regex for rare/top command
+export const COMMA_PIPE_BY_AFTER_FIELD = /^\s*(rare|top(\s+\d+)?)\s+\S+\s*(,\s*\S+\s*)*\s+\S*$/;
+export const RARE_TOP_FIELD_LOOP = /^\s*(rare|top(\s+\d+)?)\s+\S+\s*(,\s*\S+\s*)*,\s*\S*$/;
+export const FIELD_AFTER_BY = /^\s*(rare|top(\s+\d+)?)\s+\S+\s*(,\s*\S+\s*)*\s+by\s+\S*$/;
+export const PIPE_AFTER_GROUP_BY = /^\s*(rare|top(\s+\d+)?)\s+\S+\s*(,\s*\S+\s*)*\s+by\s+\S+\s+$/;
+
+// Regex for rename command
+export const AS_AFTER_FIELD = /^\s*rename\s+((,\s*)?\S+\s+as\s+\S+\s*)*\s*(,\s*)?\S+\s+\S*$/;
+export const COMMA_PIPE_AFTER_RENAME_FIELD = /^\s*rename\s+((,\s*)?\S+\s+as\s+\S+\s*)+$/;
+export const FIELD_AFTER_COMMA = /^\s*rename\s+((,\s*)?\S+\s+as\s+\S+\s*)+\s*,\s+\S*$/;
+
+// Regex for head command
+export const PIPE_AFTER_HEAD = /^\s*head\s+\d+\s+/;
+
+// Regex for sort command
+export const PLUS_MINUS_FIELD_AFTER_SORT = /^\s*sort(\s+\d+)?\s+\S*$/;
+export const FIELD_AFTER_PLUS_MINUS_SORT = /^\s*sort(\s+\d+)?((,\s*)?\s+(\+|\-)?\s*\S+\s*)*\s+(\+|\-)\s*\S*$/;
+export const COMMA_PIPE_AFTER_SORT_FIELD = /^\s*sort(\s+\d+)?((,\s*)?\s+(\+|\-)?\s*\S+\s*)*\s+\S+\s+$/;
+export const PLUS_MINUS_FIELD_IN_FIELDS_LOOP = /^\s*sort(\s+\d+)?((,\s*)?\s+(\+|\-)?\s*\S+\s*)*,\s+\S*$/;
+
+// Regex for stats command
+export const FIELD_SPAN_AFTER_GROUP_BY = /^\s*stats\s+((,\s*)?((sum|avg|max|min|var_samp|var_pop|stddev_samp|stddev_pop)\(\s*\S+\s*\)\s*)|((,\s*)?count\(\)\s*))+\s+by\s+\S*$/;
+export const NUM_FIELD_AFTER_AGGREGATION = /^\s*stats\s+((,\s*)?((sum|avg|max|min|var_samp|var_pop|stddev_samp|stddev_pop)\(\s*\S+\s*\)\s*)|((,\s*)?count\(\)\s*))*(,\s*)?(sum|avg|max|min|var_samp|var_pop|stddev_samp|stddev_pop)\(\s*\S*$/;
+export const FIELD_AFTER_SPAN = /^\s*stats\s+((,\s*)?((sum|avg|max|min|var_samp|var_pop|stddev_samp|stddev_pop)\(\s*\S+\s*\)\s*)|((,\s*)?count\(\)\s*))+\s+by\s+span\(\s*([^\s,]*)\s*$/;
+export const CLOSE_AFTER_SPAN = /^\s*stats\s+((,\s*)?((sum|avg|max|min|var_samp|var_pop|stddev_samp|stddev_pop)\(\s*\S+\s*\)\s*)|((,\s*)?count\(\)\s*))+\s+by\s+span\(\s*[^\s,]+\s*,\s*(("(\w|\s|')+")|(\d+\.?\d*)|\w+)\s+$/;
+export const PIPE_AFTER_SPAN = /^\s*stats\s+((,\s*)?((sum|avg|max|min|var_samp|var_pop|stddev_samp|stddev_pop)\(\s*\S+\s*\)\s*)|((,\s*)?count\(\)\s*))+\s+by\s+span\(\s*[^\s,]+\s*,\s*(("(\w|\s|')*")|(\d*\.?\d*)|\w*)\s*\)\s*$/;
+export const CLOSE_AFTER_FIELD = /^\s*stats\s+((,\s*)?((sum|avg|max|min|var_samp|var_pop|stddev_samp|stddev_pop)\(\s*\S+\s*\)\s*)|((,\s*)?count\(\)\s*))*(,\s*)?(sum|avg|max|min|var_samp|var_pop|stddev_samp|stddev_pop)\(\s*\S+\s+$/;
+export const COMMA_PIPE_BY_AFTER_AGGREGATION = /^\s*stats\s+((,\s*)?((sum|avg|max|min|var_samp|var_pop|stddev_samp|stddev_pop)\(\s*\S+\s*\)\s*)|((,\s*)?count\(\)\s*))+\s+\S*$/;
+export const PIPE_AFTER_STATS_GROUP_BY = /^\s*stats\s+((,\s*)?((sum|avg|max|min|var_samp|var_pop|stddev_samp|stddev_pop)\(\s*\S+\s*\)\s*)|((,\s*)?count\(\)\s*))+\s+by\s+\S+\s+$/;
+export const AGGREGATION_FOR_STATS= /^\s*stats\s+(((,\s*)?((sum|avg|max|min|var_samp|var_pop|stddev_samp|stddev_pop)\(\s*\S+\s*\)\s*)|((,\s*)?count\(\)\s*))+\s+,\s*)?\S*$/;
+
+// Regex for parse command
+export const STRING_FIELD_AFTER_PARSE = /^\s*parse\s+\S*$/;
+export const PIPE_AFTER_PARSE = /^\s*parse\s+\S+\s+$/;
+
+// Regex for source command
+export const EQUAL_AFTER_SOURCE = /^\s*source\s+$/;
+export const INDEX_AFTER_EQUAL = /^\s*source\s+=\s+[^\\\/\?\"\<\>\|\s\,\#]*$/;
+export const PIPE_COMMA_AFTER_INDEX = /^\s*source\s+=\s+[^\\\/\?\"\<\>\|\s\,\#]+(,[^\\\/\?\"\<\>\|\s\,\#]+)*\s+$/;
+export const MORE_INDEX_AFTER_COMMA = /^\s*source\s+=\s+[^\\\/\?\"\<\>\|\s\,\#]+(,[^\\\/\?\"\<\>\|\s\,\#]+)*,\s*[^\\\/\?\"\<\>\|\s\,\#]*\s*$/;
+
+export const regexForSuggestion = [
+ EMPTY_REGEX,
+ FIELD_AFTER_COMMAND,
+ MATCH_FIELD_AFTER_WHERE,
+ EQUAL_AFTER_WHERE_FIELD,
+ DATA_AFTER_WHERE_EQUAL,
+ PIPE_AFTER_WHERE,
+ COMMA_AFTER_FIELD,
+ DATA_AFTER_COMMA,
+ CLOSE_AFTER_DATA,
+ PIPE_AFTER_MATCH,
+ FIELD_IN_FIELD_LOOP,
+ COMMA_PIPE_AFTER_FIELD,
+ PIPE_AFTER_KEEP_EMPTY,
+ PIPE_AFTER_CONSECUTIVE,
+ EQUAL_AFTER_EVAL_FIELD,
+ FIELD_AFTER_EVAL_EQUAL,
+ MATH_AFTER_FIELD,
+ PIPE_MATH_AFTER_EXPRESSIONS,
+ PLUS_MINUS_FIELD_AFTER_FIELDS,
+ FIELD_AFTER_PLUS_MINUS,
+ COMMA_PIPE_AFTER_FIELDS,
+ FIELD_IN_FIELDS_LOOP,
+ COMMA_PIPE_BY_AFTER_FIELD,
+ RARE_TOP_FIELD_LOOP,
+ FIELD_AFTER_BY,
+ PIPE_AFTER_GROUP_BY,
+ COMMA_PIPE_AFTER_RENAME_FIELD,
+ FIELD_AFTER_COMMA,
+ AS_AFTER_FIELD,
+ PIPE_AFTER_HEAD,
+ PLUS_MINUS_FIELD_AFTER_SORT,
+ FIELD_AFTER_PLUS_MINUS_SORT,
+ PLUS_MINUS_FIELD_IN_FIELDS_LOOP,
+ COMMA_PIPE_AFTER_SORT_FIELD,
+ FIELD_SPAN_AFTER_GROUP_BY,
+ NUM_FIELD_AFTER_AGGREGATION,
+ FIELD_AFTER_SPAN,
+ CLOSE_AFTER_SPAN,
+ PIPE_AFTER_SPAN,
+ CLOSE_AFTER_FIELD,
+ COMMA_PIPE_BY_AFTER_AGGREGATION,
+ PIPE_AFTER_STATS_GROUP_BY,
+ AGGREGATION_FOR_STATS,
+ STRING_FIELD_AFTER_PARSE,
+ PIPE_AFTER_PARSE,
+ EQUAL_AFTER_SOURCE,
+ INDEX_AFTER_EQUAL,
+ PIPE_COMMA_AFTER_INDEX,
+ MORE_INDEX_AFTER_COMMA,
+];
+
+export const regexForIndex = [
+ JUST_SEARCH_REGEX,
+ SEARCH_WHERE_REGEX,
+ SEARCH_MATCH_REGEX,
+];
diff --git a/common/constants/custom_panels.ts b/common/constants/custom_panels.ts
new file mode 100644
index 0000000000..0c02b97a29
--- /dev/null
+++ b/common/constants/custom_panels.ts
@@ -0,0 +1,8 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const CUSTOM_PANELS_API_PREFIX = '/api/observability/operational_panels';
+export const CUSTOM_PANELS_DOCUMENTATION_URL = 'https://opensearch.org/docs/latest/observability-plugin/operational-panels/';
+export const CREATE_PANEL_MESSAGE = 'Enter a name to describe the purpose of this custom panel.';
diff --git a/common/constants/explorer.ts b/common/constants/explorer.ts
new file mode 100644
index 0000000000..fbe09f13ba
--- /dev/null
+++ b/common/constants/explorer.ts
@@ -0,0 +1,79 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const EVENT_ANALYTICS_DOCUMENTATION_URL =
+ 'https://opensearch.org/docs/latest/observability-plugin/event-analytics/';
+export const OPEN_TELEMETRY_LOG_CORRELATION_LINK =
+ 'https://opentelemetry.io/docs/reference/specification/logs/overview/#log-correlation';
+export const RAW_QUERY = 'rawQuery';
+export const FINAL_QUERY = 'finalQuery';
+export const SELECTED_DATE_RANGE = 'selectedDateRange';
+export const INDEX = 'index';
+export const SELECTED_TIMESTAMP = 'selectedTimestamp';
+export const SELECTED_FIELDS = 'selectedFields';
+export const UNSELECTED_FIELDS = 'unselectedFields';
+export const AVAILABLE_FIELDS = 'availableFields';
+export const QUERIED_FIELDS = 'queriedFields';
+export const TAB_ID_TXT_PFX = 'query-panel-';
+export const TAB_TITLE = 'New query';
+export const TAB_CHART_TITLE = 'Visualizations';
+export const TAB_EVENT_TITLE = 'Events';
+export const TAB_EVENT_ID_TXT_PFX = 'main-content-events-';
+export const TAB_CHART_ID_TXT_PFX = 'main-content-vis-';
+export const TAB_EVENT_ID = 'main-content-events';
+export const TAB_CHART_ID = 'main-content-vis';
+export const HAS_SAVED_TIMESTAMP = 'hasSavedTimestamp';
+export const FILTER_OPTIONS = ['Visualization', 'Query'];
+export const SAVED_QUERY = 'savedQuery';
+export const SAVED_VISUALIZATION = 'savedVisualization';
+export const SAVED_OBJECT_ID = 'savedObjectId';
+export const SAVED_OBJECT_TYPE = 'objectType';
+export const TAB_CREATED_TYPE = 'tabCreatedType';
+export const NEW_TAB = 'newTab';
+export const REDIRECT_TAB = 'redirect_tab';
+export const PAGE_SIZE = 50;
+export const DEFAULT_COLUMNS = ['', 'Time', '_source'];
+export const OTEL_TRACE_ID = 'traceId';
+export const DATE_PICKER_FORMAT = 'YYYY-MM-DD HH:mm:ss';
+export const TIME_INTERVAL_OPTIONS = [
+ {
+ text: 'Minute',
+ value: 'm',
+ },
+ {
+ text: 'Hour',
+ value: 'h',
+ },
+ {
+ text: 'Day',
+ value: 'd',
+ },
+ {
+ text: 'Week',
+ value: 'w',
+ },
+ {
+ text: 'Month',
+ value: 'M',
+ },
+ {
+ text: 'Year',
+ value: 'y',
+ },
+];
+
+// redux
+export const SELECTED_QUERY_TAB = 'selectedQueryTab';
+export const QUERY_TAB_IDS = 'queryTabIds';
+export const NEW_SELECTED_QUERY_TAB = 'newSelectedQueryTab';
+export const REDUX_EXPL_SLICE_QUERIES = 'queries';
+export const REDUX_EXPL_SLICE_QUERY_RESULT = 'queryResults';
+export const REDUX_EXPL_SLICE_FIELDS = 'fields';
+export const REDUX_EXPL_SLICE_QUERY_TABS = 'queryTabs';
+export const REDUX_EXPL_SLICE_VISUALIZATION = 'explorerVisualization';
+export const REDUX_EXPL_SLICE_COUNT_DISTRIBUTION = 'countDistributionVisualization';
+export const PLOTLY_GAUGE_COLUMN_NUMBER = 5;
+export const APP_ANALYTICS_TAB_ID_REGEX = /application-analytics-tab.+/;
+export const DEFAULT_AVAILABILITY_QUERY = 'stats count() by span( timestamp, 1h )';
diff --git a/common/constants/notebooks.ts b/common/constants/notebooks.ts
new file mode 100644
index 0000000000..c3140792cf
--- /dev/null
+++ b/common/constants/notebooks.ts
@@ -0,0 +1,23 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const NOTEBOOKS_API_PREFIX = '/api/observability/notebooks';
+export const NOTEBOOKS_SELECTED_BACKEND = 'DEFAULT'; // ZEPPELIN || DEFAULT
+export const NOTEBOOKS_FETCH_SIZE = 1000;
+export const CREATE_NOTE_MESSAGE = 'Enter a name to describe the purpose of this notebook.';
+export const NOTEBOOKS_DOCUMENTATION_URL = 'https://opensearch.org/docs/latest/observability-plugin/notebooks/';
+
+export const zeppelinURL = 'http://localhost:8080';
+
+export const wreckOptions = {
+ baseUrl: zeppelinURL,
+ headers: { 'Content-Type': 'application/json' },
+};
+
+const BASE_NOTEBOOKS_URI = '/_plugins/_notebooks';
+export const OPENSEARCH_NOTEBOOKS_API = {
+ GET_NOTEBOOKS: `${BASE_NOTEBOOKS_URI}/notebooks`,
+ NOTEBOOK: `${BASE_NOTEBOOKS_URI}/notebook`,
+};
diff --git a/common/constants/shared.ts b/common/constants/shared.ts
new file mode 100644
index 0000000000..19c0fb8fd9
--- /dev/null
+++ b/common/constants/shared.ts
@@ -0,0 +1,127 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import CSS from 'csstype';
+
+// Client route
+export const PPL_BASE = '/api/ppl';
+export const PPL_SEARCH = '/search';
+export const DSL_BASE = '/api/dsl';
+export const DSL_SEARCH = '/search';
+export const DSL_CAT = '/cat.indices';
+export const DSL_MAPPING = '/indices.getFieldMapping';
+export const OBSERVABILITY_BASE = '/api/observability';
+export const EVENT_ANALYTICS = '/event_analytics';
+export const SAVED_OBJECTS = '/saved_objects';
+export const SAVED_QUERY = '/query';
+export const SAVED_VISUALIZATION = '/vis';
+
+// Server route
+export const PPL_ENDPOINT = '/_plugins/_ppl';
+export const SQL_ENDPOINT = '/_plugins/_sql';
+export const DSL_ENDPOINT = '/_plugins/_dsl';
+
+export const observabilityID = 'observability-dashboards';
+export const observabilityTitle = 'Observability';
+export const observabilityPluginOrder = 6000;
+
+// Shared Constants
+export const SQL_DOCUMENTATION_URL = 'https://opensearch.org/docs/latest/search-plugins/sql/index/';
+export const PPL_DOCUMENTATION_URL =
+ 'https://opensearch.org/docs/latest/observability-plugin/ppl/commands/';
+export const UI_DATE_FORMAT = 'MM/DD/YYYY hh:mm A';
+export const PPL_DATE_FORMAT = 'YYYY-MM-DD HH:mm:ss.SSSSSS';
+export const SPAN_REGEX = /span/;
+export const PPL_SPAN_REGEX = /by\s*span/i;
+export const PPL_STATS_REGEX = /\|\s*stats/i;
+export const PPL_INDEX_INSERT_POINT_REGEX = /(search source|source|index)\s*=\s*([^|\s]+)(.*)/i;
+export const PPL_INDEX_REGEX = /(search source|source|index)\s*=\s*([^|\s]+)/i;
+export const PPL_NEWLINE_REGEX = /[\n\r]+/g;
+
+// Observability plugin URI
+const BASE_OBSERVABILITY_URI = '/_plugins/_observability';
+export const OPENSEARCH_PANELS_API = {
+ OBJECT: `${BASE_OBSERVABILITY_URI}/object`,
+};
+
+// Saved Objects
+export const SAVED_OBJECT = '/object';
+
+// Color Constants
+export const PLOTLY_COLOR = [
+ '#3CA1C7',
+ '#8C55A3',
+ '#DB748A',
+ '#F2BE4B',
+ '#68CCC2',
+ '#2A7866',
+ '#843769',
+ '#374FB8',
+ '#BD6F26',
+ '#4C636F',
+];
+
+export const LONG_CHART_COLOR = PLOTLY_COLOR[1];
+
+export const pageStyles: CSS.Properties = {
+ float: 'left',
+ width: '100%',
+ maxWidth: '1130px',
+};
+
+export const NUMERICAL_FIELDS = ['short', 'integer', 'long', 'float', 'double'];
+
+export const ENABLED_VIS_TYPES = ['bar', 'horizontal_bar', 'line', 'pie', 'heatmap', 'text'];
+
+//Live tail constants
+export const LIVE_OPTIONS = [
+ {
+ label:'5s',
+ startTime: 'now-5s',
+ delayTime: 5000,
+ },
+ {
+ label:'10s',
+ startTime: 'now-10s',
+ delayTime: 10000,
+ },
+ {
+ label:'30s',
+ startTime: 'now-30s',
+ delayTime: 30000,
+ },
+ {
+ label:'1m',
+ startTime: 'now-1m',
+ delayTime: 60000,
+ },
+ {
+ label:'5m',
+ startTime: 'now-5m',
+ delayTime: 60000 * 5,
+ },
+ {
+ label:'15m',
+ startTime: 'now-15m',
+ delayTime: 60000 * 15,
+ },
+ {
+ label:'30m',
+ startTime: 'now-30m',
+ delayTime: 60000 * 30,
+ },
+ {
+ label:'1h',
+ startTime: 'now-1h',
+ delayTime: 60000 * 60,
+ },
+ {
+ label:'2h',
+ startTime: 'now-2h',
+ delayTime: 60000 * 120,
+ },
+];
+
+export const LIVE_END_TIME ='now';
\ No newline at end of file
diff --git a/common/constants/trace_analytics.ts b/common/constants/trace_analytics.ts
new file mode 100644
index 0000000000..f480a25f6d
--- /dev/null
+++ b/common/constants/trace_analytics.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const DATA_PREPPER_INDEX_NAME = 'otel-v1-apm-span-*';
+export const DATA_PREPPER_SERVICE_INDEX_NAME = 'otel-v1-apm-service-map*';
+export const TRACE_ANALYTICS_DATE_FORMAT = 'MM/DD/YYYY HH:mm:ss';
+export const TRACE_ANALYTICS_PLOTS_DATE_FORMAT = 'MMM D, YYYY HH:mm:ss';
+export const SERVICE_MAP_MAX_NODES = 500;
+// size limit when requesting edge related queries, not necessarily the number of edges
+export const SERVICE_MAP_MAX_EDGES = 1000;
+export const TRACES_MAX_NUM = 3000;
+export const TRACE_ANALYTICS_DOCUMENTATION_LINK = 'https://opensearch.org/docs/latest/observability-plugin/trace/index/';
+
+export const TRACE_ANALYTICS_INDICES_ROUTE = '/api/observability/trace_analytics/indices';
+export const TRACE_ANALYTICS_DSL_ROUTE = '/api/observability/trace_analytics/query';
diff --git a/common/types/application_analytics.ts b/common/types/application_analytics.ts
new file mode 100644
index 0000000000..11f42c2361
--- /dev/null
+++ b/common/types/application_analytics.ts
@@ -0,0 +1,37 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export interface OptionType {
+ label: string;
+}
+
+export interface ApplicationType {
+ id: string;
+ dateCreated: string;
+ dateModified: string;
+ name: string;
+ description: string;
+ baseQuery: string;
+ servicesEntities: string[];
+ traceGroups: string[];
+ panelId: string;
+ availability: { name: string; color: string; availabilityVisId: string };
+}
+
+export interface ApplicationRequestType {
+ name: string;
+ description: string;
+ baseQuery: string;
+ servicesEntities: string[];
+ traceGroups: string[];
+ panelId: string;
+ availabilityVisId: string;
+}
+
+export interface AvailabilityType {
+ name: string;
+ color: string;
+ availabilityVisId: string;
+}
diff --git a/common/types/custom_panels.ts b/common/types/custom_panels.ts
new file mode 100644
index 0000000000..e397b06076
--- /dev/null
+++ b/common/types/custom_panels.ts
@@ -0,0 +1,47 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export interface CustomPanelListType {
+ name: string;
+ id: string;
+ dateCreated: number;
+ dateModified: number;
+ applicationId?: string;
+}
+
+export interface VisualizationType {
+ id: string;
+ savedVisualizationId: string;
+ x: number;
+ y: number;
+ w: number;
+ h: number;
+}
+
+export interface PanelType {
+ name: string;
+ visualizations: VisualizationType[];
+ timeRange: { to: string; from: string };
+ queryFilter: { query: string; language: string };
+ applicationId?: string;
+}
+
+export interface SavedVisualizationType {
+ id: string;
+ name: string;
+ query: string;
+ type: string;
+ selected_date_range: { start: string; end: string; text: string };
+ timeField: string;
+ application_id?: string;
+ user_configs: any;
+}
+
+export interface pplResponse {
+ data: any;
+ metadata: any;
+ size: number;
+ status: number;
+}
diff --git a/common/types/explorer.ts b/common/types/explorer.ts
new file mode 100644
index 0000000000..d43aba7518
--- /dev/null
+++ b/common/types/explorer.ts
@@ -0,0 +1,229 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { History } from 'history';
+import Plotly from 'plotly.js-dist';
+import {
+ RAW_QUERY,
+ SELECTED_FIELDS,
+ UNSELECTED_FIELDS,
+ AVAILABLE_FIELDS,
+ QUERIED_FIELDS,
+ INDEX,
+ FINAL_QUERY,
+ SELECTED_TIMESTAMP,
+ SELECTED_DATE_RANGE,
+} from '../constants/explorer';
+import { CoreStart, HttpStart, NotificationsStart } from '../../../../src/core/public';
+import SavedObjects from '../../public/services/saved_objects/event_analytics/saved_objects';
+import TimestampUtils from '../../public/services/timestamp/timestamp';
+import PPLService from '../../public/services/requests/ppl';
+import DSLService from '../../public/services/requests/dsl';
+
+export interface IQueryTab {
+ id: string;
+ name: React.ReactNode | string;
+ content: React.ReactNode;
+}
+
+export interface IField {
+ name: string;
+ type: string;
+}
+
+export interface ITabQueryResults {
+ [tabId: string]: any;
+}
+
+export interface ITabQueries {
+ [tabId: string]: IQuery;
+}
+
+export interface IQuery {
+ [RAW_QUERY]: string;
+ [FINAL_QUERY]: string;
+ [INDEX]: string;
+ [SELECTED_DATE_RANGE]: string[];
+ [SELECTED_TIMESTAMP]: string;
+}
+
+export interface IExplorerTabFields {
+ [tabId: string]: IExplorerFields;
+}
+
+export interface IExplorerFields {
+ [SELECTED_FIELDS]: IField[];
+ [UNSELECTED_FIELDS]: IField[];
+ [AVAILABLE_FIELDS]: IField[];
+ [QUERIED_FIELDS]: IField[];
+}
+
+export interface EmptyTabParams {
+ tabIds: string[] | undefined;
+ queries: any | undefined;
+ explorerData: any | undefined;
+}
+
+export interface ILogExplorerProps {
+ pplService: PPLService;
+ dslService: DSLService;
+ savedObjects: SavedObjects;
+ http: HttpStart;
+ history: History;
+ notifications: NotificationsStart;
+ timestampUtils: TimestampUtils;
+ setToast: (
+ title: string,
+ color?: string,
+ text?: React.ReactChild | undefined,
+ side?: string | undefined
+ ) => void;
+ savedObjectId: string;
+ getExistingEmptyTab: (params: EmptyTabParams) => string;
+}
+
+export interface IExplorerProps {
+ pplService: PPLService;
+ dslService: DSLService;
+ tabId: string;
+ savedObjects: SavedObjects;
+ timestampUtils: TimestampUtils;
+ history: History;
+ notifications: NotificationsStart;
+ savedObjectId: string;
+ curSelectedTabId: React.MutableRefObject;
+ setToast: (
+ title: string,
+ color?: string,
+ text?: React.ReactChild | undefined,
+ side?: string | undefined
+ ) => void;
+ http: CoreStart['http'];
+ tabCreatedTypes?: any;
+ searchBarConfigs?: any;
+ appId?: string;
+ addVisualizationToPanel?: any;
+ startTime?: string;
+ endTime?: string;
+ setStartTime?: any;
+ setEndTime?: any;
+ appBaseQuery?: string;
+ callback?: any;
+ callbackInApp?: any;
+}
+
+export interface SavedQuery {
+ description: string;
+ name: string;
+ query: string;
+ selected_date_range: { start: string; end: string; text: string };
+ selected_fields: { text: string; tokens: [{ name: string; type: string }] };
+ selected_timestamp: { name: string; type: string };
+}
+
+export interface SavedVisualization {
+ description: string;
+ name: string;
+ query: string;
+ selected_date_range: { start: string; end: string; text: string };
+ selected_fields: { text: string; tokens: [] };
+ selected_timestamp: { name: string; type: string };
+ type: string;
+ application_id?: string;
+}
+
+export interface SavedQueryRes {
+ createdTimeMs: number;
+ lastUpdatedTimeMs: number;
+ objectId: string;
+ savedQuery: SavedQuery;
+ tenant: string;
+}
+
+export interface SavedVizRes {
+ createdTimeMs: number;
+ lastUpdatedTimeMs: number;
+ objectId: string;
+ savedVisualization: SavedVisualization;
+ tenant: string;
+}
+
+export interface IVisualizationContainerPropsData {
+ appData?: { fromApp: boolean };
+ rawVizData?: any;
+ query?: IQuery;
+ indexFields?: IField[];
+ userConfigs?: any;
+ defaultAxes?: {
+ xaxis: IField[];
+ yaxis: IField[];
+ };
+}
+
+export interface IVisualizationContainerPropsVis {
+ vis: IVisualizationTypeDefination;
+}
+
+export interface IConfigPanelTab {
+ id: string;
+ name: string;
+ mapTo: string;
+ editor: React.ReactNode;
+ sections: IConfigPanelOptions[];
+ props?: any;
+}
+
+export interface IConfigPanelOptions {
+ id: string;
+ name: string;
+ mapTo: string;
+ editor: React.ReactNode;
+ schemas: IConfigPanelOptionSection[];
+}
+
+export interface IConfigPanelOptionSection {
+ name: string;
+ component: null;
+ mapTo: 'mode';
+ props?: any;
+ isSingleSelection?: boolean;
+}
+
+export interface IVisualizationTypeDefination {
+ name: string;
+ type: string;
+ id: string;
+ label: string;
+ fullLabel: string;
+ category: string;
+ icon: React.ReactNode;
+ editorConfig: {
+ panelTabs: IConfigPanelTab;
+ };
+ visConfig: {
+ layout: Partial;
+ config: Partial;
+ };
+ component: React.ReactNode;
+}
+
+export interface IVisualizationContainerProps {
+ data: IVisualizationContainerPropsData;
+ vis: IVisualizationContainerPropsVis;
+}
+
+export interface IDefaultTimestampState {
+ hasSchemaConflict: boolean;
+ default_timestamp: string;
+ message: string;
+}
+
+export interface LiveTailProps {
+ isLiveTailOn: boolean;
+ setIsLiveTailPopoverOpen: React.Dispatch>;
+ liveTailName: string;
+ isLiveTailPopoverOpen: boolean;
+ dataTestSubj: string;
+}
diff --git a/common/types/notebooks.ts b/common/types/notebooks.ts
new file mode 100644
index 0000000000..5c193ab5db
--- /dev/null
+++ b/common/types/notebooks.ts
@@ -0,0 +1,53 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { RefObject } from 'react';
+import { DashboardStart } from "../../../../src/plugins/dashboard/public";
+import { NavigationPublicPluginStart } from "../../../../src/plugins/navigation/public";
+
+export interface NotebooksPluginSetup {
+ getGreeting: () => string;
+}
+// eslint-disable-next-line @typescript-eslint/no-empty-interface
+export interface NotebooksPluginStart {}
+
+export interface optionsType {
+ baseUrl: string;
+ payload?: any;
+ headers?: any;
+ redirects?: number;
+ beforeRedirect?: any;
+ redirected?: any;
+ timeout?: number; // default: unlimited
+ maxBytes?: number; // default: unlimited
+ rejectUnauthorized?: boolean;
+ secureProtocol?: string; // The SSL method to use
+ ciphers?: string; // The TLS ciphers to support
+}
+
+export type ParaType = {
+ uniqueId: string;
+ isRunning: boolean;
+ inQueue: boolean;
+ isSelected: boolean;
+ isInputHidden: boolean;
+ isOutputHidden: boolean;
+ showAddPara: boolean;
+ isVizualisation: boolean;
+ vizObjectInput: string;
+ id: number;
+ inp: string;
+ lang: string;
+ editorLanguage: string;
+ typeOut: Array;
+ out: any[];
+ isInputExpanded: boolean;
+ isOutputStale: boolean;
+ paraRef: RefObject;
+ paraDivRef: RefObject;
+ visStartTime?: string;
+ visEndTime?: string;
+ visSavedObjId?: string;
+};
diff --git a/common/utils/index.ts b/common/utils/index.ts
new file mode 100644
index 0000000000..e5f765ccd0
--- /dev/null
+++ b/common/utils/index.ts
@@ -0,0 +1,7 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { getIndexPatternFromRawQuery, preprocessQuery, buildQuery } from './query_utils';
+export { uiSettingsService } from './settings_service';
diff --git a/common/utils/query_utils.ts b/common/utils/query_utils.ts
new file mode 100644
index 0000000000..985964d7b2
--- /dev/null
+++ b/common/utils/query_utils.ts
@@ -0,0 +1,68 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import datemath from '@elastic/datemath';
+import { isEmpty } from 'lodash';
+import { DATE_PICKER_FORMAT } from '../../common/constants/explorer';
+import {
+ PPL_INDEX_INSERT_POINT_REGEX,
+ PPL_INDEX_REGEX,
+ PPL_NEWLINE_REGEX,
+} from '../../common/constants/shared';
+
+export const getIndexPatternFromRawQuery = (query: string): string => {
+ const matches = query.match(PPL_INDEX_REGEX);
+ if (matches) {
+ return matches[2];
+ }
+ return '';
+};
+
+// insert time filter command and additional commands based on raw query
+export const preprocessQuery = ({
+ rawQuery,
+ startTime,
+ endTime,
+ timeField,
+ isLiveQuery,
+}: {
+ rawQuery: string;
+ startTime: string;
+ endTime: string;
+ timeField?: string;
+ isLiveQuery: boolean;
+}) => {
+ let finalQuery = '';
+
+ if (isEmpty(rawQuery)) return finalQuery;
+
+ // convert to moment
+ const start = datemath.parse(startTime)?.utc().format(DATE_PICKER_FORMAT);
+ const end = datemath.parse(endTime, { roundUp: true })?.utc().format(DATE_PICKER_FORMAT);
+ const tokens = rawQuery.replaceAll(PPL_NEWLINE_REGEX, '').match(PPL_INDEX_INSERT_POINT_REGEX);
+
+ if (isEmpty(tokens)) return finalQuery;
+
+ finalQuery = `${tokens![1]}=${
+ tokens![2]
+ } | where ${timeField} >= '${start}' and ${timeField} <= '${end}'${tokens![3]}`;
+ if (isLiveQuery) {
+ finalQuery = finalQuery + ` | sort - ${timeField}`;
+ }
+ return finalQuery;
+};
+
+export const buildQuery = (baseQuery: string, currQuery: string) => {
+ let fullQuery: string;
+ if (baseQuery) {
+ fullQuery = baseQuery;
+ if (currQuery) {
+ fullQuery += '| ' + currQuery;
+ }
+ } else {
+ fullQuery = currQuery;
+ }
+ return fullQuery;
+};
diff --git a/common/utils/settings_service.ts b/common/utils/settings_service.ts
new file mode 100644
index 0000000000..f22912127d
--- /dev/null
+++ b/common/utils/settings_service.ts
@@ -0,0 +1,25 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { IUiSettingsClient, NotificationsStart, ToastInput } from '../../../../src/core/public';
+
+let uiSettings: IUiSettingsClient;
+let notifications: NotificationsStart;
+
+export const uiSettingsService = {
+ init: (client: IUiSettingsClient, notificationsStart: NotificationsStart) => {
+ uiSettings = client;
+ notifications = notificationsStart;
+ },
+ get: (key: string, defaultOverride?: any) => {
+ return uiSettings?.get(key, defaultOverride) || '';
+ },
+ set: (key: string, value: any) => {
+ return uiSettings?.set(key, value) || Promise.reject("uiSettings client not initialized.");
+ },
+ addToast: (toast: ToastInput) => {
+ return notifications.toasts.add(toast);
+ }
+};
\ No newline at end of file
diff --git a/cypress.json b/cypress.json
new file mode 100644
index 0000000000..5de5badf68
--- /dev/null
+++ b/cypress.json
@@ -0,0 +1,21 @@
+{
+ "baseUrl": "http://localhost:5601",
+ "video": true,
+ "chromeWebSecurity": false,
+ "fixturesFolder": ".cypress/fixtures",
+ "integrationFolder": ".cypress/integration",
+ "pluginsFile": ".cypress/plugins/index.js",
+ "screenshotsFolder": ".cypress/screenshots",
+ "supportFile": ".cypress/support/index.js",
+ "videosFolder": ".cypress/videos",
+ "viewportWidth": 2000,
+ "viewportHeight": 1320,
+ "requestTimeout": 60000,
+ "responseTimeout": 60000,
+ "defaultCommandTimeout": 60000,
+ "env": {
+ "opensearch": "localhost:9200",
+ "opensearchDashboards": "localhost:5601",
+ "security_enabled": true
+ }
+}
diff --git a/opensearch-dashboards-plugin-helpers.dev.json b/opensearch-dashboards-plugin-helpers.dev.json
new file mode 100644
index 0000000000..23260a3b2e
--- /dev/null
+++ b/opensearch-dashboards-plugin-helpers.dev.json
@@ -0,0 +1,9 @@
+{
+ "serverSourcePatterns": [
+ "package.json",
+ "yarn.lock",
+ "tsconfig.json",
+ "{common,public,server,test}/**/*",
+ "!__tests__"
+ ]
+}
diff --git a/opensearch_dashboards.json b/opensearch_dashboards.json
new file mode 100644
index 0000000000..93a15121e5
--- /dev/null
+++ b/opensearch_dashboards.json
@@ -0,0 +1,19 @@
+{
+ "id": "observabilityDashboards",
+ "version": "1.3.4.0",
+ "opensearchDashboardsVersion": "1.3.4",
+ "server": true,
+ "ui": true,
+ "requiredPlugins": [
+ "charts",
+ "data",
+ "embeddable",
+ "inspector",
+ "urlForwarding",
+ "navigation",
+ "uiActions",
+ "dashboard",
+ "visualizations",
+ "opensearchDashboardsReact"
+ ]
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000000..d88a5ae5bc
--- /dev/null
+++ b/package.json
@@ -0,0 +1,44 @@
+{
+ "name": "observability-dashboards",
+ "version": "1.3.4.0",
+ "main": "index.ts",
+ "license": "Apache-2.0",
+ "scripts": {
+ "osd": "node ../../scripts/osd",
+ "build": "yarn plugin_helpers build",
+ "test": "../../node_modules/.bin/jest --config ./test/jest.config.js",
+ "cypress:run": "TZ=America/Los_Angeles cypress run",
+ "cypress:open": "TZ=America/Los_Angeles cypress open",
+ "plugin_helpers": "node ../../scripts/plugin_helpers"
+ },
+ "dependencies": {
+ "@algolia/autocomplete-core": "^1.4.1",
+ "@algolia/autocomplete-theme-classic": "^1.2.1",
+ "@nteract/outputs": "^3.0.11",
+ "@nteract/presentational-components": "^3.4.3",
+ "@reduxjs/toolkit": "^1.6.1",
+ "plotly.js-dist": "^2.2.0",
+ "react-graph-vis": "^1.0.5",
+ "react-plotly.js": "^2.5.1"
+ },
+ "devDependencies": {
+ "@types/enzyme-adapter-react-16": "^1.0.6",
+ "@types/react-plotly.js": "^2.5.0",
+ "@types/react-test-renderer": "^16.9.1",
+ "@cypress/skip-test": "^2.6.1",
+ "cypress": "^5.0.0",
+ "enzyme-adapter-react-16": "^1.15.2",
+ "eslint": "^6.8.0",
+ "jest-dom": "^4.0.0",
+ "performance-now": "^2.1.0"
+ },
+ "resolutions": {
+ "react-syntax-highlighter": "^15.4.3",
+ "prismjs": "^1.22.0",
+ "trim": "^1.0.0",
+ "lodash": "^4.17.21",
+ "glob-parent": "^6.0.1",
+ "ansi-regex": "^5.0.1",
+ "json-schema": "^0.4.0"
+ }
+}
diff --git a/public/components/app.tsx b/public/components/app.tsx
new file mode 100644
index 0000000000..36594b8900
--- /dev/null
+++ b/public/components/app.tsx
@@ -0,0 +1,139 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { I18nProvider } from '@osd/i18n/react';
+import React from 'react';
+import { Provider } from 'react-redux';
+import { HashRouter, Route, Switch } from 'react-router-dom';
+import { CoreStart } from '../../../../src/core/public';
+import { observabilityID, observabilityTitle } from '../../common/constants/shared';
+import store from '../framework/redux/store';
+import { AppPluginStartDependencies } from '../types';
+import { Home as ApplicationAnalyticsHome } from './application_analytics/home';
+import { Home as CustomPanelsHome } from './custom_panels/home';
+import { EventAnalytics } from './explorer/event_analytics';
+import { Main as NotebooksHome } from './notebooks/components/main';
+import { Home as TraceAnalyticsHome } from './trace_analytics/home';
+
+interface ObservabilityAppDeps {
+ CoreStartProp: CoreStart;
+ DepsStart: AppPluginStartDependencies;
+ pplService: any;
+ dslService: any;
+ savedObjects: any;
+ timestampUtils: any;
+}
+
+export const App = ({
+ CoreStartProp,
+ DepsStart,
+ pplService,
+ dslService,
+ savedObjects,
+ timestampUtils,
+}: ObservabilityAppDeps) => {
+ const { chrome, http, notifications } = CoreStartProp;
+ const parentBreadcrumb = {
+ text: observabilityTitle,
+ href: `${observabilityID}#/`,
+ };
+
+ const customPanelBreadcrumb = {
+ text: 'Operational panels',
+ href: '#/operational_panels/',
+ };
+
+ return (
+
+
+
+ <>
+
+ {
+ return (
+
+ );
+ }}
+ />
+ (
+
+ )}
+ />
+ {
+ chrome.setBreadcrumbs([parentBreadcrumb, customPanelBreadcrumb]);
+ return (
+
+ );
+ }}
+ />
+ (
+
+ )}
+ />
+ {
+ return (
+
+ );
+ }}
+ />
+
+ >
+
+
+
+ );
+};
diff --git a/public/components/application_analytics/__tests__/__snapshots__/create.test.tsx.snap b/public/components/application_analytics/__tests__/__snapshots__/create.test.tsx.snap
new file mode 100644
index 0000000000..079cdc1b18
--- /dev/null
+++ b/public/components/application_analytics/__tests__/__snapshots__/create.test.tsx.snap
@@ -0,0 +1,18907 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Create Page can clear query 1`] = `
+Object {
+ "asFragment": [Function],
+ "baseElement":
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Log source
+
+
+
+
+
+ Configure your application base query
+
+
+
+
+
+
+
+
+ Clear
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Services & entities
+
+
+
+ 0
+
+
+
+
+
+
+
+ Select services & entities to include in this application
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Service map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace groups
+
+
+
+ 0
+
+
+
+
+
+
+
+ Constrain your application to specific trace groups
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latency by trace group
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+ Create and Set Availability
+
+
+
+
+
+
+
+
+
+
+
+ ,
+ "container":
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Log source
+
+
+
+
+
+ Configure your application base query
+
+
+
+
+
+
+
+
+ Clear
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Services & entities
+
+
+
+ 0
+
+
+
+
+
+
+
+ Select services & entities to include in this application
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Service map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace groups
+
+
+
+ 0
+
+
+
+
+
+
+
+ Constrain your application to specific trace groups
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latency by trace group
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+ Create and Set Availability
+
+
+
+
+
+
+
+
+
+
,
+ "debug": [Function],
+ "findAllByAltText": [Function],
+ "findAllByDisplayValue": [Function],
+ "findAllByLabelText": [Function],
+ "findAllByPlaceholderText": [Function],
+ "findAllByRole": [Function],
+ "findAllByTestId": [Function],
+ "findAllByText": [Function],
+ "findAllByTitle": [Function],
+ "findByAltText": [Function],
+ "findByDisplayValue": [Function],
+ "findByLabelText": [Function],
+ "findByPlaceholderText": [Function],
+ "findByRole": [Function],
+ "findByTestId": [Function],
+ "findByText": [Function],
+ "findByTitle": [Function],
+ "getAllByAltText": [Function],
+ "getAllByDisplayValue": [Function],
+ "getAllByLabelText": [Function],
+ "getAllByPlaceholderText": [Function],
+ "getAllByRole": [Function],
+ "getAllByTestId": [Function],
+ "getAllByText": [Function],
+ "getAllByTitle": [Function],
+ "getByAltText": [Function],
+ "getByDisplayValue": [Function],
+ "getByLabelText": [Function],
+ "getByPlaceholderText": [Function],
+ "getByRole": [Function],
+ "getByTestId": [Function],
+ "getByText": [Function],
+ "getByTitle": [Function],
+ "queryAllByAltText": [Function],
+ "queryAllByDisplayValue": [Function],
+ "queryAllByLabelText": [Function],
+ "queryAllByPlaceholderText": [Function],
+ "queryAllByRole": [Function],
+ "queryAllByTestId": [Function],
+ "queryAllByText": [Function],
+ "queryAllByTitle": [Function],
+ "queryByAltText": [Function],
+ "queryByDisplayValue": [Function],
+ "queryByLabelText": [Function],
+ "queryByPlaceholderText": [Function],
+ "queryByRole": [Function],
+ "queryByTestId": [Function],
+ "queryByText": [Function],
+ "queryByTitle": [Function],
+ "rerender": [Function],
+ "unmount": [Function],
+}
+`;
+
+exports[`Create Page clears one trace selected 1`] = `
+Object {
+ "asFragment": [Function],
+ "baseElement":
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Log source
+
+
+
+
+
+ Configure your application base query
+
+
+
+
+
+
+
+
+ Clear
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Services & entities
+
+
+
+ 0
+
+
+
+
+
+
+
+ Select services & entities to include in this application
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Service map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace groups
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ Constrain your application to specific trace groups
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latency by trace group
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+ Create and Set Availability
+
+
+
+
+
+
+
+
+
+
+ ,
+ "container":
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Log source
+
+
+
+
+
+ Configure your application base query
+
+
+
+
+
+
+
+
+ Clear
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Services & entities
+
+
+
+ 0
+
+
+
+
+
+
+
+ Select services & entities to include in this application
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Service map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace groups
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ Constrain your application to specific trace groups
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latency by trace group
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+ Create and Set Availability
+
+
+
+
+
+
+
+
+
+
,
+ "debug": [Function],
+ "findAllByAltText": [Function],
+ "findAllByDisplayValue": [Function],
+ "findAllByLabelText": [Function],
+ "findAllByPlaceholderText": [Function],
+ "findAllByRole": [Function],
+ "findAllByTestId": [Function],
+ "findAllByText": [Function],
+ "findAllByTitle": [Function],
+ "findByAltText": [Function],
+ "findByDisplayValue": [Function],
+ "findByLabelText": [Function],
+ "findByPlaceholderText": [Function],
+ "findByRole": [Function],
+ "findByTestId": [Function],
+ "findByText": [Function],
+ "findByTitle": [Function],
+ "getAllByAltText": [Function],
+ "getAllByDisplayValue": [Function],
+ "getAllByLabelText": [Function],
+ "getAllByPlaceholderText": [Function],
+ "getAllByRole": [Function],
+ "getAllByTestId": [Function],
+ "getAllByText": [Function],
+ "getAllByTitle": [Function],
+ "getByAltText": [Function],
+ "getByDisplayValue": [Function],
+ "getByLabelText": [Function],
+ "getByPlaceholderText": [Function],
+ "getByRole": [Function],
+ "getByTestId": [Function],
+ "getByText": [Function],
+ "getByTitle": [Function],
+ "queryAllByAltText": [Function],
+ "queryAllByDisplayValue": [Function],
+ "queryAllByLabelText": [Function],
+ "queryAllByPlaceholderText": [Function],
+ "queryAllByRole": [Function],
+ "queryAllByTestId": [Function],
+ "queryAllByText": [Function],
+ "queryAllByTitle": [Function],
+ "queryByAltText": [Function],
+ "queryByDisplayValue": [Function],
+ "queryByLabelText": [Function],
+ "queryByPlaceholderText": [Function],
+ "queryByRole": [Function],
+ "queryByTestId": [Function],
+ "queryByText": [Function],
+ "queryByTitle": [Function],
+ "rerender": [Function],
+ "unmount": [Function],
+}
+`;
+
+exports[`Create Page clears service selected 1`] = `
+Object {
+ "asFragment": [Function],
+ "baseElement":
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Log source
+
+
+
+
+
+ Configure your application base query
+
+
+
+
+
+
+
+
+ Clear
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Services & entities
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ Select services & entities to include in this application
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Service map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace groups
+
+
+
+ 0
+
+
+
+
+
+
+
+ Constrain your application to specific trace groups
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latency by trace group
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+ Create and Set Availability
+
+
+
+
+
+
+
+
+
+
+ ,
+ "container":
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Log source
+
+
+
+
+
+ Configure your application base query
+
+
+
+
+
+
+
+
+ Clear
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Services & entities
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ Select services & entities to include in this application
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Service map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace groups
+
+
+
+ 0
+
+
+
+
+
+
+
+ Constrain your application to specific trace groups
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latency by trace group
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+ Create and Set Availability
+
+
+
+
+
+
+
+
+
+
,
+ "debug": [Function],
+ "findAllByAltText": [Function],
+ "findAllByDisplayValue": [Function],
+ "findAllByLabelText": [Function],
+ "findAllByPlaceholderText": [Function],
+ "findAllByRole": [Function],
+ "findAllByTestId": [Function],
+ "findAllByText": [Function],
+ "findAllByTitle": [Function],
+ "findByAltText": [Function],
+ "findByDisplayValue": [Function],
+ "findByLabelText": [Function],
+ "findByPlaceholderText": [Function],
+ "findByRole": [Function],
+ "findByTestId": [Function],
+ "findByText": [Function],
+ "findByTitle": [Function],
+ "getAllByAltText": [Function],
+ "getAllByDisplayValue": [Function],
+ "getAllByLabelText": [Function],
+ "getAllByPlaceholderText": [Function],
+ "getAllByRole": [Function],
+ "getAllByTestId": [Function],
+ "getAllByText": [Function],
+ "getAllByTitle": [Function],
+ "getByAltText": [Function],
+ "getByDisplayValue": [Function],
+ "getByLabelText": [Function],
+ "getByPlaceholderText": [Function],
+ "getByRole": [Function],
+ "getByTestId": [Function],
+ "getByText": [Function],
+ "getByTitle": [Function],
+ "queryAllByAltText": [Function],
+ "queryAllByDisplayValue": [Function],
+ "queryAllByLabelText": [Function],
+ "queryAllByPlaceholderText": [Function],
+ "queryAllByRole": [Function],
+ "queryAllByTestId": [Function],
+ "queryAllByText": [Function],
+ "queryAllByTitle": [Function],
+ "queryByAltText": [Function],
+ "queryByDisplayValue": [Function],
+ "queryByLabelText": [Function],
+ "queryByPlaceholderText": [Function],
+ "queryByRole": [Function],
+ "queryByTestId": [Function],
+ "queryByText": [Function],
+ "queryByTitle": [Function],
+ "rerender": [Function],
+ "unmount": [Function],
+}
+`;
+
+exports[`Create Page renders empty 1`] = `
+Object {
+ "asFragment": [Function],
+ "baseElement":
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Log source
+
+
+
+
+
+ Configure your application base query
+
+
+
+
+
+
+
+
+ Clear
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Services & entities
+
+
+
+ 0
+
+
+
+
+
+
+
+ Select services & entities to include in this application
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Service map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace groups
+
+
+
+ 0
+
+
+
+
+
+
+
+ Constrain your application to specific trace groups
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latency by trace group
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+ Create and Set Availability
+
+
+
+
+
+
+
+
+
+
+ ,
+ "container":
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Log source
+
+
+
+
+
+ Configure your application base query
+
+
+
+
+
+
+
+
+ Clear
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Services & entities
+
+
+
+ 0
+
+
+
+
+
+
+
+ Select services & entities to include in this application
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Service map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace groups
+
+
+
+ 0
+
+
+
+
+
+
+
+ Constrain your application to specific trace groups
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latency by trace group
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+ Create and Set Availability
+
+
+
+
+
+
+
+
+
+
,
+ "debug": [Function],
+ "findAllByAltText": [Function],
+ "findAllByDisplayValue": [Function],
+ "findAllByLabelText": [Function],
+ "findAllByPlaceholderText": [Function],
+ "findAllByRole": [Function],
+ "findAllByTestId": [Function],
+ "findAllByText": [Function],
+ "findAllByTitle": [Function],
+ "findByAltText": [Function],
+ "findByDisplayValue": [Function],
+ "findByLabelText": [Function],
+ "findByPlaceholderText": [Function],
+ "findByRole": [Function],
+ "findByTestId": [Function],
+ "findByText": [Function],
+ "findByTitle": [Function],
+ "getAllByAltText": [Function],
+ "getAllByDisplayValue": [Function],
+ "getAllByLabelText": [Function],
+ "getAllByPlaceholderText": [Function],
+ "getAllByRole": [Function],
+ "getAllByTestId": [Function],
+ "getAllByText": [Function],
+ "getAllByTitle": [Function],
+ "getByAltText": [Function],
+ "getByDisplayValue": [Function],
+ "getByLabelText": [Function],
+ "getByPlaceholderText": [Function],
+ "getByRole": [Function],
+ "getByTestId": [Function],
+ "getByText": [Function],
+ "getByTitle": [Function],
+ "queryAllByAltText": [Function],
+ "queryAllByDisplayValue": [Function],
+ "queryAllByLabelText": [Function],
+ "queryAllByPlaceholderText": [Function],
+ "queryAllByRole": [Function],
+ "queryAllByTestId": [Function],
+ "queryAllByText": [Function],
+ "queryAllByTitle": [Function],
+ "queryByAltText": [Function],
+ "queryByDisplayValue": [Function],
+ "queryByLabelText": [Function],
+ "queryByPlaceholderText": [Function],
+ "queryByRole": [Function],
+ "queryByTestId": [Function],
+ "queryByText": [Function],
+ "queryByTitle": [Function],
+ "rerender": [Function],
+ "unmount": [Function],
+}
+`;
+
+exports[`Create Page renders with name and description 1`] = `
+Object {
+ "asFragment": [Function],
+ "baseElement":
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Log source
+
+
+
+
+
+ Configure your application base query
+
+
+
+
+
+
+
+
+ Clear
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Services & entities
+
+
+
+ 0
+
+
+
+
+
+
+
+ Select services & entities to include in this application
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Service map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace groups
+
+
+
+ 0
+
+
+
+
+
+
+
+ Constrain your application to specific trace groups
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latency by trace group
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+ Create and Set Availability
+
+
+
+
+
+
+
+
+
+
+ ,
+ "container":
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Log source
+
+
+
+
+
+ Configure your application base query
+
+
+
+
+
+
+
+
+ Clear
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Services & entities
+
+
+
+ 0
+
+
+
+
+
+
+
+ Select services & entities to include in this application
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Service map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace groups
+
+
+
+ 0
+
+
+
+
+
+
+
+ Constrain your application to specific trace groups
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latency by trace group
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+ Create and Set Availability
+
+
+
+
+
+
+
+
+
+
,
+ "debug": [Function],
+ "findAllByAltText": [Function],
+ "findAllByDisplayValue": [Function],
+ "findAllByLabelText": [Function],
+ "findAllByPlaceholderText": [Function],
+ "findAllByRole": [Function],
+ "findAllByTestId": [Function],
+ "findAllByText": [Function],
+ "findAllByTitle": [Function],
+ "findByAltText": [Function],
+ "findByDisplayValue": [Function],
+ "findByLabelText": [Function],
+ "findByPlaceholderText": [Function],
+ "findByRole": [Function],
+ "findByTestId": [Function],
+ "findByText": [Function],
+ "findByTitle": [Function],
+ "getAllByAltText": [Function],
+ "getAllByDisplayValue": [Function],
+ "getAllByLabelText": [Function],
+ "getAllByPlaceholderText": [Function],
+ "getAllByRole": [Function],
+ "getAllByTestId": [Function],
+ "getAllByText": [Function],
+ "getAllByTitle": [Function],
+ "getByAltText": [Function],
+ "getByDisplayValue": [Function],
+ "getByLabelText": [Function],
+ "getByPlaceholderText": [Function],
+ "getByRole": [Function],
+ "getByTestId": [Function],
+ "getByText": [Function],
+ "getByTitle": [Function],
+ "queryAllByAltText": [Function],
+ "queryAllByDisplayValue": [Function],
+ "queryAllByLabelText": [Function],
+ "queryAllByPlaceholderText": [Function],
+ "queryAllByRole": [Function],
+ "queryAllByTestId": [Function],
+ "queryAllByText": [Function],
+ "queryAllByTitle": [Function],
+ "queryByAltText": [Function],
+ "queryByDisplayValue": [Function],
+ "queryByLabelText": [Function],
+ "queryByPlaceholderText": [Function],
+ "queryByRole": [Function],
+ "queryByTestId": [Function],
+ "queryByText": [Function],
+ "queryByTitle": [Function],
+ "rerender": [Function],
+ "unmount": [Function],
+}
+`;
+
+exports[`Create Page renders with one service selected 1`] = `
+Object {
+ "asFragment": [Function],
+ "baseElement":
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Log source
+
+
+
+
+
+ Configure your application base query
+
+
+
+
+
+
+
+
+ Clear
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Services & entities
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ Select services & entities to include in this application
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Service map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace groups
+
+
+
+ 0
+
+
+
+
+
+
+
+ Constrain your application to specific trace groups
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latency by trace group
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+ Create and Set Availability
+
+
+
+
+
+
+
+
+
+
+ ,
+ "container":
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Log source
+
+
+
+
+
+ Configure your application base query
+
+
+
+
+
+
+
+
+ Clear
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Services & entities
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ Select services & entities to include in this application
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Service map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace groups
+
+
+
+ 0
+
+
+
+
+
+
+
+ Constrain your application to specific trace groups
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latency by trace group
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+ Create and Set Availability
+
+
+
+
+
+
+
+
+
+
,
+ "debug": [Function],
+ "findAllByAltText": [Function],
+ "findAllByDisplayValue": [Function],
+ "findAllByLabelText": [Function],
+ "findAllByPlaceholderText": [Function],
+ "findAllByRole": [Function],
+ "findAllByTestId": [Function],
+ "findAllByText": [Function],
+ "findAllByTitle": [Function],
+ "findByAltText": [Function],
+ "findByDisplayValue": [Function],
+ "findByLabelText": [Function],
+ "findByPlaceholderText": [Function],
+ "findByRole": [Function],
+ "findByTestId": [Function],
+ "findByText": [Function],
+ "findByTitle": [Function],
+ "getAllByAltText": [Function],
+ "getAllByDisplayValue": [Function],
+ "getAllByLabelText": [Function],
+ "getAllByPlaceholderText": [Function],
+ "getAllByRole": [Function],
+ "getAllByTestId": [Function],
+ "getAllByText": [Function],
+ "getAllByTitle": [Function],
+ "getByAltText": [Function],
+ "getByDisplayValue": [Function],
+ "getByLabelText": [Function],
+ "getByPlaceholderText": [Function],
+ "getByRole": [Function],
+ "getByTestId": [Function],
+ "getByText": [Function],
+ "getByTitle": [Function],
+ "queryAllByAltText": [Function],
+ "queryAllByDisplayValue": [Function],
+ "queryAllByLabelText": [Function],
+ "queryAllByPlaceholderText": [Function],
+ "queryAllByRole": [Function],
+ "queryAllByTestId": [Function],
+ "queryAllByText": [Function],
+ "queryAllByTitle": [Function],
+ "queryByAltText": [Function],
+ "queryByDisplayValue": [Function],
+ "queryByLabelText": [Function],
+ "queryByPlaceholderText": [Function],
+ "queryByRole": [Function],
+ "queryByTestId": [Function],
+ "queryByText": [Function],
+ "queryByTitle": [Function],
+ "rerender": [Function],
+ "unmount": [Function],
+}
+`;
+
+exports[`Create Page renders with one trace selected 1`] = `
+Object {
+ "asFragment": [Function],
+ "baseElement":
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Log source
+
+
+
+
+
+ Configure your application base query
+
+
+
+
+
+
+
+
+ Clear
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Services & entities
+
+
+
+ 0
+
+
+
+
+
+
+
+ Select services & entities to include in this application
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Service map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace groups
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ Constrain your application to specific trace groups
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latency by trace group
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+ Create and Set Availability
+
+
+
+
+
+
+
+
+
+
+ ,
+ "container":
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Log source
+
+
+
+
+
+ Configure your application base query
+
+
+
+
+
+
+
+
+ Clear
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Services & entities
+
+
+
+ 0
+
+
+
+
+
+
+
+ Select services & entities to include in this application
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Service map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace groups
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ Constrain your application to specific trace groups
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latency by trace group
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+ Create and Set Availability
+
+
+
+
+
+
+
+
+
+
,
+ "debug": [Function],
+ "findAllByAltText": [Function],
+ "findAllByDisplayValue": [Function],
+ "findAllByLabelText": [Function],
+ "findAllByPlaceholderText": [Function],
+ "findAllByRole": [Function],
+ "findAllByTestId": [Function],
+ "findAllByText": [Function],
+ "findAllByTitle": [Function],
+ "findByAltText": [Function],
+ "findByDisplayValue": [Function],
+ "findByLabelText": [Function],
+ "findByPlaceholderText": [Function],
+ "findByRole": [Function],
+ "findByTestId": [Function],
+ "findByText": [Function],
+ "findByTitle": [Function],
+ "getAllByAltText": [Function],
+ "getAllByDisplayValue": [Function],
+ "getAllByLabelText": [Function],
+ "getAllByPlaceholderText": [Function],
+ "getAllByRole": [Function],
+ "getAllByTestId": [Function],
+ "getAllByText": [Function],
+ "getAllByTitle": [Function],
+ "getByAltText": [Function],
+ "getByDisplayValue": [Function],
+ "getByLabelText": [Function],
+ "getByPlaceholderText": [Function],
+ "getByRole": [Function],
+ "getByTestId": [Function],
+ "getByText": [Function],
+ "getByTitle": [Function],
+ "queryAllByAltText": [Function],
+ "queryAllByDisplayValue": [Function],
+ "queryAllByLabelText": [Function],
+ "queryAllByPlaceholderText": [Function],
+ "queryAllByRole": [Function],
+ "queryAllByTestId": [Function],
+ "queryAllByText": [Function],
+ "queryAllByTitle": [Function],
+ "queryByAltText": [Function],
+ "queryByDisplayValue": [Function],
+ "queryByLabelText": [Function],
+ "queryByPlaceholderText": [Function],
+ "queryByRole": [Function],
+ "queryByTestId": [Function],
+ "queryByText": [Function],
+ "queryByTitle": [Function],
+ "rerender": [Function],
+ "unmount": [Function],
+}
+`;
+
+exports[`Create Page renders with query 1`] = `
+Object {
+ "asFragment": [Function],
+ "baseElement":
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Log source
+
+
+
+
+
+ Configure your application base query
+
+
+
+
+
+
+
+
+ Clear
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Services & entities
+
+
+
+ 0
+
+
+
+
+
+
+
+ Select services & entities to include in this application
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Service map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace groups
+
+
+
+ 0
+
+
+
+
+
+
+
+ Constrain your application to specific trace groups
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latency by trace group
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+ Create and Set Availability
+
+
+
+
+
+
+
+
+
+
+
+ ,
+ "container":
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Log source
+
+
+
+
+
+ Configure your application base query
+
+
+
+
+
+
+
+
+ Clear
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Services & entities
+
+
+
+ 0
+
+
+
+
+
+
+
+ Select services & entities to include in this application
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Service map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace groups
+
+
+
+ 0
+
+
+
+
+
+
+
+ Constrain your application to specific trace groups
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latency by trace group
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No matches
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+ Create and Set Availability
+
+
+
+
+
+
+
+
+
+
,
+ "debug": [Function],
+ "findAllByAltText": [Function],
+ "findAllByDisplayValue": [Function],
+ "findAllByLabelText": [Function],
+ "findAllByPlaceholderText": [Function],
+ "findAllByRole": [Function],
+ "findAllByTestId": [Function],
+ "findAllByText": [Function],
+ "findAllByTitle": [Function],
+ "findByAltText": [Function],
+ "findByDisplayValue": [Function],
+ "findByLabelText": [Function],
+ "findByPlaceholderText": [Function],
+ "findByRole": [Function],
+ "findByTestId": [Function],
+ "findByText": [Function],
+ "findByTitle": [Function],
+ "getAllByAltText": [Function],
+ "getAllByDisplayValue": [Function],
+ "getAllByLabelText": [Function],
+ "getAllByPlaceholderText": [Function],
+ "getAllByRole": [Function],
+ "getAllByTestId": [Function],
+ "getAllByText": [Function],
+ "getAllByTitle": [Function],
+ "getByAltText": [Function],
+ "getByDisplayValue": [Function],
+ "getByLabelText": [Function],
+ "getByPlaceholderText": [Function],
+ "getByRole": [Function],
+ "getByTestId": [Function],
+ "getByText": [Function],
+ "getByTitle": [Function],
+ "queryAllByAltText": [Function],
+ "queryAllByDisplayValue": [Function],
+ "queryAllByLabelText": [Function],
+ "queryAllByPlaceholderText": [Function],
+ "queryAllByRole": [Function],
+ "queryAllByTestId": [Function],
+ "queryAllByText": [Function],
+ "queryAllByTitle": [Function],
+ "queryByAltText": [Function],
+ "queryByDisplayValue": [Function],
+ "queryByLabelText": [Function],
+ "queryByPlaceholderText": [Function],
+ "queryByRole": [Function],
+ "queryByTestId": [Function],
+ "queryByText": [Function],
+ "queryByTitle": [Function],
+ "rerender": [Function],
+ "unmount": [Function],
+}
+`;
diff --git a/public/components/application_analytics/__tests__/__snapshots__/log_config.test.tsx.snap b/public/components/application_analytics/__tests__/__snapshots__/log_config.test.tsx.snap
new file mode 100644
index 0000000000..f5bdb4cac2
--- /dev/null
+++ b/public/components/application_analytics/__tests__/__snapshots__/log_config.test.tsx.snap
@@ -0,0 +1,966 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Log Config component renders empty log config 1`] = `
+
+
+
+
+
+ Log source
+
+
+
+
+ Configure your application base query
+
+
+ }
+ data-test-subj="logSourceAccordion"
+ extraAction={
+
+ Clear
+
+ }
+ id="logSource"
+ initialIsOpen={false}
+ isLoading={false}
+ isLoadingMessage={false}
+ onToggle={[Function]}
+ paddingSize="l"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Log source
+
+
+
+
+
+
+
+
+
+
+ Configure your application base query
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Clear
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ You can't change the base query after the application is created.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Base Query
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PPL
+
+
+
+
+
+
+
+
+
+ The default logs view in the application will be filtered by this query.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Log Config component renders with query 1`] = `
+
+
+
+
+
+ Log source
+
+
+
+
+ Configure your application base query
+
+
+ }
+ data-test-subj="logSourceAccordion"
+ extraAction={
+
+ Clear
+
+ }
+ id="logSource"
+ initialIsOpen={false}
+ isLoading={false}
+ isLoadingMessage={false}
+ onToggle={[Function]}
+ paddingSize="l"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Log source
+
+
+
+
+
+
+
+
+
+
+ Configure your application base query
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Clear
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ You can't change the base query after the application is created.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Base Query
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PPL
+
+
+
+
+
+
+
+
+
+ The default logs view in the application will be filtered by this query.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/application_analytics/__tests__/__snapshots__/service_config.test.tsx.snap b/public/components/application_analytics/__tests__/__snapshots__/service_config.test.tsx.snap
new file mode 100644
index 0000000000..8ffca27abb
--- /dev/null
+++ b/public/components/application_analytics/__tests__/__snapshots__/service_config.test.tsx.snap
@@ -0,0 +1,2157 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Service Config component renders empty service config 1`] = `
+
+
+
+
+
+ Services & entities
+
+
+ 0
+
+
+
+
+
+ Select services & entities to include in this application
+
+
+ }
+ data-test-subj="servicesEntitiesAccordion"
+ extraAction={
+
+ Clear all
+
+ }
+ id="servicesEntities"
+ initialIsOpen={false}
+ isLoading={false}
+ isLoadingMessage={false}
+ onToggle={[Function]}
+ paddingSize="l"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Services & entities
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Select services & entities to include in this application
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Services & entities
+
+
+
+
+
+
+
+
+
+
+
+
+ Select services and entities
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Service map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+ }
+ title={
+
+ No matches
+
+ }
+ >
+
+
+
+
+
+ No matches
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Service Config component renders with one service selected 1`] = `
+
+
+
+
+
+ Services & entities
+
+
+ 0
+
+
+
+
+
+ Select services & entities to include in this application
+
+
+ }
+ data-test-subj="servicesEntitiesAccordion"
+ extraAction={
+
+ Clear all
+
+ }
+ id="servicesEntities"
+ initialIsOpen={false}
+ isLoading={false}
+ isLoadingMessage={false}
+ onToggle={[Function]}
+ paddingSize="l"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Services & entities
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Select services & entities to include in this application
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Services & entities
+
+
+
+
+
+
+
+
+
+
+
+
+ Select services and entities
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Service map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+ }
+ title={
+
+ No matches
+
+ }
+ >
+
+
+
+
+
+ No matches
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/application_analytics/__tests__/__snapshots__/trace_config.test.tsx.snap b/public/components/application_analytics/__tests__/__snapshots__/trace_config.test.tsx.snap
new file mode 100644
index 0000000000..395900132d
--- /dev/null
+++ b/public/components/application_analytics/__tests__/__snapshots__/trace_config.test.tsx.snap
@@ -0,0 +1,1587 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Trace Config component renders empty trace config 1`] = `
+
+
+
+
+
+ Trace groups
+
+
+ 0
+
+
+
+
+
+ Constrain your application to specific trace groups
+
+
+ }
+ data-test-subj="traceGroupsAccordion"
+ extraAction={
+
+ Clear all
+
+ }
+ id="traceGroups"
+ initialIsOpen={false}
+ isLoading={false}
+ isLoadingMessage={false}
+ onToggle={[Function]}
+ paddingSize="l"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace groups
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Constrain your application to specific trace groups
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace Groups
+
+
+
+
+
+
+
+
+
+
+
+
+ Select or add trace groups
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Select one or multiple trace groups, or type a custom one
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latency by trace group
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ □
+
+ < 95 percentile
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ■
+
+ >= 95 percentile
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+ }
+ title={
+
+ No matches
+
+ }
+ >
+
+
+
+
+
+ No matches
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Trace Config component renders with one trace selected 1`] = `
+
+
+
+
+
+ Trace groups
+
+
+ 0
+
+
+
+
+
+ Constrain your application to specific trace groups
+
+
+ }
+ data-test-subj="traceGroupsAccordion"
+ extraAction={
+
+ Clear all
+
+ }
+ id="traceGroups"
+ initialIsOpen={false}
+ isLoading={false}
+ isLoadingMessage={false}
+ onToggle={[Function]}
+ paddingSize="l"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace groups
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Constrain your application to specific trace groups
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Clear all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace Groups
+
+
+
+
+
+
+
+
+
+
+
+
+ Select or add trace groups
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Select one or multiple trace groups, or type a custom one
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latency by trace group
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ □
+
+ < 95 percentile
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ■
+
+ >= 95 percentile
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+ }
+ title={
+
+ No matches
+
+ }
+ >
+
+
+
+
+
+ No matches
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/application_analytics/__tests__/create.test.tsx b/public/components/application_analytics/__tests__/create.test.tsx
new file mode 100644
index 0000000000..5fda0c03a8
--- /dev/null
+++ b/public/components/application_analytics/__tests__/create.test.tsx
@@ -0,0 +1,583 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { configure } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import { CreateApp } from '../components/create';
+import { coreStartMock } from '../../../../test/__mocks__/coreMocks';
+import DSLService from 'public/services/requests/dsl';
+import PPLService from 'public/services/requests/ppl';
+import { render } from '@testing-library/react';
+
+describe('Create Page', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders empty', () => {
+ const core = coreStartMock;
+ const setQuery = jest.fn();
+ const setFilters = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const setNameWithStorage = jest.fn();
+ const setDescriptionWithStorage = jest.fn();
+ const setQueryWithStorage = jest.fn();
+ const setFiltersWithStorage = jest.fn();
+ const createApp = jest.fn();
+ const setToasts = jest.fn();
+ const updateApp = jest.fn();
+ const clearStorage = jest.fn();
+ const setAppConfigs = jest.fn();
+ const setStartTimeWithStorage = jest.fn();
+ const setEndTimeWithStorage = jest.fn();
+ const dslService = ({
+ http: jest.fn(),
+ fetch: jest.fn(),
+ fetchIndices: jest.fn(),
+ fetchFields: jest.fn(),
+ } as unknown) as DSLService;
+ const pplService = ({
+ http: jest.fn(),
+ fetch: jest.fn(),
+ } as unknown) as PPLService;
+ const utils = render(
+
+ );
+
+ expect(utils).toMatchSnapshot();
+ });
+
+ it('renders with name and description', () => {
+ const core = coreStartMock;
+ const setQuery = jest.fn();
+ const setFilters = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const setNameWithStorage = jest.fn();
+ const setDescriptionWithStorage = jest.fn();
+ const setQueryWithStorage = jest.fn();
+ const setFiltersWithStorage = jest.fn();
+ const createApp = jest.fn();
+ const setToasts = jest.fn();
+ const updateApp = jest.fn();
+ const clearStorage = jest.fn();
+ const setAppConfigs = jest.fn();
+ const setStartTimeWithStorage = jest.fn();
+ const setEndTimeWithStorage = jest.fn();
+ const dslService = ({
+ http: jest.fn(),
+ fetch: jest.fn(),
+ fetchIndices: jest.fn(),
+ fetchFields: jest.fn(),
+ } as unknown) as DSLService;
+ const pplService = ({
+ http: jest.fn(),
+ fetch: jest.fn(),
+ } as unknown) as PPLService;
+ const utils = render(
+
+ );
+
+ expect(utils).toMatchSnapshot();
+ });
+
+ it('renders with query', () => {
+ const core = coreStartMock;
+ const setQuery = jest.fn();
+ const setFilters = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const setNameWithStorage = jest.fn();
+ const setDescriptionWithStorage = jest.fn();
+ const setQueryWithStorage = jest.fn();
+ const setFiltersWithStorage = jest.fn();
+ const createApp = jest.fn();
+ const setToasts = jest.fn();
+ const updateApp = jest.fn();
+ const clearStorage = jest.fn();
+ const setAppConfigs = jest.fn();
+ const setStartTimeWithStorage = jest.fn();
+ const setEndTimeWithStorage = jest.fn();
+ const dslService = ({
+ http: jest.fn(),
+ fetch: jest.fn(),
+ fetchIndices: jest.fn(),
+ fetchFields: jest.fn(),
+ } as unknown) as DSLService;
+ const pplService = ({
+ http: jest.fn(),
+ fetch: jest.fn(),
+ } as unknown) as PPLService;
+ const utils = render(
+
+ );
+ utils.getByText('Log source').click();
+ utils.getByText('Clear').click();
+ utils.getByText('Cancel').click();
+
+ expect(utils).toMatchSnapshot();
+ });
+
+ it('can clear query', () => {
+ const core = coreStartMock;
+ const setQuery = jest.fn();
+ const setFilters = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const setNameWithStorage = jest.fn();
+ const setDescriptionWithStorage = jest.fn();
+ const setQueryWithStorage = jest.fn();
+ const setFiltersWithStorage = jest.fn();
+ const createApp = jest.fn();
+ const setToasts = jest.fn();
+ const updateApp = jest.fn();
+ const clearStorage = jest.fn();
+ const setAppConfigs = jest.fn();
+ const setStartTimeWithStorage = jest.fn();
+ const setEndTimeWithStorage = jest.fn();
+ const dslService = ({
+ http: jest.fn(),
+ fetch: jest.fn(),
+ fetchIndices: jest.fn(),
+ fetchFields: jest.fn(),
+ } as unknown) as DSLService;
+ const pplService = ({
+ http: jest.fn(),
+ fetch: jest.fn(),
+ } as unknown) as PPLService;
+ const utils = render(
+
+ );
+ utils.getByText('Log source').click();
+ utils.getByText('Clear').click();
+ utils.getByText('Clear').click();
+
+ expect(utils).toMatchSnapshot();
+ });
+
+ it('renders with one service selected', () => {
+ const core = coreStartMock;
+ const setQuery = jest.fn();
+ const setFilters = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const setNameWithStorage = jest.fn();
+ const setDescriptionWithStorage = jest.fn();
+ const setQueryWithStorage = jest.fn();
+ const setFiltersWithStorage = jest.fn();
+ const createApp = jest.fn();
+ const setToasts = jest.fn();
+ const updateApp = jest.fn();
+ const clearStorage = jest.fn();
+ const setAppConfigs = jest.fn();
+ const setStartTimeWithStorage = jest.fn();
+ const setEndTimeWithStorage = jest.fn();
+ const dslService = ({
+ http: jest.fn(),
+ fetch: jest.fn(),
+ fetchIndices: jest.fn(),
+ fetchFields: jest.fn(),
+ } as unknown) as DSLService;
+ const pplService = ({
+ http: jest.fn(),
+ fetch: jest.fn(),
+ } as unknown) as PPLService;
+ const serviceFilters = [
+ {
+ field: 'serviceName',
+ operator: 'is',
+ value: 'User',
+ inverted: false,
+ disabled: false,
+ },
+ ];
+ const utils = render(
+
+ );
+ utils.getByText('Select services & entities to include in this application').click();
+ utils.getByText('Clear').click();
+ utils.getByText('Cancel').click();
+
+ expect(utils).toMatchSnapshot();
+ });
+
+ it('clears service selected', () => {
+ const core = coreStartMock;
+ const setQuery = jest.fn();
+ const setFilters = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const setNameWithStorage = jest.fn();
+ const setDescriptionWithStorage = jest.fn();
+ const setQueryWithStorage = jest.fn();
+ const setFiltersWithStorage = jest.fn();
+ const createApp = jest.fn();
+ const setToasts = jest.fn();
+ const updateApp = jest.fn();
+ const clearStorage = jest.fn();
+ const setAppConfigs = jest.fn();
+ const setStartTimeWithStorage = jest.fn();
+ const setEndTimeWithStorage = jest.fn();
+ const dslService = ({
+ http: jest.fn(),
+ fetch: jest.fn(),
+ fetchIndices: jest.fn(),
+ fetchFields: jest.fn(),
+ } as unknown) as DSLService;
+ const pplService = ({
+ http: jest.fn(),
+ fetch: jest.fn(),
+ } as unknown) as PPLService;
+ const serviceFilters = [
+ {
+ field: 'serviceName',
+ operator: 'is',
+ value: 'User',
+ inverted: false,
+ disabled: false,
+ },
+ ];
+ const utils = render(
+
+ );
+ utils.getByText('Select services & entities to include in this application').click();
+ utils.getByText('Clear').click();
+ utils.getByText('Clear').click();
+
+ expect(utils).toMatchSnapshot();
+ });
+
+ it('renders with one trace selected', () => {
+ const core = coreStartMock;
+ const setQuery = jest.fn();
+ const setFilters = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const setNameWithStorage = jest.fn();
+ const setDescriptionWithStorage = jest.fn();
+ const setQueryWithStorage = jest.fn();
+ const setFiltersWithStorage = jest.fn();
+ const createApp = jest.fn();
+ const setToasts = jest.fn();
+ const updateApp = jest.fn();
+ const clearStorage = jest.fn();
+ const setAppConfigs = jest.fn();
+ const setStartTimeWithStorage = jest.fn();
+ const setEndTimeWithStorage = jest.fn();
+ const dslService = ({
+ http: jest.fn(),
+ fetch: jest.fn(),
+ fetchIndices: jest.fn(),
+ fetchFields: jest.fn(),
+ } as unknown) as DSLService;
+ const pplService = ({
+ http: jest.fn(),
+ fetch: jest.fn(),
+ } as unknown) as PPLService;
+ const traceFilters = [
+ {
+ field: 'traceGroup',
+ operator: 'is',
+ value: 'test.auto',
+ inverted: false,
+ disabled: false,
+ },
+ ];
+ const utils = render(
+
+ );
+ utils.getByText('Constrain your application to specific trace groups').click();
+ utils.getByText('Clear').click();
+ utils.getByText('Cancel').click();
+
+ expect(utils).toMatchSnapshot();
+ });
+
+ it('clears one trace selected', () => {
+ const core = coreStartMock;
+ const setQuery = jest.fn();
+ const setFilters = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const setNameWithStorage = jest.fn();
+ const setDescriptionWithStorage = jest.fn();
+ const setQueryWithStorage = jest.fn();
+ const setFiltersWithStorage = jest.fn();
+ const createApp = jest.fn();
+ const setToasts = jest.fn();
+ const updateApp = jest.fn();
+ const clearStorage = jest.fn();
+ const setAppConfigs = jest.fn();
+ const setStartTimeWithStorage = jest.fn();
+ const setEndTimeWithStorage = jest.fn();
+ const dslService = ({
+ http: jest.fn(),
+ fetch: jest.fn(),
+ fetchIndices: jest.fn(),
+ fetchFields: jest.fn(),
+ } as unknown) as DSLService;
+ const pplService = ({
+ http: jest.fn(),
+ fetch: jest.fn(),
+ } as unknown) as PPLService;
+ const traceFilters = [
+ {
+ field: 'traceGroup',
+ operator: 'is',
+ value: 'test.auto',
+ inverted: false,
+ disabled: false,
+ },
+ ];
+ const utils = render(
+
+ );
+ utils.getByText('Constrain your application to specific trace groups').click();
+ utils.getByText('Clear').click();
+ utils.getByText('Clear').click();
+
+ expect(utils).toMatchSnapshot();
+ });
+});
diff --git a/public/components/application_analytics/__tests__/log_config.test.tsx b/public/components/application_analytics/__tests__/log_config.test.tsx
new file mode 100644
index 0000000000..f1d0781d81
--- /dev/null
+++ b/public/components/application_analytics/__tests__/log_config.test.tsx
@@ -0,0 +1,121 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import { LogConfig } from '../components/config_components/log_config';
+import { coreStartMock } from '../../../../test/__mocks__/coreMocks';
+import DSLService from 'public/services/requests/dsl';
+
+describe('Log Config component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders empty log config', () => {
+ const core = coreStartMock;
+ const setQuery = jest.fn();
+ const setFilters = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const setIsFlyoutVisible = jest.fn();
+ const setNameWithStorage = jest.fn();
+ const setDescriptionWithStorage = jest.fn();
+ const setQueryWithStorage = jest.fn();
+ const setFiltersWithStorage = jest.fn();
+ const setAppConfigs = jest.fn();
+ const setStartTimeWithStorage = jest.fn();
+ const setEndTimeWithStorage = jest.fn();
+ const dslService = ({
+ http: jest.fn(),
+ fetch: jest.fn(),
+ fetchIndices: jest.fn(),
+ fetchFields: jest.fn(),
+ } as unknown) as DSLService;
+ const wrapper = mount(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it('renders with query', () => {
+ const core = coreStartMock;
+ const setQuery = jest.fn();
+ const setFilters = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const setIsFlyoutVisible = jest.fn();
+ const setNameWithStorage = jest.fn();
+ const setDescriptionWithStorage = jest.fn();
+ const setQueryWithStorage = jest.fn();
+ const setFiltersWithStorage = jest.fn();
+ const setAppConfigs = jest.fn();
+ const setStartTimeWithStorage = jest.fn();
+ const setEndTimeWithStorage = jest.fn();
+ const dslService = ({
+ http: jest.fn(),
+ fetch: jest.fn(),
+ fetchIndices: jest.fn(),
+ fetchFields: jest.fn(),
+ } as unknown) as DSLService;
+ const wrapper = mount(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+});
diff --git a/public/components/application_analytics/__tests__/service_config.test.tsx b/public/components/application_analytics/__tests__/service_config.test.tsx
new file mode 100644
index 0000000000..d574ba9427
--- /dev/null
+++ b/public/components/application_analytics/__tests__/service_config.test.tsx
@@ -0,0 +1,130 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import { ServiceConfig } from '../components/config_components/service_config';
+import { coreStartMock } from '../../../../test/__mocks__/coreMocks';
+import DSLService from 'public/services/requests/dsl';
+
+describe('Service Config component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders empty service config', () => {
+ const core = coreStartMock;
+ const setQuery = jest.fn();
+ const setFilters = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const setSelectedServices = jest.fn();
+ const setNameWithStorage = jest.fn();
+ const setDescriptionWithStorage = jest.fn();
+ const setQueryWithStorage = jest.fn();
+ const setFiltersWithStorage = jest.fn();
+ const setAppConfigs = jest.fn();
+ const setStartTimeWithStorage = jest.fn();
+ const setEndTimeWithStorage = jest.fn();
+ const dslService = ({
+ http: jest.fn(),
+ fetch: jest.fn(),
+ fetchIndices: jest.fn(),
+ fetchFields: jest.fn(),
+ } as unknown) as DSLService;
+ const wrapper = mount(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it('renders with one service selected', () => {
+ const core = coreStartMock;
+ const setQuery = jest.fn();
+ const setFilters = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const setSelectedServices = jest.fn();
+ const setNameWithStorage = jest.fn();
+ const setDescriptionWithStorage = jest.fn();
+ const setQueryWithStorage = jest.fn();
+ const setFiltersWithStorage = jest.fn();
+ const setAppConfigs = jest.fn();
+ const setStartTimeWithStorage = jest.fn();
+ const setEndTimeWithStorage = jest.fn();
+ const dslService = ({
+ http: jest.fn(),
+ fetch: jest.fn(),
+ fetchIndices: jest.fn(),
+ fetchFields: jest.fn(),
+ } as unknown) as DSLService;
+ const serviceFilter = [
+ {
+ field: 'serviceName',
+ operator: 'is',
+ value: 'User',
+ inverted: false,
+ disabled: false,
+ },
+ ];
+ const wrapper = mount(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+});
diff --git a/public/components/application_analytics/__tests__/trace_config.test.tsx b/public/components/application_analytics/__tests__/trace_config.test.tsx
new file mode 100644
index 0000000000..10a524fe2a
--- /dev/null
+++ b/public/components/application_analytics/__tests__/trace_config.test.tsx
@@ -0,0 +1,116 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import { TraceConfig } from '../components/config_components/trace_config';
+import { coreStartMock } from '../../../../test/__mocks__/coreMocks';
+import DSLService from 'public/services/requests/dsl';
+
+describe('Trace Config component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders empty trace config', () => {
+ const core = coreStartMock;
+ const setQuery = jest.fn();
+ const setFilters = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const setSelectedTraces = jest.fn();
+ const setNameWithStorage = jest.fn();
+ const setDescriptionWithStorage = jest.fn();
+ const setQueryWithStorage = jest.fn();
+ const setFiltersWithStorage = jest.fn();
+ const dslService = ({
+ http: jest.fn(),
+ fetch: jest.fn(),
+ fetchIndices: jest.fn(),
+ fetchFields: jest.fn(),
+ } as unknown) as DSLService;
+ const wrapper = mount(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it('renders with one trace selected', () => {
+ const core = coreStartMock;
+ const setQuery = jest.fn();
+ const setFilters = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const setSelectedTraces = jest.fn();
+ const setNameWithStorage = jest.fn();
+ const setDescriptionWithStorage = jest.fn();
+ const setQueryWithStorage = jest.fn();
+ const setFiltersWithStorage = jest.fn();
+ const dslService = ({
+ http: jest.fn(),
+ fetch: jest.fn(),
+ fetchIndices: jest.fn(),
+ fetchFields: jest.fn(),
+ } as unknown) as DSLService;
+ const traceFilter = [
+ {
+ field: 'traceGroup',
+ operator: 'is',
+ value: 'test.auto',
+ inverted: false,
+ disabled: false,
+ },
+ ];
+ const wrapper = mount(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+});
diff --git a/public/components/application_analytics/app_analytics.scss b/public/components/application_analytics/app_analytics.scss
new file mode 100644
index 0000000000..ad05f65448
--- /dev/null
+++ b/public/components/application_analytics/app_analytics.scss
@@ -0,0 +1,29 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+.query-area {
+ width: 900px;
+}
+
+#logSource {
+ overflow: visible;
+ position: relative;
+ z-index: 10;
+ .ppl-link {
+ top: 103px;
+ right: 140px;
+ }
+}
+
+#baseQueryCallout {
+ max-width: 900px;
+}
+
+#compositionColumn {
+ width: 300px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+}
diff --git a/public/components/application_analytics/components/app_table.tsx b/public/components/application_analytics/components/app_table.tsx
new file mode 100644
index 0000000000..75fe228af8
--- /dev/null
+++ b/public/components/application_analytics/components/app_table.tsx
@@ -0,0 +1,344 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable react-hooks/exhaustive-deps */
+
+import '../app_analytics.scss';
+import {
+ EuiBadge,
+ EuiButton,
+ EuiContextMenuItem,
+ EuiContextMenuPanel,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiHorizontalRule,
+ EuiInMemoryTable,
+ EuiLink,
+ EuiLoadingSpinner,
+ EuiOverlayMask,
+ EuiPage,
+ EuiPageBody,
+ EuiPageContent,
+ EuiPageContentHeader,
+ EuiPageContentHeaderSection,
+ EuiPageHeader,
+ EuiPageHeaderSection,
+ EuiPopover,
+ EuiSpacer,
+ EuiTableFieldDataColumnType,
+ EuiText,
+ EuiTitle,
+ EuiToolTip,
+} from '@elastic/eui';
+import _ from 'lodash';
+import React, { ReactElement, useEffect, useState } from 'react';
+import moment from 'moment';
+import { DeleteModal } from '../../common/helpers/delete_modal';
+import { AppAnalyticsComponentDeps } from '../home';
+import { getCustomModal } from '../../custom_panels/helpers/modal_containers';
+import { pageStyles, UI_DATE_FORMAT } from '../../../../common/constants/shared';
+import { ApplicationType, AvailabilityType } from '../../../../common/types/application_analytics';
+
+interface AppTableProps extends AppAnalyticsComponentDeps {
+ loading: boolean;
+ applications: ApplicationType[];
+ fetchApplications: () => void;
+ renameApplication: (newAppName: string, appId: string) => void;
+ deleteApplication: (appList: string[], panelIdList: string[], toastMessage?: string) => void;
+ clearStorage: () => void;
+ moveToApp: (id: string, type: string) => void;
+}
+
+export function AppTable(props: AppTableProps) {
+ const {
+ chrome,
+ applications,
+ parentBreadcrumbs,
+ fetchApplications,
+ renameApplication,
+ deleteApplication,
+ setFilters,
+ clearStorage,
+ moveToApp,
+ } = props;
+ const [isModalVisible, setIsModalVisible] = useState(false);
+ const [isActionsPopoverOpen, setIsActionsPopoverOpen] = useState(false);
+ const [modalLayout, setModalLayout] = useState( );
+ const [selectedApplications, setSelectedApplications] = useState([]);
+ const createButtonText = 'Create application';
+
+ useEffect(() => {
+ chrome.setBreadcrumbs([
+ ...parentBreadcrumbs,
+ {
+ text: 'Application analytics',
+ href: '#/application_analytics',
+ },
+ ]);
+ clear();
+ fetchApplications();
+ }, []);
+
+ const clear = () => {
+ setFilters([]);
+ clearStorage();
+ };
+
+ const closeModal = () => {
+ setIsModalVisible(false);
+ };
+
+ const showModal = () => {
+ setIsModalVisible(true);
+ };
+
+ const onRename = async (newApplicationName: string) => {
+ renameApplication(newApplicationName, selectedApplications[0].id);
+ closeModal();
+ };
+
+ const onDelete = async () => {
+ closeModal();
+ const toastMessage = `Application${
+ selectedApplications.length > 1 ? 's' : ' "' + selectedApplications[0].name + '"'
+ } successfully deleted!`;
+ await deleteApplication(
+ selectedApplications.map((app) => app.id),
+ selectedApplications.map((app) => app.panelId),
+ toastMessage
+ );
+ };
+
+ const renameApp = () => {
+ setModalLayout(
+ getCustomModal(
+ onRename,
+ closeModal,
+ 'Name',
+ 'Rename application',
+ 'Cancel',
+ 'Rename',
+ selectedApplications[0].name
+ )
+ );
+ showModal();
+ };
+
+ const deleteApp = () => {
+ const applicationString = `application${selectedApplications.length > 1 ? 's' : ''}`;
+ setModalLayout(
+
+ );
+ showModal();
+ };
+
+ const popoverButton = (
+ setIsActionsPopoverOpen(!isActionsPopoverOpen)}
+ >
+ Actions
+
+ );
+
+ const popoverItems: ReactElement[] = [
+ {
+ setIsActionsPopoverOpen(false);
+ renameApp();
+ }}
+ >
+ Rename
+ ,
+ //
+ // Duplicate
+ // ,
+ {
+ setIsActionsPopoverOpen(false);
+ deleteApp();
+ }}
+ >
+ Delete
+ ,
+ // Add sample application ,
+ ];
+
+ const renderAvailability = (value: AvailabilityType, record: ApplicationType) => {
+ if (value.color === 'loading') {
+ return ;
+ } else if (value.name) {
+ return (
+
+ {value.name}
+
+ );
+ } else if (value.color === 'undefined') {
+ return No match ;
+ } else if (value.color === 'null') {
+ return - ;
+ } else {
+ return (
+ moveToApp(record.id, 'createSetAvailability')}
+ >
+ Set Availability
+
+ );
+ }
+ };
+
+ const tableColumns = [
+ {
+ field: 'name',
+ name: 'Name',
+ sortable: true,
+ truncateText: true,
+ render: (value, record) => (
+
+ {_.truncate(record.name, { length: 100 })}
+
+ ),
+ },
+ {
+ field: 'composition',
+ name: 'Composition',
+ sortable: false,
+ truncateText: true,
+ render: (value, record) => (
+
+
+ {record.servicesEntities.concat(record.traceGroups).join(', ')}
+
+
+ ),
+ },
+ {
+ field: 'availability',
+ name: 'Current Availability',
+ sortable: true,
+ render: renderAvailability,
+ },
+ {
+ field: 'dateModified',
+ name: 'Date Modified',
+ sortable: true,
+ render: (value) => {moment(value).format(UI_DATE_FORMAT)} ,
+ },
+ ] as Array>;
+
+ return (
+
+
+
+
+
+
+ Overview
+
+
+
+
+
+
+
+
+ Applications ({applications.length})
+
+
+
+
+
+
+ setIsActionsPopoverOpen(false)}
+ >
+
+
+
+
+
+ {createButtonText}
+
+
+
+
+
+
+ {applications.length > 0 ? (
+ setSelectedApplications(items),
+ }}
+ />
+ ) : (
+ <>
+
+
+ No applications
+
+
+
+
+
+ {createButtonText}
+
+
+ {/*
+ Add sample applications
+ */}
+
+
+ >
+ )}
+
+
+
+ {isModalVisible && modalLayout}
+
+ );
+}
diff --git a/public/components/application_analytics/components/application.tsx b/public/components/application_analytics/components/application.tsx
new file mode 100644
index 0000000000..97816ea886
--- /dev/null
+++ b/public/components/application_analytics/components/application.tsx
@@ -0,0 +1,576 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable react-hooks/exhaustive-deps */
+/* eslint-disable no-console */
+
+import {
+ EuiHorizontalRule,
+ EuiPage,
+ EuiPageBody,
+ EuiPageHeader,
+ EuiPageHeaderSection,
+ EuiPanel,
+ EuiSelectOption,
+ EuiSpacer,
+ EuiTabbedContent,
+ EuiTabbedContentTab,
+ EuiText,
+ EuiTitle,
+} from '@elastic/eui';
+import DSLService from 'public/services/requests/dsl';
+import PPLService from 'public/services/requests/ppl';
+import SavedObjects from 'public/services/saved_objects/event_analytics/saved_objects';
+import TimestampUtils from 'public/services/timestamp/timestamp';
+import React, { ReactChild, useEffect, useState } from 'react';
+import { useHistory } from 'react-router-dom';
+import { useDispatch } from 'react-redux';
+import { last } from 'lodash';
+import { VisualizationType } from 'common/types/custom_panels';
+import { TracesContent } from '../../../components/trace_analytics/components/traces/traces_content';
+import { DashboardContent } from '../../../components/trace_analytics/components/dashboard/dashboard_content';
+import { ServicesContent } from '../../trace_analytics/components/services/services_content';
+import {
+ filtersToDsl,
+ PanelTitle,
+} from '../../../../public/components/trace_analytics/components/common/helper_functions';
+import { SpanDetailTable } from '../../../../public/components/trace_analytics/components/traces/span_detail_table';
+import { Explorer } from '../../explorer/explorer';
+import { Configuration } from './configuration';
+import {
+ TAB_CONFIG_ID,
+ TAB_CONFIG_TITLE,
+ TAB_LOG_ID,
+ TAB_LOG_TITLE,
+ TAB_OVERVIEW_ID,
+ TAB_OVERVIEW_TITLE,
+ TAB_PANEL_ID,
+ TAB_PANEL_TITLE,
+ TAB_SERVICE_ID,
+ TAB_SERVICE_TITLE,
+ TAB_TRACE_ID,
+ TAB_TRACE_TITLE,
+} from '../../../../common/constants/application_analytics';
+import { TAB_EVENT_ID, TAB_CHART_ID, NEW_TAB } from '../../../../common/constants/explorer';
+import { IQueryTab } from '../../../../common/types/explorer';
+import { NotificationsStart } from '../../../../../../src/core/public';
+import { AppAnalyticsComponentDeps } from '../home';
+import { CustomPanelView } from '../../../../public/components/custom_panels/custom_panel_view';
+import {
+ ApplicationRequestType,
+ ApplicationType,
+} from '../../../../common/types/application_analytics';
+import { CUSTOM_PANELS_API_PREFIX } from '../../../../common/constants/custom_panels';
+import { ServiceDetailFlyout } from './flyout_components/service_detail_flyout';
+import { SpanDetailFlyout } from '../../../../public/components/trace_analytics/components/traces/span_detail_flyout';
+import { TraceDetailFlyout } from './flyout_components/trace_detail_flyout';
+import { fetchAppById, initializeTabData } from '../helpers/utils';
+
+const searchBarConfigs = {
+ [TAB_EVENT_ID]: {
+ showSaveButton: false,
+ showSavePanelOptionsList: false,
+ },
+ [TAB_CHART_ID]: {
+ showSaveButton: true,
+ showSavePanelOptionsList: false,
+ },
+};
+
+interface AppDetailProps extends AppAnalyticsComponentDeps {
+ disabled?: boolean;
+ appId: string;
+ pplService: PPLService;
+ dslService: DSLService;
+ savedObjects: SavedObjects;
+ timestampUtils: TimestampUtils;
+ notifications: NotificationsStart;
+ updateApp: (appId: string, updateAppData: Partial, type: string) => void;
+ setToasts: (title: string, color?: string, text?: ReactChild) => void;
+ callback: (childfunction: () => void) => void;
+}
+
+export function Application(props: AppDetailProps) {
+ const {
+ pplService,
+ dslService,
+ timestampUtils,
+ savedObjects,
+ http,
+ notifications,
+ appId,
+ chrome,
+ parentBreadcrumbs,
+ query,
+ filters,
+ appConfigs,
+ updateApp,
+ setAppConfigs,
+ setToasts,
+ setFilters,
+ callback,
+ } = props;
+ const [application, setApplication] = useState({
+ id: '',
+ dateCreated: '',
+ dateModified: '',
+ name: '',
+ description: '',
+ baseQuery: '',
+ servicesEntities: [],
+ traceGroups: [],
+ panelId: '',
+ availability: { name: '', color: '', availabilityVisId: '' },
+ });
+ const dispatch = useDispatch();
+ const [triggerAvailability, setTriggerAvailability] = useState(false);
+ const [selectedTabId, setSelectedTab] = useState(TAB_OVERVIEW_ID);
+ const [serviceFlyoutName, setServiceFlyoutName] = useState('');
+ const [traceFlyoutId, setTraceFlyoutId] = useState('');
+ const [spanFlyoutId, setSpanFlyoutId] = useState('');
+ const [spanDSL, setSpanDSL] = useState({});
+ const [totalSpans, setTotalSpans] = useState(0);
+ const [editVizId, setEditVizId] = useState('');
+ const [visWithAvailability, setVisWithAvailability] = useState([]);
+ const handleContentTabClick = (selectedTab: IQueryTab) => setSelectedTab(selectedTab.id);
+ const [appStartTime, setAppStartTime] = useState(
+ sessionStorage.getItem(`${application.name}StartTime`) || 'now-24h'
+ );
+ const [appEndTime, setAppEndTime] = useState(
+ sessionStorage.getItem(`${application.name}EndTime`) || 'now'
+ );
+
+ const history = useHistory();
+
+ const setStartTimeForApp = (newStartTime: string) => {
+ setAppStartTime(newStartTime);
+ sessionStorage.setItem(`${application.name}StartTime`, newStartTime);
+ };
+ const setEndTimeForApp = (newEndTime: string) => {
+ setAppEndTime(newEndTime);
+ sessionStorage.setItem(`${application.name}EndTime`, newEndTime);
+ };
+
+ const addSpanFilter = (field: string, value: any) => {
+ const newFilters = [...filters];
+ const index = newFilters.findIndex(({ field: filterField }) => field === filterField);
+ if (index === -1) {
+ newFilters.push({ field, operator: 'is', value, inverted: false, disabled: false });
+ } else {
+ newFilters.splice(index, 1, {
+ field,
+ operator: 'is',
+ value,
+ inverted: false,
+ disabled: false,
+ });
+ }
+ setFilters(newFilters);
+ };
+
+ // Add visualization to application's panel
+ const addVisualizationToPanel = async (visualizationId: string, visualizationName: string) => {
+ return http
+ .post(`${CUSTOM_PANELS_API_PREFIX}/visualizations`, {
+ body: JSON.stringify({
+ panelId: application.panelId,
+ savedVisualizationId: visualizationId,
+ }),
+ })
+ .then(() => {
+ fetchAppById(
+ http,
+ pplService,
+ appId,
+ setApplication,
+ setAppConfigs,
+ setVisWithAvailability,
+ setToasts
+ );
+ })
+ .catch((err) => {
+ setToasts(`Error in adding ${visualizationName} visualization to the panel`, 'danger');
+ console.error(err);
+ });
+ };
+
+ useEffect(() => {
+ fetchAppById(
+ http,
+ pplService,
+ appId,
+ setApplication,
+ setAppConfigs,
+ setVisWithAvailability,
+ setToasts
+ );
+ const tabId = `application-analytics-tab-${appId}`;
+ initializeTabData(dispatch, tabId, NEW_TAB);
+ callback(switchToEvent);
+ }, [appId]);
+
+ useEffect(() => {
+ chrome.setBreadcrumbs([
+ ...parentBreadcrumbs,
+ {
+ text: 'Application analytics',
+ href: '#/application_analytics',
+ },
+ {
+ text: application.name,
+ href: `${last(parentBreadcrumbs)!.href}application_analytics/${appId}`,
+ },
+ ]);
+ setStartTimeForApp(sessionStorage.getItem(`${application.name}StartTime`) || 'now-24h');
+ setEndTimeForApp(sessionStorage.getItem(`${application.name}EndTime`) || 'now');
+ }, [appId, application.name]);
+
+ useEffect(() => {
+ const DSL = filtersToDsl(filters, query, appStartTime, appEndTime, 'app', appConfigs);
+ setSpanDSL(DSL);
+ }, [filters, appConfigs, query, appStartTime, appEndTime]);
+
+ useEffect(() => {
+ if (selectedTabId !== TAB_LOG_ID) {
+ switchToEditViz('');
+ }
+ }, [selectedTabId]);
+
+ const openServiceFlyout = (serviceName: string) => {
+ setSpanFlyoutId('');
+ setTraceFlyoutId('');
+ setServiceFlyoutName(serviceName);
+ };
+
+ const closeServiceFlyout = () => {
+ setServiceFlyoutName('');
+ };
+
+ const openSpanFlyout = (spanId: string) => {
+ setServiceFlyoutName('');
+ setTraceFlyoutId('');
+ setSpanFlyoutId(spanId);
+ };
+
+ const closeSpanFlyout = () => {
+ setSpanFlyoutId('');
+ };
+
+ const openTraceFlyout = (traceId: string) => {
+ setServiceFlyoutName('');
+ setSpanFlyoutId('');
+ setTraceFlyoutId(traceId);
+ };
+
+ const closeTraceFlyout = () => {
+ setTraceFlyoutId('');
+ };
+
+ const childBreadcrumbs = [
+ {
+ text: 'Application analytics',
+ href: '#/application_analytics',
+ },
+ {
+ text: `${application.name}`,
+ href: `#/application_analytics/${appId}`,
+ },
+ ];
+
+ const getOverview = () => {
+ return (
+ <>
+
+
+ >
+ );
+ };
+
+ const nameColumnAction = (item: any) => openServiceFlyout(item);
+ const traceColumnAction = () => switchToTrace();
+
+ const getService = () => {
+ return (
+ <>
+
+
+ >
+ );
+ };
+
+ const switchToTrace = () => {
+ setSelectedTab(TAB_TRACE_ID);
+ };
+
+ const traceIdColumnAction = (item: any) => openTraceFlyout(item);
+
+ const getTrace = () => {
+ return (
+ <>
+
+
+
+
+
+
+
+
+ >
+ );
+ };
+
+ const getLog = () => {
+ return (
+
+ );
+ };
+
+ const onEditClick = (savedVisualizationId: string) => {
+ switchToEditViz(savedVisualizationId);
+ };
+
+ const updateAvailabilityVizId = (vizs: VisualizationType[]) => {
+ if (
+ !vizs
+ .map((viz) => viz.savedVisualizationId)
+ .includes(application.availability.availabilityVisId)
+ ) {
+ updateApp(appId, { availabilityVisId: '' }, 'editAvailability');
+ }
+ };
+
+ const getPanel = () => {
+ return (
+ undefined}
+ cloneCustomPanel={async () => Promise.reject()}
+ deleteCustomPanel={async () => Promise.reject()}
+ setToast={setToasts}
+ page="app"
+ appId={appId}
+ updateAvailabilityVizId={updateAvailabilityVizId}
+ startTime={appStartTime}
+ endTime={appEndTime}
+ setStartTime={setStartTimeForApp}
+ setEndTime={setEndTimeForApp}
+ onAddClick={switchToEvent}
+ onEditClick={onEditClick}
+ />
+ );
+ };
+
+ const switchToEvent = () => {
+ setSelectedTab(TAB_LOG_ID);
+ };
+
+ const switchToEditViz = (savedVizId: string) => {
+ if (savedVizId) {
+ setEditVizId(savedVizId);
+ switchToEvent();
+ } else {
+ setEditVizId('');
+ }
+ };
+
+ const switchToAvailability = () => {
+ switchToEvent();
+ setTriggerAvailability(true);
+ };
+
+ const callbackInApp = (childFunc: () => void) => {
+ if (childFunc && triggerAvailability) {
+ childFunc();
+ setTriggerAvailability(false);
+ }
+ };
+
+ const getConfig = () => {
+ return (
+
+ );
+ };
+
+ function getAppAnalyticsTab({
+ tabId,
+ tabTitle,
+ getContent,
+ }: {
+ tabId: string;
+ tabTitle: string;
+ getContent: () => JSX.Element;
+ }) {
+ return {
+ id: tabId,
+ name: (
+ <>
+
+ {tabTitle}
+
+ >
+ ),
+ content: <>{getContent()}>,
+ };
+ }
+
+ const appAnalyticsTabs = [
+ getAppAnalyticsTab({
+ tabId: TAB_OVERVIEW_ID,
+ tabTitle: TAB_OVERVIEW_TITLE,
+ getContent: () => getOverview(),
+ }),
+ getAppAnalyticsTab({
+ tabId: TAB_SERVICE_ID,
+ tabTitle: TAB_SERVICE_TITLE,
+ getContent: () => getService(),
+ }),
+ getAppAnalyticsTab({
+ tabId: TAB_TRACE_ID,
+ tabTitle: TAB_TRACE_TITLE,
+ getContent: () => getTrace(),
+ }),
+ getAppAnalyticsTab({
+ tabId: TAB_LOG_ID,
+ tabTitle: TAB_LOG_TITLE,
+ getContent: () => getLog(),
+ }),
+ getAppAnalyticsTab({
+ tabId: TAB_PANEL_ID,
+ tabTitle: TAB_PANEL_TITLE,
+ getContent: () => getPanel(),
+ }),
+ getAppAnalyticsTab({
+ tabId: TAB_CONFIG_ID,
+ tabTitle: TAB_CONFIG_TITLE,
+ getContent: () => getConfig(),
+ }),
+ ];
+
+ return (
+
+
+
+
+
+
+ {application.name}
+
+
+ {application.description}
+
+
+
+ {
+ return tab.id === selectedTabId;
+ })}
+ onTabClick={(selectedTab: EuiTabbedContentTab) => handleContentTabClick(selectedTab)}
+ tabs={appAnalyticsTabs}
+ />
+
+ {serviceFlyoutName && (
+
+ )}
+ {spanFlyoutId && (
+
+ )}
+ {traceFlyoutId && (
+
+ )}
+
+
+ );
+}
diff --git a/public/components/application_analytics/components/config_components/log_config.tsx b/public/components/application_analytics/components/config_components/log_config.tsx
new file mode 100644
index 0000000000..fd0371bbdf
--- /dev/null
+++ b/public/components/application_analytics/components/config_components/log_config.tsx
@@ -0,0 +1,167 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ EuiAccordion,
+ EuiText,
+ EuiSpacer,
+ EuiButton,
+ EuiFormRow,
+ EuiFlexItem,
+ EuiBadge,
+ EuiOverlayMask,
+ EuiCallOut,
+ EuiFlexGroup,
+} from '@elastic/eui';
+import DSLService from 'public/services/requests/dsl';
+import React, { useState } from 'react';
+import {
+ parseGetSuggestions,
+ onItemSelect,
+} from '../../../../../public/components/common/search/autocomplete_logic';
+import { uiSettingsService } from '../../../../../common/utils';
+import { Autocomplete } from '../../../common/search/autocomplete';
+import { AppAnalyticsComponentDeps } from '../../home';
+import { getClearModal } from '../../helpers/modal_containers';
+import '../../app_analytics.scss';
+
+interface LogConfigProps extends AppAnalyticsComponentDeps {
+ dslService: DSLService;
+ setIsFlyoutVisible: any;
+ editMode: boolean;
+}
+
+export const LogConfig = (props: LogConfigProps) => {
+ const { dslService, query, setQueryWithStorage, setIsFlyoutVisible, editMode } = props;
+ const [logOpen, setLogOpen] = useState(false);
+ const [isModalVisible, setIsModalVisible] = useState(false);
+ const [modalLayout, setModalLayout] = useState( );
+ const [tempQuery, setTempQuery] = useState('');
+
+ const handleQueryChange = async (newQuery: string) => {
+ setTempQuery(newQuery);
+ setQueryWithStorage(newQuery);
+ };
+
+ const showFlyout = () => {
+ setIsFlyoutVisible(true);
+ };
+
+ const onCancel = () => {
+ setIsModalVisible(false);
+ };
+
+ const closeModal = () => {
+ setIsModalVisible(false);
+ };
+
+ const showModal = () => {
+ setIsModalVisible(true);
+ };
+
+ const onConfirm = () => {
+ handleQueryChange('');
+ closeModal();
+ };
+
+ const clearAllModal = () => {
+ setModalLayout(
+ getClearModal(
+ onCancel,
+ onConfirm,
+ 'Clear log source?',
+ 'This will clear all information in log source configuration.',
+ 'Clear'
+ )
+ );
+ showModal();
+ };
+
+ const allowedCommands = [
+ { label: 'dedup' },
+ { label: 'eval' },
+ { label: 'fields' },
+ { label: 'parse' },
+ { label: 'rename' },
+ { label: 'sort' },
+ { label: 'where' },
+ ];
+
+ return (
+
+
+
+ Log source
+
+
+
+ Configure your application base query
+
+ >
+ }
+ extraAction={
+
+ Clear
+
+ }
+ onToggle={(isOpen) => {
+ setLogOpen(isOpen);
+ }}
+ paddingSize="l"
+ >
+
+
+
+ You can't change the base query after the application is created.
+
+
+
+
+
+ {}}
+ dslService={dslService}
+ getSuggestions={parseGetSuggestions}
+ onItemSelect={onItemSelect}
+ isDisabled={editMode}
+ tabId={'application-analytics-tab'}
+ possibleCommands={allowedCommands}
+ />
+
+ PPL
+
+
+
+
+
+
+ {isModalVisible && modalLayout}
+
+ );
+};
diff --git a/public/components/application_analytics/components/config_components/service_config.tsx b/public/components/application_analytics/components/config_components/service_config.tsx
new file mode 100644
index 0000000000..30b78adcdc
--- /dev/null
+++ b/public/components/application_analytics/components/config_components/service_config.tsx
@@ -0,0 +1,193 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable react-hooks/exhaustive-deps */
+
+import {
+ EuiAccordion,
+ EuiBadge,
+ EuiButton,
+ EuiComboBox,
+ EuiFormRow,
+ EuiOverlayMask,
+ EuiSpacer,
+ EuiText,
+} from '@elastic/eui';
+import DSLService from 'public/services/requests/dsl';
+import React, { useState } from 'react';
+import { useEffect } from 'react';
+import { FilterType } from '../../../trace_analytics/components/common/filters/filters';
+import { ServiceObject } from '../../../trace_analytics/components/common/plots/service_map';
+import { ServiceMap } from '../../../trace_analytics/components/services';
+import { handleServiceMapRequest } from '../../../trace_analytics/requests/services_request_handler';
+import { AppAnalyticsComponentDeps } from '../../home';
+import { OptionType } from '../../../../../common/types/application_analytics';
+import { getClearModal } from '../../helpers/modal_containers';
+
+interface ServiceConfigProps extends AppAnalyticsComponentDeps {
+ dslService: DSLService;
+ selectedServices: OptionType[];
+ setSelectedServices: (services: OptionType[]) => void;
+}
+
+export const ServiceConfig = (props: ServiceConfigProps) => {
+ const {
+ dslService,
+ filters,
+ setFiltersWithStorage,
+ http,
+ selectedServices,
+ setSelectedServices,
+ } = props;
+ const [servicesOpen, setServicesOpen] = useState(false);
+ const [serviceMap, setServiceMap] = useState({});
+ const [serviceMapIdSelected, setServiceMapIdSelected] = useState<
+ 'latency' | 'error_rate' | 'throughput'
+ >('latency');
+ const [isModalVisible, setIsModalVisible] = useState(false);
+ const [modalLayout, setModalLayout] = useState( );
+
+ useEffect(() => {
+ handleServiceMapRequest(http, dslService, setServiceMap);
+ }, []);
+
+ useEffect(() => {
+ const serviceOptions = filters
+ .filter((f) => f.field === 'serviceName')
+ .map((f) => {
+ return { label: f.value };
+ });
+ const noDups = serviceOptions.filter((s, index) => {
+ return serviceOptions.findIndex((ser) => ser.label === s.label) === index;
+ });
+ setSelectedServices(noDups);
+ }, [filters]);
+
+ const addFilter = (filter: FilterType) => {
+ for (const addedFilter of filters) {
+ if (
+ addedFilter.field === filter.field &&
+ addedFilter.operator === filter.operator &&
+ addedFilter.value === filter.value
+ ) {
+ return;
+ }
+ }
+ const newFilters = [...filters, filter];
+ setFiltersWithStorage(newFilters);
+ };
+
+ const onServiceChange = (newServices: any) => {
+ const serviceFilters = newServices.map((option: OptionType) => {
+ return {
+ field: 'serviceName',
+ operator: 'is',
+ value: option.label,
+ inverted: false,
+ disabled: false,
+ };
+ });
+ const nonServiceFilters = filters.filter((f) => f.field !== 'serviceName');
+ setFiltersWithStorage([...nonServiceFilters, ...serviceFilters]);
+ };
+
+ const clearServices = () => {
+ const withoutServices = filters.filter((f) => f.field !== 'serviceName');
+ setFiltersWithStorage(withoutServices);
+ };
+
+ const services = Object.keys(serviceMap).map((service) => {
+ return { label: decodeURI(service) };
+ });
+
+ const onCancel = () => {
+ setIsModalVisible(false);
+ };
+
+ const closeModal = () => {
+ setIsModalVisible(false);
+ };
+
+ const showModal = () => {
+ setIsModalVisible(true);
+ };
+
+ const onConfirm = () => {
+ clearServices();
+ closeModal();
+ };
+
+ const clearAllModal = () => {
+ setModalLayout(
+ getClearModal(
+ onCancel,
+ onConfirm,
+ 'Clear services & entities?',
+ 'This will clear all information in services & entities configuration.',
+ 'Clear all'
+ )
+ );
+ showModal();
+ };
+
+ return (
+
+
+
+
+ Services & entities{' '}
+
+ {selectedServices.length}
+
+
+
+
+
+ Select services & entities to include in this application
+
+ >
+ }
+ extraAction={
+
+ Clear all
+
+ }
+ onToggle={(isOpen) => {
+ setServicesOpen(isOpen);
+ }}
+ paddingSize="l"
+ >
+
+
+
+
+
+
+ {isModalVisible && modalLayout}
+
+ );
+};
diff --git a/public/components/application_analytics/components/config_components/trace_config.tsx b/public/components/application_analytics/components/config_components/trace_config.tsx
new file mode 100644
index 0000000000..e0ff9a1bb1
--- /dev/null
+++ b/public/components/application_analytics/components/config_components/trace_config.tsx
@@ -0,0 +1,274 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable react-hooks/exhaustive-deps */
+
+import dateMath from '@elastic/datemath';
+import {
+ EuiAccordion,
+ EuiBadge,
+ EuiButton,
+ EuiComboBox,
+ EuiFormRow,
+ EuiOverlayMask,
+ EuiSpacer,
+ EuiText,
+} from '@elastic/eui';
+import DSLService from 'public/services/requests/dsl';
+import React, { useEffect, useState } from 'react';
+import { FilterType } from 'public/components/trace_analytics/components/common/filters/filters';
+import { OptionType } from '../../../../../common/types/application_analytics';
+import { filtersToDsl } from '../../../trace_analytics/components/common/helper_functions';
+import { handleDashboardRequest } from '../../../trace_analytics/requests/dashboard_request_handler';
+import { AppAnalyticsComponentDeps } from '../../home';
+import { DashboardTable } from '../../../trace_analytics/components/dashboard/dashboard_table';
+import { getClearModal } from '../../helpers/modal_containers';
+
+interface TraceConfigProps extends AppAnalyticsComponentDeps {
+ dslService: DSLService;
+ selectedTraces: OptionType[];
+ setSelectedTraces: (traces: OptionType[]) => void;
+}
+
+export const TraceConfig = (props: TraceConfigProps) => {
+ const {
+ dslService,
+ query,
+ filters,
+ setFiltersWithStorage,
+ http,
+ startTime,
+ endTime,
+ selectedTraces,
+ setSelectedTraces,
+ } = props;
+ const [traceOpen, setTraceOpen] = useState(false);
+ const [loading, setLoading] = useState(false);
+ const [traceItems, setTraceItems] = useState([]);
+ const [traceOptions, setTraceOptions] = useState([]);
+ const [percentileMap, setPercentileMap] = useState<{ [traceGroup: string]: number[] }>({});
+ const [redirect, setRedirect] = useState(true);
+ const [isModalVisible, setIsModalVisible] = useState(false);
+ const [modalLayout, setModalLayout] = useState( );
+
+ useEffect(() => {
+ setLoading(true);
+ const timeFilterDSL = filtersToDsl([], '', startTime, endTime);
+ const latencyTrendStartTime = dateMath.parse(endTime)?.subtract(24, 'hours').toISOString()!;
+ const latencyTrendDSL = filtersToDsl(filters, query, latencyTrendStartTime, endTime);
+ handleDashboardRequest(
+ http,
+ dslService,
+ timeFilterDSL,
+ latencyTrendDSL,
+ traceItems,
+ setTraceItems,
+ setPercentileMap
+ ).then(() => setLoading(false));
+ setRedirect(false);
+ }, []);
+
+ useEffect(() => {
+ const toOptions = traceItems.map((item: any) => {
+ return { label: decodeURI(item.dashboard_trace_group_name) };
+ });
+ setTraceOptions(toOptions);
+ }, [traceItems]);
+
+ useEffect(() => {
+ const filteredOptions = filters
+ .filter((f) => f.field === 'traceGroup')
+ .map((f) => {
+ return { label: f.value };
+ });
+ const noDups = filteredOptions.filter((t, index) => {
+ return filteredOptions.findIndex((trace) => trace.label === t.label) === index;
+ });
+ setSelectedTraces(noDups);
+ }, [filters]);
+
+ const addFilter = (filter: FilterType) => {
+ for (const addedFilter of filters) {
+ if (
+ addedFilter.field === filter.field &&
+ addedFilter.operator === filter.operator &&
+ addedFilter.value === filter.value
+ ) {
+ const removed = filters.filter((fil) => fil.field !== addedFilter.field);
+ setFiltersWithStorage(removed);
+ return;
+ }
+ }
+ const newFilters = [...filters, filter];
+ setFiltersWithStorage(newFilters);
+ };
+
+ const onTraceChange = (newTraces: any) => {
+ const traceFilters = newTraces.map((option: OptionType) => {
+ return {
+ field: 'traceGroup',
+ operator: 'is',
+ value: option.label,
+ inverted: false,
+ disabled: false,
+ };
+ });
+ const nonTraceFilters = filters.filter((f) => f.field !== 'traceGroup');
+ setFiltersWithStorage([...nonTraceFilters, ...traceFilters]);
+ };
+
+ const onCreateTrace = (searchValue: string, flattenedOptions: any) => {
+ const normalizedSearchValue = searchValue.trim().toLowerCase();
+ if (!normalizedSearchValue) {
+ return;
+ }
+ const newTraceOption = {
+ label: searchValue,
+ };
+ const newTraceFilter = {
+ field: 'traceGroup',
+ operator: 'is',
+ value: searchValue,
+ inverted: false,
+ disabled: false,
+ };
+ // Create the option if it doesn't exist.
+ if (
+ flattenedOptions.findIndex(
+ (option: OptionType) => option.label.trim().toLowerCase() === normalizedSearchValue
+ ) === -1
+ ) {
+ setTraceOptions([...traceOptions, newTraceOption]);
+ }
+ // Select the option.
+ setFiltersWithStorage([...filters, newTraceFilter]);
+ };
+
+ const addPercentileFilter = (condition = 'gte', additionalFilters = [] as FilterType[]) => {
+ if (traceItems.length === 0 || Object.keys(percentileMap).length === 0) return;
+ for (let i = 0; i < filters.length; i++) {
+ if (filters[i].custom) {
+ const newFilter = JSON.parse(JSON.stringify(filters[i]));
+ newFilter.custom.query.bool.should.forEach((should: any) =>
+ should.bool.must.forEach((must: any) => {
+ const range = must?.range?.['traceGroupFields.durationInNanos'];
+ if (range) {
+ const duration = range.lt || range.lte || range.gt || range.gte;
+ if (duration || duration === 0) {
+ must.range['traceGroupFields.durationInNanos'] = {
+ [condition]: duration,
+ };
+ }
+ }
+ })
+ );
+ newFilter.value = condition === 'gte' ? '>= 95th' : '< 95th';
+ const newFilters = [...filters, ...additionalFilters];
+ newFilters.splice(i, 1, newFilter);
+ setFiltersWithStorage(newFilters);
+ return;
+ }
+ }
+ };
+
+ const clearTraces = () => {
+ const withoutTraces = filters.filter((f) => f.field !== 'traceGroup');
+ setFiltersWithStorage(withoutTraces);
+ };
+
+ const onCancel = () => {
+ setIsModalVisible(false);
+ };
+
+ const closeModal = () => {
+ setIsModalVisible(false);
+ };
+
+ const showModal = () => {
+ setIsModalVisible(true);
+ };
+
+ const onConfirm = () => {
+ clearTraces();
+ closeModal();
+ };
+
+ const clearAllModal = () => {
+ setModalLayout(
+ getClearModal(
+ onCancel,
+ onConfirm,
+ 'Clear trace groups?',
+ 'This will clear all information in trace groups configuration.',
+ 'Clear all'
+ )
+ );
+ showModal();
+ };
+
+ return (
+
+
+
+
+ Trace groups{' '}
+ {selectedTraces.length}
+
+
+
+
+ Constrain your application to specific trace groups
+
+ >
+ }
+ extraAction={
+
+ Clear all
+
+ }
+ onToggle={(isOpen) => {
+ setTraceOpen(isOpen);
+ }}
+ paddingSize="l"
+ >
+
+
+
+
+
+
+ {isModalVisible && modalLayout}
+
+ );
+};
diff --git a/public/components/application_analytics/components/configuration.tsx b/public/components/application_analytics/components/configuration.tsx
new file mode 100644
index 0000000000..8cb8080ffc
--- /dev/null
+++ b/public/components/application_analytics/components/configuration.tsx
@@ -0,0 +1,151 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ EuiBreadcrumb,
+ EuiButton,
+ EuiCode,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiHorizontalRule,
+ EuiLink,
+ EuiPage,
+ EuiPageBody,
+ EuiPageContent,
+ EuiPageContentBody,
+ EuiPageContentHeader,
+ EuiPageContentHeaderSection,
+ EuiSelect,
+ EuiSelectOption,
+ EuiSpacer,
+ EuiText,
+ EuiTitle,
+} from '@elastic/eui';
+import { ApplicationRequestType, ApplicationType } from 'common/types/application_analytics';
+import { last } from 'lodash';
+import React, { useState } from 'react';
+
+interface ConfigProps {
+ appId: string;
+ application: ApplicationType;
+ parentBreadcrumbs: EuiBreadcrumb[];
+ visWithAvailability: EuiSelectOption[];
+ switchToAvailability: () => void;
+ updateApp: (appId: string, updateAppData: Partial, type: string) => void;
+}
+
+export const Configuration = (props: ConfigProps) => {
+ const {
+ appId,
+ application,
+ parentBreadcrumbs,
+ visWithAvailability,
+ updateApp,
+ switchToAvailability,
+ } = props;
+ const [availabilityVisId, setAvailabilityVisId] = useState(
+ application.availability.availabilityVisId || ''
+ );
+
+ const onAvailabilityVisChange = (event: any) => {
+ setAvailabilityVisId(event.target.value);
+ updateApp(appId, { availabilityVisId: event.target.value }, 'editAvailability');
+ };
+
+ return (
+
+
+
+
+
+
+
+ Configuration details
+
+
+
+
+
+ {
+ window.location.assign(
+ `${last(parentBreadcrumbs)!.href}application_analytics/edit/${appId}`
+ );
+ }}
+ >
+ Edit
+
+
+
+
+
+
+
+
+
+
+ Log source
+
+
+
+ {application.baseQuery}
+
+
+
+
+ Services & entities
+
+
+
+
+ {application.servicesEntities.map((group) => (
+ {decodeURI(group)}
+ ))}
+
+
+
+
+
+ Trace groups
+
+
+
+
+ {application.traceGroups.map((group) => (
+ {decodeURI(group)}
+ ))}
+
+
+
+
+
+ Availability
+
+
+ {visWithAvailability.length > 0 ? (
+
+ ) : (
+ switchToAvailability()}
+ >
+ Set Availability
+
+ )}
+
+
+
+
+
+
+
+ );
+};
diff --git a/public/components/application_analytics/components/create.tsx b/public/components/application_analytics/components/create.tsx
new file mode 100644
index 0000000000..084d53b17d
--- /dev/null
+++ b/public/components/application_analytics/components/create.tsx
@@ -0,0 +1,278 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable react-hooks/exhaustive-deps */
+
+import {
+ EuiButton,
+ EuiFieldText,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiForm,
+ EuiFormRow,
+ EuiHorizontalRule,
+ EuiPage,
+ EuiPageBody,
+ EuiPageContent,
+ EuiPageContentHeader,
+ EuiPageContentHeaderSection,
+ EuiPageHeader,
+ EuiPageHeaderSection,
+ EuiSpacer,
+ EuiTitle,
+ EuiToolTip,
+} from '@elastic/eui';
+import DSLService from 'public/services/requests/dsl';
+import React, { ReactChild, useEffect, useState } from 'react';
+import PPLService from 'public/services/requests/ppl';
+import { last } from 'lodash';
+import { AppAnalyticsComponentDeps } from '../home';
+import { TraceConfig } from './config_components/trace_config';
+import { ServiceConfig } from './config_components/service_config';
+import { LogConfig } from './config_components/log_config';
+import { PPLReferenceFlyout } from '../../../components/common/helpers';
+import {
+ ApplicationRequestType,
+ ApplicationType,
+ OptionType,
+} from '../../../../common/types/application_analytics';
+import { fetchAppById } from '../helpers/utils';
+
+interface CreateAppProps extends AppAnalyticsComponentDeps {
+ dslService: DSLService;
+ pplService: PPLService;
+ setToasts: (title: string, color?: string, text?: ReactChild) => void;
+ createApp: (app: ApplicationRequestType, type: string) => void;
+ updateApp: (appId: string, updateAppData: Partial, type: string) => void;
+ clearStorage: () => void;
+ existingAppId: string;
+}
+
+export const CreateApp = (props: CreateAppProps) => {
+ const {
+ parentBreadcrumbs,
+ chrome,
+ http,
+ query,
+ name,
+ description,
+ pplService,
+ createApp,
+ updateApp,
+ setToasts,
+ setNameWithStorage,
+ setDescriptionWithStorage,
+ setQueryWithStorage,
+ setFilters,
+ clearStorage,
+ existingAppId,
+ } = props;
+ const [isFlyoutVisible, setIsFlyoutVisible] = useState(false);
+ const [selectedServices, setSelectedServices] = useState([]);
+ const [selectedTraces, setSelectedTraces] = useState([]);
+
+ const editMode = existingAppId !== 'undefined';
+ const [existingApp, setExistingApp] = useState({
+ id: existingAppId,
+ dateCreated: '',
+ dateModified: '',
+ name: '',
+ description: '',
+ baseQuery: '',
+ servicesEntities: [],
+ traceGroups: [],
+ panelId: '',
+ availability: { name: '', color: '', availabilityVisId: '' },
+ });
+
+ useEffect(() => {
+ chrome.setBreadcrumbs([
+ ...parentBreadcrumbs,
+ {
+ text: 'Application analytics',
+ href: '#/application_analytics',
+ },
+ {
+ text: editMode ? 'Edit' : 'Create',
+ href: `#/application_analytics/${editMode ? 'edit' : 'create'}`,
+ },
+ ]);
+ }, []);
+
+ useEffect(() => {
+ if (editMode && existingAppId) {
+ fetchAppById(
+ http,
+ pplService,
+ existingAppId,
+ setExistingApp,
+ setFilters,
+ () => {},
+ setToasts
+ );
+ }
+ }, [existingAppId]);
+
+ useEffect(() => {
+ if (editMode) {
+ setNameWithStorage(existingApp.name);
+ setDescriptionWithStorage(existingApp.description);
+ setQueryWithStorage(existingApp.baseQuery);
+ }
+ }, [existingApp]);
+
+ const closeFlyout = () => {
+ setIsFlyoutVisible(false);
+ };
+
+ let flyout;
+ if (isFlyoutVisible) {
+ flyout = ;
+ }
+
+ const isDisabled = !name || (!query && !selectedTraces.length && !selectedServices.length);
+
+ const missingField = (needLog: boolean) => {
+ let popoverContent = '';
+ if (isDisabled || (needLog && !query)) {
+ if (!name) {
+ popoverContent = 'Name is required.';
+ } else if (!query && !selectedServices.length && !selectedTraces.length) {
+ popoverContent = 'Provide at least one log source, service, entity or trace group.';
+ } else if (needLog && !query) {
+ popoverContent = 'Log source is required to set availability.';
+ }
+ return {popoverContent}
;
+ }
+ };
+
+ const onCreate = (type: string) => {
+ const appData = {
+ name,
+ description,
+ baseQuery: query,
+ servicesEntities: selectedServices.map((option) => option.label),
+ traceGroups: selectedTraces.map((option) => option.label),
+ panelId: '',
+ availabilityVisId: '',
+ };
+ createApp(appData, type);
+ };
+
+ const onUpdate = () => {
+ const appData = {
+ name,
+ description,
+ servicesEntities: selectedServices.map((option) => option.label),
+ traceGroups: selectedTraces.map((option) => option.label),
+ };
+ updateApp(existingAppId, appData, 'update');
+ };
+
+ const onCancel = () => {
+ clearStorage();
+ window.location.assign(`${last(parentBreadcrumbs)!.href}application_analytics`);
+ };
+
+ return (
+
+
+
+
+
+
+ {editMode ? 'Edit' : 'Create'} application
+
+
+
+
+
+
+
+ Application information
+
+
+
+
+
+
+ setNameWithStorage(e.target.value)}
+ />
+
+
+ setDescriptionWithStorage(e.target.value)}
+ />
+
+
+
+
+
+
+
+
+ Composition
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+
+ onCreate('create')}
+ fill={editMode ? true : false}
+ >
+ {editMode ? 'Save' : 'Create'}
+
+
+
+ {editMode || (
+
+
+ onCreate('createSetAvailability')}
+ >
+ Create and Set Availability
+
+
+
+ )}
+
+
+
+ {flyout}
+
+ );
+};
diff --git a/public/components/application_analytics/components/flyout_components/availability_info_flyout.tsx b/public/components/application_analytics/components/flyout_components/availability_info_flyout.tsx
new file mode 100644
index 0000000000..86e668f417
--- /dev/null
+++ b/public/components/application_analytics/components/flyout_components/availability_info_flyout.tsx
@@ -0,0 +1,62 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ EuiFlyout,
+ EuiFlyoutHeader,
+ EuiTitle,
+ EuiFlyoutBody,
+ EuiText,
+ EuiCodeBlock,
+ EuiFlyoutFooter,
+ EuiButton,
+} from '@elastic/eui';
+import React from 'react';
+
+interface AvailabilityInfoFlyoutProps {
+ closeFlyout: () => void;
+}
+
+export function AvailabilityInfoFlyout(props: AvailabilityInfoFlyoutProps) {
+ const { closeFlyout } = props;
+
+ return (
+
+
+
+ Availability
+
+
+
+
+ Configure availability
+ Availability is the status of your application determined by availability levels set on a
+ time series metric. To create an availability level, you must configure the following:
+
+ color: The color of the availability badge on the home page
+ name: The text in the availability badge on the home page
+ expression: Comparison operator to determine the availability
+ value: Value to use when calculating availability
+
+ Configuring availability
+ By default, Application analytics shows results from the last 24 hours of your data. To
+ see data from a different timeframe, use the date and time selector.
+ Time series metric A time series metric is any visualization that has a query that
+ spans over a timestamp and is a bar/line chart. You can use the PPL language to define
+ arbitrary conditions on your logs to create a visualization over time.
+ Example
+
+ {'source = | ... | ... | stats ... by span(, 1h)'}
+
+ You can then choose Bar or Line in visualization
+ configurations to create a time series metric.
+
+
+
+ Close
+
+
+ );
+}
diff --git a/public/components/application_analytics/components/flyout_components/service_detail_flyout.tsx b/public/components/application_analytics/components/flyout_components/service_detail_flyout.tsx
new file mode 100644
index 0000000000..07a7e0a5a2
--- /dev/null
+++ b/public/components/application_analytics/components/flyout_components/service_detail_flyout.tsx
@@ -0,0 +1,141 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable react-hooks/exhaustive-deps */
+
+import _ from 'lodash';
+import {
+ EuiFlyout,
+ EuiFlyoutBody,
+ EuiFlyoutHeader,
+ EuiHorizontalRule,
+ EuiSpacer,
+ EuiText,
+ EuiTitle,
+} from '@elastic/eui';
+import React, { useEffect, useMemo, useState } from 'react';
+import {
+ handleServiceMapRequest,
+ handleServiceViewRequest,
+} from '../../../../../public/components/trace_analytics/requests/services_request_handler';
+import { filtersToDsl } from '../../../../../public/components/trace_analytics/components/common/helper_functions';
+import { ServiceMap } from '../../../../../public/components/trace_analytics/components/services';
+import { ServiceObject } from '../../../../../public/components/trace_analytics/components/common/plots/service_map';
+import { SpanDetailTable } from '../../../../../public/components/trace_analytics/components/traces/span_detail_table';
+import { TraceAnalyticsComponentDeps } from '../../../../../public/components/trace_analytics/home';
+import { getListItem } from '../../helpers/utils';
+
+interface ServiceFlyoutProps extends TraceAnalyticsComponentDeps {
+ serviceName: string;
+ closeServiceFlyout: () => void;
+ openSpanFlyout: (spanId: string) => void;
+ setSelectedTab: (newTab: string) => void;
+}
+
+export function ServiceDetailFlyout(props: ServiceFlyoutProps) {
+ const {
+ serviceName,
+ http,
+ startTime,
+ endTime,
+ filters,
+ appConfigs,
+ query,
+ closeServiceFlyout,
+ openSpanFlyout,
+ } = props;
+ const [fields, setFields] = useState({});
+ const [serviceMap, setServiceMap] = useState({});
+ const [total, setTotal] = useState(0);
+ const [DSL, setDSL] = useState({});
+ const [serviceMapIdSelected, setServiceMapIdSelected] = useState<
+ 'latency' | 'error_rate' | 'throughput'
+ >('latency');
+
+ const renderContent = useMemo(() => {
+ if (!serviceName) return '-';
+ const overviewList = [
+ getListItem('Name', serviceName),
+ getListItem(
+ 'Number of connected services',
+ fields.number_of_connected_services !== undefined ? fields.number_of_connected_services : 0
+ ),
+ getListItem(
+ 'Connected services',
+ fields.connected_services
+ ? fields.connected_services.reduce((prev: string, curr: string) => {
+ return [prev, ', ', curr];
+ })
+ : '-'
+ ),
+ getListItem(
+ 'Average latency (ms)',
+ fields.average_latency !== undefined ? fields.average_latency : '-'
+ ),
+ getListItem(
+ 'Error rate',
+ fields.error_rate !== undefined ? _.round(fields.error_rate, 2).toString() + '%' : '-'
+ ),
+ getListItem('Throughput', fields.throughput !== undefined ? fields.throughput : '-'),
+ getListItem('Traces', fields.traces === 0 || fields.traces ? fields.traces : '-'),
+ ];
+
+ return (
+ <>
+
+ Overview
+
+
+ {overviewList}
+
+
+
+
+
+
+ Spans
+ {total === 0 || total ? {` (${total})`} : null}
+
+
+
+ >
+ );
+ }, [serviceName, fields, serviceMap, DSL, serviceMapIdSelected]);
+
+ useEffect(() => {
+ const serviceDSL = filtersToDsl(filters, query, startTime, endTime, 'app', appConfigs);
+ handleServiceViewRequest(serviceName, http, serviceDSL, setFields);
+ handleServiceMapRequest(http, serviceDSL, setServiceMap, serviceName);
+ const spanDSL = filtersToDsl(filters, query, startTime, endTime, 'app', appConfigs);
+ spanDSL.query.bool.must.push({
+ term: {
+ serviceName,
+ },
+ });
+ setDSL(spanDSL);
+ }, [serviceName, startTime, endTime]);
+
+ return (
+
+
+
+ Service detail
+
+
+ {renderContent}
+
+ );
+}
diff --git a/public/components/application_analytics/components/flyout_components/trace_detail_flyout.tsx b/public/components/application_analytics/components/flyout_components/trace_detail_flyout.tsx
new file mode 100644
index 0000000000..ce687f306c
--- /dev/null
+++ b/public/components/application_analytics/components/flyout_components/trace_detail_flyout.tsx
@@ -0,0 +1,32 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { EuiFlyout, EuiFlyoutBody, EuiFlyoutHeader, EuiTitle } from '@elastic/eui';
+import React from 'react';
+import { TraceAnalyticsComponentDeps } from '../../../../../public/components/trace_analytics/home';
+import { TraceDetailRender } from './trace_detail_render';
+
+interface TraceFlyoutProps extends TraceAnalyticsComponentDeps {
+ traceId: string;
+ closeTraceFlyout: () => void;
+ openSpanFlyout: (spanId: string) => void;
+}
+
+export function TraceDetailFlyout(props: TraceFlyoutProps) {
+ const { traceId, http, closeTraceFlyout, openSpanFlyout } = props;
+ const renderContent = (
+
+ );
+ return (
+
+
+
+ Trace detail
+
+
+ {renderContent}
+
+ );
+}
diff --git a/public/components/application_analytics/components/flyout_components/trace_detail_render.tsx b/public/components/application_analytics/components/flyout_components/trace_detail_render.tsx
new file mode 100644
index 0000000000..34a91e01b1
--- /dev/null
+++ b/public/components/application_analytics/components/flyout_components/trace_detail_render.tsx
@@ -0,0 +1,92 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { EuiText, EuiSpacer, EuiHorizontalRule, EuiCodeBlock } from '@elastic/eui';
+import React, { useEffect, useMemo, useState } from 'react';
+import { ServiceBreakdownPanel } from '../../../trace_analytics/components/traces/service_breakdown_panel';
+import { SpanDetailPanel } from '../../../trace_analytics/components/traces/span_detail_panel';
+import {
+ handleTraceViewRequest,
+ handleServicesPieChartRequest,
+ handlePayloadRequest,
+} from '../../../trace_analytics/requests/traces_request_handler';
+import { HttpStart } from '../../../../../../../src/core/public';
+import { getListItem } from '../../helpers/utils';
+
+interface TraceDetailRenderProps {
+ traceId: string;
+ http: HttpStart;
+ openSpanFlyout: (spanId: string) => void;
+}
+
+export const TraceDetailRender = ({ traceId, http, openSpanFlyout }: TraceDetailRenderProps) => {
+ const [fields, setFields] = useState({});
+ const [serviceBreakdownData, setServiceBreakdownData] = useState([]);
+ const [payloadData, setPayloadData] = useState('');
+ const [colorMap, setColorMap] = useState({});
+
+ const renderContent = useMemo(() => {
+ if (!traceId) return <>>;
+ const overviewList = [
+ getListItem('Trace ID', traceId),
+ getListItem('Trace group name', fields.trace_group || '-'),
+ getListItem('Latency', fields.latency),
+ getListItem('Last updated', fields.last_updated),
+ getListItem(
+ 'Errors',
+ fields.error_count == null ? (
+ <>>
+ ) : fields.error_count > 0 ? (
+
+ Yes
+
+ ) : (
+ 'No'
+ )
+ ),
+ ];
+
+ return (
+ <>
+
+ Overview
+
+
+ {overviewList}
+
+
+
+
+
+
+
+
+
+ Payload
+
+
+ {payloadData.length > 0 ? (
+
+ {payloadData}
+
+ ) : null}
+ >
+ );
+ }, [traceId, fields, serviceBreakdownData, colorMap, payloadData]);
+
+ useEffect(() => {
+ handleTraceViewRequest(traceId, http, fields, setFields);
+ handleServicesPieChartRequest(traceId, http, setServiceBreakdownData, setColorMap);
+ handlePayloadRequest(traceId, http, payloadData, setPayloadData);
+ }, [traceId]);
+
+ return renderContent;
+};
diff --git a/public/components/application_analytics/helpers/modal_containers.tsx b/public/components/application_analytics/helpers/modal_containers.tsx
new file mode 100644
index 0000000000..e9670bc3bc
--- /dev/null
+++ b/public/components/application_analytics/helpers/modal_containers.tsx
@@ -0,0 +1,37 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { EuiOverlayMask, EuiConfirmModal } from '@elastic/eui';
+
+/* The file contains helper functions for modal layouts
+ * getClearModal - returns a confirm-modal with clear option
+ */
+
+export const getClearModal = (
+ onCancel: (
+ event?: React.KeyboardEvent | React.MouseEvent
+ ) => void,
+ onConfirm: (event?: React.MouseEvent) => void,
+ title: string,
+ message: string,
+ confirmMessage?: string
+) => {
+ return (
+
+
+ {message}
+
+
+ );
+};
diff --git a/public/components/application_analytics/helpers/utils.tsx b/public/components/application_analytics/helpers/utils.tsx
new file mode 100644
index 0000000000..96e2d62be5
--- /dev/null
+++ b/public/components/application_analytics/helpers/utils.tsx
@@ -0,0 +1,330 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable no-console */
+
+import { EuiDescriptionList, EuiSelectOption, EuiSpacer, EuiText } from '@elastic/eui';
+import { ApplicationType, AvailabilityType } from 'common/types/application_analytics';
+import { FilterType } from 'public/components/trace_analytics/components/common/filters/filters';
+import React, { Dispatch, ReactChild } from 'react';
+import { batch } from 'react-redux';
+import PPLService from 'public/services/requests/ppl';
+import { preprocessQuery } from '../../../../common/utils/query_utils';
+import { SPAN_REGEX } from '../../../../common/constants/shared';
+import { fetchVisualizationById } from '../../../components/custom_panels/helpers/utils';
+import { CUSTOM_PANELS_API_PREFIX } from '../../../../common/constants/custom_panels';
+import { VisualizationType } from '../../../../common/types/custom_panels';
+import { NEW_SELECTED_QUERY_TAB, TAB_CREATED_TYPE } from '../../../../common/constants/explorer';
+import { APP_ANALYTICS_API_PREFIX } from '../../../../common/constants/application_analytics';
+import { HttpSetup } from '../../../../../../src/core/public';
+import { init as initFields, remove as removefields } from '../../explorer/slices/field_slice';
+import {
+ init as initVisualizationConfig,
+ reset as resetVisualizationConfig,
+} from '../../explorer/slices/viualization_config_slice';
+import {
+ init as initQuery,
+ remove as removeQuery,
+ changeQuery,
+} from '../../explorer/slices/query_slice';
+import {
+ init as initQueryResult,
+ remove as removeQueryResult,
+} from '../../explorer/slices/query_result_slice';
+import { addTab, removeTab } from '../../explorer/slices/query_tab_slice';
+
+// Name validation
+export const isNameValid = (name: string, existingNames: string[]) => {
+ const toast: string[] = [];
+ if (name.length >= 50) {
+ toast.push('Name must be less than 50 characters.');
+ }
+ if (name.trim().length === 0) {
+ toast.push('Name must not be empty.');
+ }
+ if (existingNames.includes(name)) {
+ toast.push('Name must be unique.');
+ }
+ return toast;
+};
+
+export const getListItem = (title: string, description: string | React.ReactElement) => {
+ const titleComponent = (
+
+ {title}
+
+ );
+
+ const descriptionComponent = (
+
+ {description}
+
+ );
+
+ return (
+
+
+
+
+ );
+};
+
+// Fetch application by id
+export const fetchAppById = async (
+ http: HttpSetup,
+ pplService: PPLService,
+ applicationId: string,
+ setApplication: (application: ApplicationType) => void,
+ setFilters: (filters: FilterType[]) => void,
+ setVisWithAvailability: (visList: EuiSelectOption[]) => void,
+ setToasts: (title: string, color?: string, text?: ReactChild) => void
+) => {
+ return http
+ .get(`${APP_ANALYTICS_API_PREFIX}/${applicationId}`)
+ .then(async (res: ApplicationType) => {
+ res.availability.availabilityVisId = (
+ await calculateAvailability(
+ http,
+ pplService,
+ res,
+ res.availability.availabilityVisId,
+ setVisWithAvailability
+ )
+ ).availabilityVisId;
+ setApplication(res);
+ const serviceFilters = res.servicesEntities.map((ser: string) => {
+ return {
+ field: 'serviceName',
+ operator: 'is',
+ value: ser,
+ inverted: false,
+ disabled: false,
+ };
+ });
+ const traceFilters = res.traceGroups.map((tra: string) => {
+ return {
+ field: 'traceGroup',
+ operator: 'is',
+ value: tra,
+ inverted: false,
+ disabled: false,
+ };
+ });
+ setFilters([...serviceFilters, ...traceFilters]);
+ })
+ .catch((err) => {
+ setToasts('Error occurred while fetching application', 'danger');
+ console.error(err);
+ });
+};
+
+// Remove tab data when closed
+export const removeTabData = (
+ dispatch: Dispatch,
+ TabIdToBeClosed: string,
+ newIdToFocus: string
+) => {
+ batch(() => {
+ dispatch(removeQuery({ tabId: TabIdToBeClosed }));
+ dispatch(removefields({ tabId: TabIdToBeClosed }));
+ dispatch(removeQueryResult({ tabId: TabIdToBeClosed }));
+ dispatch(resetVisualizationConfig({ tabId: TabIdToBeClosed }));
+ dispatch(
+ removeTab({
+ tabId: TabIdToBeClosed,
+ [NEW_SELECTED_QUERY_TAB]: newIdToFocus,
+ })
+ );
+ });
+};
+
+// Create a new tab and initialize its data
+export const initializeTabData = async (dispatch: Dispatch, tabId: string, where: string) => {
+ await batch(() => {
+ dispatch(initQuery({ tabId }));
+ dispatch(initQueryResult({ tabId }));
+ dispatch(initFields({ tabId }));
+ dispatch(addTab({ tabId }));
+ dispatch(initVisualizationConfig({ tabId }));
+ dispatch(
+ changeQuery({
+ tabId,
+ query: {
+ [TAB_CREATED_TYPE]: where,
+ },
+ })
+ );
+ });
+};
+
+export const fetchPanelsVizIdList = async (http: HttpSetup, appPanelId: string) => {
+ return await http
+ .get(`${CUSTOM_PANELS_API_PREFIX}/panels/${appPanelId}`)
+ .then((res) => {
+ const visIds = res.operationalPanel.visualizations.map(
+ (viz: VisualizationType) => viz.savedVisualizationId
+ );
+ return visIds;
+ })
+ .catch((err) => {
+ console.error('Error occurred while fetching visualizations for panel', err);
+ return [];
+ });
+};
+
+export const calculateAvailability = async (
+ http: HttpSetup,
+ pplService: PPLService,
+ application: ApplicationType,
+ availabilityVisId: string,
+ setVisWithAvailability: (visList: EuiSelectOption[]) => void
+): Promise => {
+ let availability = { name: '', color: '', availabilityVisId: '' };
+ const panelId = application.panelId;
+ if (!panelId) return availability;
+ // Fetches saved visualizations associated to application's panel
+ // Order visualizations by most recently created
+ const savedVisualizationsIds = (await fetchPanelsVizIdList(http, panelId)).reverse();
+ if (!savedVisualizationsIds) return availability;
+ const visWithAvailability = [];
+ let availabilityFound = false;
+ for (let i = 0; i < savedVisualizationsIds.length; i++) {
+ const visualizationId = savedVisualizationsIds[i];
+ // Fetches data for visualization
+ const visData = await fetchVisualizationById(http, visualizationId, (value: string) =>
+ console.error(value)
+ );
+ // If there are levels, we get the current value
+ if (visData.user_configs.availabilityConfig?.hasOwnProperty('level')) {
+ // For every saved visualization with availability levels we push it to visWithAvailability
+ // This is used to populate the options in configuration
+ visWithAvailability.push({ value: visualizationId, text: visData.name });
+
+ const levels = visData.user_configs.availabilityConfig.level.reverse();
+ let currValue = Number.MIN_VALUE;
+ const finalQuery = preprocessQuery({
+ rawQuery: visData.query,
+ startTime: visData.selected_date_range.start,
+ endTime: visData.selected_date_range.end,
+ timeField: visData.timeField,
+ isLiveQuery: false,
+ });
+ await pplService
+ .fetch({
+ query: finalQuery,
+ format: 'viz',
+ })
+ .then((res) => {
+ const stat = res.metadata.fields.filter(
+ (field: { name: string; type: string }) => !field.name.match(SPAN_REGEX)
+ )[0].name;
+ const value = res.data[stat];
+ currValue = value[value.length - 1];
+ })
+ .catch((err) => {
+ console.error(err);
+ });
+ for (let j = 0; j < levels.length; j++) {
+ const level = levels[j];
+ // If there is an availiabilityVisId selected we only want to compute availability based on that
+ if (availabilityVisId ? availabilityVisId === visualizationId : true) {
+ if (level.value !== null) {
+ if (currValue === null) {
+ availability = {
+ name: '',
+ color: 'null',
+ availabilityVisId: '',
+ };
+ } else {
+ if (!availabilityFound) {
+ const expression = level.expression;
+ switch (expression) {
+ case '≥':
+ if (currValue >= parseFloat(level.value)) {
+ availability = {
+ name: level.name,
+ color: level.color,
+ availabilityVisId: visualizationId,
+ };
+ availabilityFound = true;
+ }
+ break;
+ case '≤':
+ if (currValue <= parseFloat(level.value)) {
+ availability = {
+ name: level.name,
+ color: level.color,
+ availabilityVisId: visualizationId,
+ };
+ availabilityFound = true;
+ }
+ break;
+ case '>':
+ if (currValue > parseFloat(level.value)) {
+ availability = {
+ name: level.name,
+ color: level.color,
+ availabilityVisId: visualizationId,
+ };
+ availabilityFound = true;
+ }
+ break;
+ case '<':
+ if (currValue < parseFloat(level.value)) {
+ availability = {
+ name: level.name,
+ color: level.color,
+ availabilityVisId: visualizationId,
+ };
+ availabilityFound = true;
+ }
+ break;
+ case '=':
+ if (currValue === parseFloat(level.value)) {
+ availability = {
+ name: level.name,
+ color: level.color,
+ availabilityVisId: visualizationId,
+ };
+ availabilityFound = true;
+ }
+ break;
+ case '≠':
+ if (currValue !== parseFloat(level.value)) {
+ availability = {
+ name: level.name,
+ color: level.color,
+ availabilityVisId: visualizationId,
+ };
+ availabilityFound = true;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ setVisWithAvailability(visWithAvailability);
+ if (!availabilityFound && visWithAvailability.length > 0) {
+ return { name: '', color: 'undefined', availabilityVisId: '' };
+ }
+ return availability;
+};
diff --git a/public/components/application_analytics/home.tsx b/public/components/application_analytics/home.tsx
new file mode 100644
index 0000000000..95ab3d9784
--- /dev/null
+++ b/public/components/application_analytics/home.tsx
@@ -0,0 +1,445 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable react-hooks/exhaustive-deps */
+/* eslint-disable no-console */
+
+import React, { ReactChild, useEffect, useState } from 'react';
+import { Route, RouteComponentProps, Switch } from 'react-router-dom';
+import DSLService from 'public/services/requests/dsl';
+import PPLService from 'public/services/requests/ppl';
+import SavedObjects from 'public/services/saved_objects/event_analytics/saved_objects';
+import TimestampUtils from 'public/services/timestamp/timestamp';
+import { EuiGlobalToastList, EuiLink } from '@elastic/eui';
+import { Toast } from '@elastic/eui/src/components/toast/global_toast_list';
+import { isEmpty, last } from 'lodash';
+import { useDispatch } from 'react-redux';
+import { AppTable } from './components/app_table';
+import { Application } from './components/application';
+import { CreateApp } from './components/create';
+import { TraceAnalyticsComponentDeps, TraceAnalyticsCoreDeps } from '../trace_analytics/home';
+import { FilterType } from '../trace_analytics/components/common/filters/filters';
+import { handleIndicesExistRequest } from '../trace_analytics/requests/request_handler';
+import { ObservabilitySideBar } from '../common/side_nav';
+import { NotificationsStart } from '../../../../../src/core/public';
+import { APP_ANALYTICS_API_PREFIX } from '../../../common/constants/application_analytics';
+import {
+ ApplicationRequestType,
+ ApplicationType,
+} from '../../../common/types/application_analytics';
+import {
+ calculateAvailability,
+ fetchPanelsVizIdList,
+ isNameValid,
+ removeTabData,
+} from './helpers/utils';
+import {
+ CUSTOM_PANELS_API_PREFIX,
+ CUSTOM_PANELS_DOCUMENTATION_URL,
+} from '../../../common/constants/custom_panels';
+
+export type AppAnalyticsCoreDeps = TraceAnalyticsCoreDeps;
+
+interface HomeProps extends RouteComponentProps, AppAnalyticsCoreDeps {
+ pplService: PPLService;
+ dslService: DSLService;
+ savedObjects: SavedObjects;
+ timestampUtils: TimestampUtils;
+ notifications: NotificationsStart;
+}
+
+export interface AppAnalyticsComponentDeps extends TraceAnalyticsComponentDeps {
+ name: string;
+ description: string;
+ setNameWithStorage: (newName: string) => void;
+ setDescriptionWithStorage: (newDescription: string) => void;
+ setQueryWithStorage: (newQuery: string) => void;
+ setFiltersWithStorage: (newFilters: FilterType[]) => void;
+ setAppConfigs: (newAppConfigs: FilterType[]) => void;
+}
+
+export const Home = (props: HomeProps) => {
+ const {
+ pplService,
+ dslService,
+ timestampUtils,
+ savedObjects,
+ parentBreadcrumbs,
+ http,
+ chrome,
+ notifications,
+ } = props;
+ const [triggerSwitchToEvent, setTriggerSwitchToEvent] = useState(0);
+ const dispatch = useDispatch();
+ const [applicationList, setApplicationList] = useState([]);
+ const [toasts, setToasts] = useState([]);
+ const [indicesExist, setIndicesExist] = useState(true);
+ const [appConfigs, setAppConfigs] = useState([]);
+ const storedFilters = sessionStorage.getItem('AppAnalyticsFilters');
+ const [filters, setFilters] = useState(
+ storedFilters ? JSON.parse(storedFilters) : []
+ );
+ const [name, setName] = useState(sessionStorage.getItem('AppAnalyticsName') || '');
+ const [description, setDescription] = useState(
+ sessionStorage.getItem('AppAnalyticsDescription') || ''
+ );
+ const [query, setQuery] = useState(sessionStorage.getItem('AppAnalyticsQuery') || '');
+ const [startTime, setStartTime] = useState(
+ sessionStorage.getItem('AppAnalyticsStartTime') || 'now-24h'
+ );
+ const [endTime, setEndTime] = useState(
+ sessionStorage.getItem('AppAnalyticsEndTime') || 'now'
+ );
+
+ // Setting state with storage to save input when user refreshes page
+ const setFiltersWithStorage = (newFilters: FilterType[]) => {
+ setFilters(newFilters);
+ sessionStorage.setItem('AppAnalyticsFilters', JSON.stringify(newFilters));
+ };
+ const setNameWithStorage = (newName: string) => {
+ setName(newName);
+ sessionStorage.setItem('AppAnalyticsName', newName);
+ };
+ const setDescriptionWithStorage = (newDescription: string) => {
+ setDescription(newDescription);
+ sessionStorage.setItem('AppAnalyticsDescription', newDescription);
+ };
+ const setQueryWithStorage = (newQuery: string) => {
+ setQuery(newQuery);
+ sessionStorage.setItem('AppAnalyticsQuery', newQuery);
+ };
+
+ useEffect(() => {
+ handleIndicesExistRequest(http, setIndicesExist);
+ }, []);
+
+ const commonProps: AppAnalyticsComponentDeps = {
+ parentBreadcrumbs,
+ http,
+ chrome,
+ name,
+ setNameWithStorage,
+ description,
+ setDescriptionWithStorage,
+ query,
+ setQuery,
+ setQueryWithStorage,
+ appConfigs,
+ setAppConfigs,
+ filters,
+ setFilters,
+ setFiltersWithStorage,
+ startTime,
+ setStartTime,
+ endTime,
+ setEndTime,
+ indicesExist,
+ };
+
+ const setToast = (title: string, color = 'success', text?: ReactChild) => {
+ if (!text) text = '';
+ setToasts([...toasts, { id: new Date().toISOString(), title, text, color } as Toast]);
+ };
+
+ const clearStorage = () => {
+ setNameWithStorage('');
+ setDescriptionWithStorage('');
+ setFiltersWithStorage([]);
+ setQueryWithStorage('');
+ };
+
+ const moveToApp = (id: string, type: string) => {
+ window.location.assign(`${last(parentBreadcrumbs)!.href}application_analytics/${id}`);
+ if (type === 'createSetAvailability') {
+ setTriggerSwitchToEvent(2);
+ }
+ };
+
+ const createPanelForApp = (applicationId: string, appName: string, type: string) => {
+ return http
+ .post(`${CUSTOM_PANELS_API_PREFIX}/panels`, {
+ body: JSON.stringify({
+ panelName: `${appName}'s Panel`,
+ applicationId,
+ }),
+ })
+ .then((res) => {
+ updateApp(applicationId, { panelId: res.newPanelId }, type);
+ })
+ .catch((err) => {
+ setToast(
+ 'Please ask your administrator to enable Operational Panels for you.',
+ 'danger',
+
+ Documentation
+
+ );
+ console.error(err);
+ });
+ };
+
+ const deletePanelForApp = (appPanelId: string) => {
+ const concatList = [appPanelId].toString();
+ return http.delete(`${CUSTOM_PANELS_API_PREFIX}/panelList/` + concatList).catch((err) => {
+ setToast(
+ 'Error occurred while deleting Operational Panels, please make sure you have the correct permission.',
+ 'danger'
+ );
+ console.error(err.body.message);
+ });
+ };
+
+ const deleteSavedVisualizationsForPanel = async (appPanelId: string) => {
+ const savedVizIdsToDelete = await fetchPanelsVizIdList(http, appPanelId);
+ if (!isEmpty(savedVizIdsToDelete)) {
+ savedObjects
+ .deleteSavedObjectsList({ objectIdList: savedVizIdsToDelete })
+ .then((res) => {
+ deletePanelForApp(appPanelId);
+ })
+ .catch((err) => {
+ setToast('Error occurred while deleting Saved Visualizations', 'danger');
+ console.error(err);
+ });
+ }
+ };
+
+ // Fetches all existing applications
+ const fetchApps = () => {
+ return http
+ .get(`${APP_ANALYTICS_API_PREFIX}/`)
+ .then(async (res) => {
+ // Want to calculate availability going down the table
+ const availabilityVisIdStore: Record = {};
+ for (let i = 0; i < res.data.length; i++) {
+ availabilityVisIdStore[res.data[i].id] = res.data[i].availability.availabilityVisId;
+ res.data[i].availability = { name: '', color: 'loading', availabilityVisId: '' };
+ }
+ setApplicationList(res.data);
+ for (let i = res.data.length - 1; i > -1; i--) {
+ res.data[i].availability = await calculateAvailability(
+ http,
+ pplService,
+ res.data[i],
+ availabilityVisIdStore[res.data[i].id],
+ () => {}
+ );
+ // Need to set state with new object to trigger re-render
+ setApplicationList([
+ ...res.data.filter((app: ApplicationType) => app.id !== res.data[i].id),
+ res.data[i],
+ ]);
+ }
+ })
+ .catch((err) => {
+ setToast('Error occurred while fetching applications', 'danger');
+ console.error(err);
+ });
+ };
+
+ // Create a new application
+ const createApp = (application: ApplicationRequestType, type: string) => {
+ const toast = isNameValid(
+ application.name,
+ applicationList.map((obj) => obj.name)
+ );
+ if (toast.length > 0) {
+ setToast(toast.join(', '), 'danger');
+ return;
+ }
+
+ const requestBody = {
+ name: application.name,
+ description: application.description || '',
+ baseQuery: application.baseQuery,
+ servicesEntities: application.servicesEntities,
+ traceGroups: application.traceGroups,
+ availabilityVisId: '',
+ };
+
+ return http
+ .post(`${APP_ANALYTICS_API_PREFIX}/`, {
+ body: JSON.stringify(requestBody),
+ })
+ .then(async (res) => {
+ createPanelForApp(res.newAppId, application.name, type);
+ setToast(`Application "${application.name}" successfully created!`);
+ clearStorage();
+ })
+ .catch((err) => {
+ setToast(`Error occurred while creating new application "${application.name}"`, 'danger');
+ console.error(err);
+ });
+ };
+
+ // Rename an existing application
+ const renameApp = (newAppName: string, appId: string) => {
+ const toast = isNameValid(
+ newAppName,
+ applicationList.map((obj) => obj.name)
+ );
+ if (toast.length > 0) {
+ setToast(toast.join(', '), 'danger');
+ return;
+ }
+
+ const requestBody = {
+ appId,
+ name: newAppName,
+ };
+
+ return http
+ .put(`${APP_ANALYTICS_API_PREFIX}/rename`, {
+ body: JSON.stringify(requestBody),
+ })
+ .then((res) => {
+ setApplicationList((prevApplicationList) => {
+ const newApplicationData = [...prevApplicationList];
+ const renamedApplication = newApplicationData.find(
+ (application) => application.id === appId
+ );
+ if (renamedApplication) renamedApplication.name = newAppName;
+ return newApplicationData;
+ });
+ setToast(`Application successfully renamed to "${newAppName}"`);
+ })
+ .catch((err) => {
+ setToast('Error occurred while renaming application', 'danger');
+ console.error(err);
+ });
+ };
+
+ // Update existing application
+ const updateApp = (
+ appId: string,
+ updateAppData: Partial,
+ type: string
+ ) => {
+ const requestBody = {
+ appId,
+ updateBody: updateAppData,
+ };
+
+ return http
+ .put(`${APP_ANALYTICS_API_PREFIX}/`, {
+ body: JSON.stringify(requestBody),
+ })
+ .then((res) => {
+ if (type === 'update') {
+ setToast('Application successfully updated.');
+ clearStorage();
+ moveToApp(res.updatedAppId, type);
+ }
+ if (type.startsWith('create')) {
+ moveToApp(res.updatedAppId, type);
+ }
+ })
+ .catch((err) => {
+ setToast('Error occurred while updating application', 'danger');
+ console.error(err);
+ });
+ };
+
+ // Delete existing applications
+ const deleteApp = (appList: string[], panelList: string[], toastMessage?: string) => {
+ return http
+ .delete(`${APP_ANALYTICS_API_PREFIX}/${appList.join(',')}`)
+ .then((res) => {
+ setApplicationList((prevApplicationList) => {
+ return prevApplicationList.filter((app) => !appList.includes(app.id));
+ });
+
+ for (let i = 0; i < appList.length; i++) {
+ removeTabData(dispatch, appList[i], '');
+ }
+
+ for (let i = 0; i < panelList.length; i++) {
+ deleteSavedVisualizationsForPanel(panelList[i]);
+ }
+
+ const message =
+ toastMessage || `Application${appList.length > 1 ? 's' : ''} successfully deleted!`;
+ setToast(message);
+ return res;
+ })
+ .catch((err: any) => {
+ setToast('Error occured while deleting application', 'danger');
+ console.error(err);
+ });
+ };
+
+ const callback = (childFunc: () => void) => {
+ if (childFunc && triggerSwitchToEvent > 0) {
+ childFunc();
+ setTriggerSwitchToEvent(triggerSwitchToEvent - 1);
+ }
+ };
+
+ return (
+
+
{
+ setToasts(toasts.filter((toast) => toast.id !== removedToast.id));
+ }}
+ toastLifeTimeMs={6000}
+ />
+
+ (
+
+
+
+ )}
+ />
+ (
+
+ )}
+ />
+ (
+
+ )}
+ />
+
+
+ );
+};
diff --git a/public/components/common/debounced_component/debounced_component.tsx b/public/components/common/debounced_component/debounced_component.tsx
new file mode 100644
index 0000000000..710c16c9c2
--- /dev/null
+++ b/public/components/common/debounced_component/debounced_component.tsx
@@ -0,0 +1,27 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useState, useMemo, useEffect, memo, FunctionComponent } from 'react';
+import { debounce } from 'lodash';
+
+/**
+ * debouncedComponent wraps the specified React component, returning a component which
+ * only renders once there is a pause in props changes for at least `delay` milliseconds.
+ * During the debounce phase, it will return the previously rendered value.
+ */
+export function debouncedComponent(component: FunctionComponent, delay = 256) {
+ const MemoizedComponent = (memo(component) as unknown) as FunctionComponent;
+
+ return (props: TProps) => {
+ const [cachedProps, setCachedProps] = useState(props);
+ const debouncePropsChange = useMemo(() => debounce(setCachedProps, delay), [setCachedProps]);
+
+ // cancel debounced prop change if component has been unmounted in the meantime
+ useEffect(() => () => debouncePropsChange.cancel(), [debouncePropsChange]);
+ debouncePropsChange(props);
+
+ return React.createElement(MemoizedComponent, cachedProps);
+ };
+}
diff --git a/public/components/common/debounced_component/index.ts b/public/components/common/debounced_component/index.ts
new file mode 100644
index 0000000000..aa1308791a
--- /dev/null
+++ b/public/components/common/debounced_component/index.ts
@@ -0,0 +1,6 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export * from './debounced_component';
diff --git a/public/components/common/field_button/field_button.scss b/public/components/common/field_button/field_button.scss
new file mode 100644
index 0000000000..8ae66b433b
--- /dev/null
+++ b/public/components/common/field_button/field_button.scss
@@ -0,0 +1,80 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+.osdFieldButton {
+ @include euiFontSizeS;
+ border-radius: $euiBorderRadius;
+ margin-bottom: $euiSizeXS;
+ display: flex;
+ align-items: center;
+ transition: box-shadow $euiAnimSpeedFast $euiAnimSlightResistance,
+ background-color $euiAnimSpeedFast $euiAnimSlightResistance; // sass-lint:disable-line indentation
+
+ &:focus-within,
+ &-isActive {
+ @include euiFocusRing;
+ }
+}
+
+.osdFieldButton--isDraggable {
+ background: lightOrDarkTheme($euiColorEmptyShade, $euiColorLightestShade);
+
+ &:hover,
+ &:focus,
+ &:focus-within {
+ @include euiBottomShadowMedium;
+ border-radius: $euiBorderRadius;
+ z-index: 2;
+ }
+
+ .osdFieldButton__button {
+ &:hover,
+ &:focus {
+ cursor: grab;
+ }
+ }
+}
+
+.osdFieldButton__button {
+ flex-grow: 1;
+ text-align: left;
+ padding: $euiSizeS;
+ display: flex;
+ align-items: flex-start;
+}
+
+.osdFieldButton__fieldIcon {
+ flex-shrink: 0;
+ line-height: 0;
+ margin-right: $euiSizeS;
+}
+
+.osdFieldButton__name {
+ flex-grow: 1;
+ word-break: break-word;
+}
+
+.osdFieldButton__infoIcon {
+ flex-shrink: 0;
+ margin-left: $euiSizeXS;
+}
+
+.osdFieldButton__fieldAction {
+ margin-right: $euiSizeS;
+}
+
+// Reduce text size and spacing for the small size
+.osdFieldButton--small {
+ font-size: $euiFontSizeXS;
+
+ .osdFieldButton__button {
+ padding: $euiSizeXS;
+ }
+
+ .osdFieldButton__fieldIcon,
+ .osdFieldButton__fieldAction {
+ margin-right: $euiSizeXS;
+ }
+}
diff --git a/public/components/common/field_button/field_button.tsx b/public/components/common/field_button/field_button.tsx
new file mode 100644
index 0000000000..5ceac98755
--- /dev/null
+++ b/public/components/common/field_button/field_button.tsx
@@ -0,0 +1,122 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import './field_button.scss';
+import classNames from 'classnames';
+import React, { ReactNode, HTMLAttributes, ButtonHTMLAttributes } from 'react';
+import { CommonProps } from '@elastic/eui';
+
+export interface FieldButtonProps extends HTMLAttributes {
+ /**
+ * Label for the button
+ */
+ fieldName: ReactNode;
+ /**
+ * Icon representing the field type.
+ * Recommend using FieldIcon
+ */
+ fieldIcon?: ReactNode;
+ /**
+ * An optional node to place inside and at the end of the
+ */
+ fieldInfoIcon?: ReactNode;
+ /**
+ * An optional node to place outside of and to the right of the
+ */
+ fieldAction?: ReactNode;
+ /**
+ * Adds a forced focus ring to the whole component
+ */
+ isActive?: boolean;
+ /**
+ * Styles the component differently to indicate it is draggable
+ */
+ isDraggable?: boolean;
+ /**
+ * Use the small size in condensed areas
+ */
+ size?: ButtonSize;
+ className?: string;
+ /**
+ * The component will render a `` when provided an `onClick`
+ */
+ onClick?: () => void;
+ /**
+ * Applies to the inner `` or ``
+ */
+ dataTestSubj?: string;
+ /**
+ * Pass more button props to the `
` element
+ */
+ buttonProps?: ButtonHTMLAttributes & CommonProps;
+}
+
+const sizeToClassNameMap = {
+ s: 'osdFieldButton--small',
+ m: null,
+} as const;
+
+export type ButtonSize = keyof typeof sizeToClassNameMap;
+
+export const SIZES = Object.keys(sizeToClassNameMap) as ButtonSize[];
+
+export function FieldButton({
+ size = 'm',
+ isActive = false,
+ fieldIcon,
+ fieldName,
+ fieldInfoIcon,
+ fieldAction,
+ className,
+ isDraggable = false,
+ onClick,
+ dataTestSubj,
+ buttonProps,
+ ...rest
+}: FieldButtonProps) {
+ const classes = classNames(
+ 'osdFieldButton',
+ size ? sizeToClassNameMap[size] : null,
+ { 'osdFieldButton-isActive': isActive },
+ { 'osdFieldButton--isDraggable': isDraggable },
+ className
+ );
+
+ const contentClasses = classNames('osd-resetFocusState', 'osdFieldButton__button');
+
+ const innerContent = (
+ <>
+ {fieldIcon && {fieldIcon} }
+ {fieldName && {fieldName} }
+ {fieldInfoIcon && {fieldInfoIcon}
}
+ >
+ );
+
+ return (
+
+ {onClick ? (
+
{
+ if (e.type === 'click') {
+ e.currentTarget.focus();
+ }
+ onClick();
+ }}
+ data-test-subj={dataTestSubj}
+ className={contentClasses}
+ {...buttonProps}
+ >
+ {innerContent}
+
+ ) : (
+
+ {innerContent}
+
+ )}
+
+ {fieldAction &&
{fieldAction}
}
+
+ );
+}
diff --git a/public/components/common/field_button/index.ts b/public/components/common/field_button/index.ts
new file mode 100644
index 0000000000..70274f800f
--- /dev/null
+++ b/public/components/common/field_button/index.ts
@@ -0,0 +1,6 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export * from './field_button';
diff --git a/public/components/common/field_icon/field_icon.tsx b/public/components/common/field_icon/field_icon.tsx
new file mode 100644
index 0000000000..a63dfe5add
--- /dev/null
+++ b/public/components/common/field_icon/field_icon.tsx
@@ -0,0 +1,71 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import classNames from 'classnames';
+import { EuiToken, EuiTokenProps } from '@elastic/eui';
+
+export interface FieldIconProps extends Omit {
+ type:
+ | 'boolean'
+ | 'conflict'
+ | 'date'
+ | 'geo_point'
+ | 'geo_shape'
+ | 'ip'
+ | 'murmur3'
+ | 'number'
+ | '_source'
+ | 'string'
+ | string
+ | 'nested';
+ label?: string;
+ scripted?: boolean;
+}
+
+// defaultIcon => a unknown datatype
+const defaultIcon = { iconType: 'questionInCircle', color: 'gray' };
+
+export const typeToEuiIconMap: Partial> = {
+ boolean: { iconType: 'tokenBoolean' },
+ // icon for an index pattern mapping conflict in discover
+ conflict: { iconType: 'alert', color: 'euiVisColor9' },
+ date: { iconType: 'tokenDate' },
+ geo_point: { iconType: 'tokenGeo' },
+ geo_shape: { iconType: 'tokenGeo' },
+ ip: { iconType: 'tokenIP' },
+ // is a plugin's data type https://www.elastic.co/guide/en/elasticsearch/plugins/current/mapper-murmur3-usage.html
+ murmur3: { iconType: 'tokenFile' },
+ number: { iconType: 'tokenNumber' },
+ _source: { iconType: 'editorCodeBlock', color: 'gray' },
+ string: { iconType: 'tokenString' },
+ nested: { iconType: 'tokenNested' },
+};
+
+/**
+ * Field token icon used across the app
+ */
+export function FieldIcon({
+ type,
+ label,
+ size = 's',
+ scripted,
+ className,
+ ...rest
+}: FieldIconProps) {
+ const token = typeToEuiIconMap[type] || defaultIcon;
+
+ return (
+
+ );
+}
diff --git a/public/components/common/field_icon/index.ts b/public/components/common/field_icon/index.ts
new file mode 100644
index 0000000000..87023615e0
--- /dev/null
+++ b/public/components/common/field_icon/index.ts
@@ -0,0 +1,6 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export * from './field_icon';
diff --git a/public/components/common/field_name/field_name.tsx b/public/components/common/field_name/field_name.tsx
new file mode 100644
index 0000000000..b7ea2a5929
--- /dev/null
+++ b/public/components/common/field_name/field_name.tsx
@@ -0,0 +1,51 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui';
+
+// import { FieldIcon, FieldIconProps } from '../../../../../kibana_react/public';
+// import { shortenDottedString } from '../../helpers';
+import { getFieldTypeName } from './field_type_name';
+
+// properties fieldType and fieldName are provided in osd_doc_view
+// this should be changed when both components are deangularized
+interface Props {
+ fieldName: string;
+ fieldType: string;
+ useShortDots?: boolean;
+ // fieldIconProps?: Omit;
+ scripted?: boolean;
+}
+
+export function FieldName({
+ fieldName,
+ fieldType,
+ useShortDots,
+ // fieldIconProps,
+ scripted = false,
+}: Props) {
+ const typeName = getFieldTypeName(fieldType);
+ // const displayName = useShortDots ? shortenDottedString(fieldName) : fieldName;
+ const displayName = fieldName;
+
+ return (
+
+ {/*
+
+ */}
+
+
+ {displayName}
+
+
+
+ );
+}
diff --git a/public/components/common/field_name/field_type_name.ts b/public/components/common/field_name/field_type_name.ts
new file mode 100644
index 0000000000..f44eeb79c1
--- /dev/null
+++ b/public/components/common/field_name/field_type_name.ts
@@ -0,0 +1,60 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { i18n } from '@osd/i18n';
+
+export function getFieldTypeName(type: string) {
+ switch (type) {
+ case 'boolean':
+ return i18n.translate('discover.fieldNameIcons.booleanAriaLabel', {
+ defaultMessage: 'Boolean field',
+ });
+ case 'conflict':
+ return i18n.translate('discover.fieldNameIcons.conflictFieldAriaLabel', {
+ defaultMessage: 'Conflicting field',
+ });
+ case 'date':
+ return i18n.translate('discover.fieldNameIcons.dateFieldAriaLabel', {
+ defaultMessage: 'Date field',
+ });
+ case 'geo_point':
+ return i18n.translate('discover.fieldNameIcons.geoPointFieldAriaLabel', {
+ defaultMessage: 'Geo point field',
+ });
+ case 'geo_shape':
+ return i18n.translate('discover.fieldNameIcons.geoShapeFieldAriaLabel', {
+ defaultMessage: 'Geo shape field',
+ });
+ case 'ip':
+ return i18n.translate('discover.fieldNameIcons.ipAddressFieldAriaLabel', {
+ defaultMessage: 'IP address field',
+ });
+ case 'murmur3':
+ return i18n.translate('discover.fieldNameIcons.murmur3FieldAriaLabel', {
+ defaultMessage: 'Murmur3 field',
+ });
+ case 'number':
+ return i18n.translate('discover.fieldNameIcons.numberFieldAriaLabel', {
+ defaultMessage: 'Number field',
+ });
+ case 'source':
+ // Note that this type is currently not provided, type for _source is undefined
+ return i18n.translate('discover.fieldNameIcons.sourceFieldAriaLabel', {
+ defaultMessage: 'Source field',
+ });
+ case 'string':
+ return i18n.translate('discover.fieldNameIcons.stringFieldAriaLabel', {
+ defaultMessage: 'String field',
+ });
+ case 'nested':
+ return i18n.translate('discover.fieldNameIcons.nestedFieldAriaLabel', {
+ defaultMessage: 'Nested field',
+ });
+ default:
+ return i18n.translate('discover.fieldNameIcons.unknownFieldAriaLabel', {
+ defaultMessage: 'Unknown field',
+ });
+ }
+}
diff --git a/public/components/common/flyout_containers/flyout_containers.tsx b/public/components/common/flyout_containers/flyout_containers.tsx
new file mode 100644
index 0000000000..182a811aac
--- /dev/null
+++ b/public/components/common/flyout_containers/flyout_containers.tsx
@@ -0,0 +1,51 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { EuiFlyout } from '@elastic/eui';
+import React from 'react';
+
+/*
+ * "FlyoutContainers" component used to create flyouts
+ *
+ * Props taken in as params are:
+ * flyoutHeader - header JSX element of flyout
+ * flyoutBody - body JSX element of flyout
+ * flyoutFooter - footer JSX element of flyout
+ * ariaLabel - aria-label for focus of flyout
+ */
+
+type Props = {
+ closeFlyout: () => void;
+ flyoutHeader: JSX.Element;
+ flyoutBody: JSX.Element;
+ flyoutFooter: JSX.Element;
+ ariaLabel: string;
+ size?: string;
+};
+
+export const FlyoutContainers = ({
+ closeFlyout,
+ flyoutHeader,
+ flyoutBody,
+ flyoutFooter,
+ ariaLabel,
+ size,
+}: Props) => {
+ return (
+
+ closeFlyout()}
+ size={size ? size : 'm'}
+ aria-labelledby={ariaLabel}
+ >
+ {flyoutHeader}
+ {flyoutBody}
+ {flyoutFooter}
+
+
+ );
+};
diff --git a/public/components/common/flyout_containers/index.ts b/public/components/common/flyout_containers/index.ts
new file mode 100644
index 0000000000..bff9741937
--- /dev/null
+++ b/public/components/common/flyout_containers/index.ts
@@ -0,0 +1,6 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { FlyoutContainers } from './flyout_containers';
diff --git a/public/components/common/helpers/add_sample_modal.tsx b/public/components/common/helpers/add_sample_modal.tsx
new file mode 100644
index 0000000000..d027b73543
--- /dev/null
+++ b/public/components/common/helpers/add_sample_modal.tsx
@@ -0,0 +1,32 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { EuiOverlayMask, EuiConfirmModal } from '@elastic/eui';
+
+export const getSampleDataModal = (
+ onCancel: (
+ event?: React.KeyboardEvent | React.MouseEvent
+ ) => void,
+ onConfirm: (event?: React.MouseEvent) => void
+) => {
+ return (
+
+
+
+ Do you want to add sample data? This will also add Dashboards sample flights and logs
+ data if they have not been added.
+
+
+
+ );
+};
diff --git a/public/components/common/helpers/delete_modal.tsx b/public/components/common/helpers/delete_modal.tsx
new file mode 100644
index 0000000000..9bf80ec1fb
--- /dev/null
+++ b/public/components/common/helpers/delete_modal.tsx
@@ -0,0 +1,79 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useState } from 'react';
+import {
+ EuiOverlayMask,
+ EuiModal,
+ EuiButton,
+ EuiButtonEmpty,
+ EuiFieldText,
+ EuiForm,
+ EuiFormRow,
+ EuiModalBody,
+ EuiModalFooter,
+ EuiModalHeader,
+ EuiModalHeaderTitle,
+ EuiSpacer,
+ EuiText,
+} from '@elastic/eui';
+
+export const DeleteModal = ({
+ onCancel,
+ onConfirm,
+ title,
+ message,
+}: {
+ onCancel: (
+ event?: React.KeyboardEvent | React.MouseEvent
+ ) => void;
+ onConfirm: (event?: React.MouseEvent) => void;
+ title: string;
+ message: string;
+}) => {
+ const [value, setValue] = useState('');
+ const onChange = (e: React.ChangeEvent) => {
+ setValue(e.target.value);
+ };
+ return (
+
+
+
+ {title}
+
+
+
+ {message}
+ The action cannot be undone.
+
+
+
+ onChange(e)}
+ data-test-subj="popoverModal__deleteTextInput"
+ />
+
+
+
+
+
+ Cancel
+ onConfirm()}
+ color="danger"
+ fill
+ disabled={value !== 'delete'}
+ data-test-subj="popoverModal__deleteButton"
+ >
+ Delete
+
+
+
+
+ );
+};
diff --git a/public/components/common/helpers/format_number_with_commas.ts b/public/components/common/helpers/format_number_with_commas.ts
new file mode 100644
index 0000000000..861f62ad12
--- /dev/null
+++ b/public/components/common/helpers/format_number_with_commas.ts
@@ -0,0 +1,13 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+const COMMA_SEPARATOR_RE = /(\d)(?=(\d{3})+(?!\d))/g;
+
+/**
+ * Converts a number to a string and adds commas
+ * as thousands separators
+ */
+export const formatNumWithCommas = (input: number) =>
+ String(input).replace(COMMA_SEPARATOR_RE, '$1,');
diff --git a/public/components/common/helpers/index.ts b/public/components/common/helpers/index.ts
new file mode 100644
index 0000000000..6aa2e95271
--- /dev/null
+++ b/public/components/common/helpers/index.ts
@@ -0,0 +1,7 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { formatNumWithCommas } from './format_number_with_commas';
+export { PPLReferenceFlyout } from './ppl_reference_flyout';
diff --git a/public/components/common/helpers/ppl_docs/commands/dedup.ts b/public/components/common/helpers/ppl_docs/commands/dedup.ts
new file mode 100644
index 0000000000..2de86921be
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/commands/dedup.ts
@@ -0,0 +1,114 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const dedupCmd = `## dedup
+---
+
+### Description
+
+Using \'dedup\' command to remove identical document defined by field from
+the search result.
+
+### Syntax
+
+dedup \[int\] <field-list> \[keepempty=<bool>\]
+\[consecutive=<bool>\]
+
+- int: optional. The \'dedup\' command retains multiple events for each
+ combination when you specify <int>. The number for <int>
+ must be greater than 0. If you do not specify a number, only the
+ first occurring event is kept. All other duplicates are removed from
+ the results. **Default:** 1
+- keepempty: optional. if true, keep the document if the any field in
+ the field-list has NULL value or field is MISSING. **Default:**
+ false.
+- consecutive: optional. If set to true, removes only events with
+ duplicate combinations of values that are consecutive. **Default:**
+ false.
+- field-list: mandatory. The comma-delimited field list. At least one
+ field is required.
+
+### Example 1: Dedup by one field
+
+The example show dedup the document with gender field.
+
+PPL query:
+
+ os> source=accounts | dedup gender | fields account_number, gender;
+ fetched rows / total rows = 2/2
+ +------------------+----------+
+ | account_number | gender |
+ |------------------+----------|
+ | 1 | M |
+ | 13 | F |
+ +------------------+----------+
+
+### Example 2: Keep 2 duplicates documents
+
+The example show dedup the document with gender field keep 2
+duplication.
+
+PPL query:
+
+ os> source=accounts | dedup 2 gender | fields account_number, gender;
+ fetched rows / total rows = 3/3
+ +------------------+----------+
+ | account_number | gender |
+ |------------------+----------|
+ | 1 | M |
+ | 6 | M |
+ | 13 | F |
+ +------------------+----------+
+
+### Example 3: Keep or Ignore the empty field by default
+
+The example show dedup the document by keep null value field.
+
+PPL query:
+
+ os> source=accounts | dedup email keepempty=true | fields account_number, email;
+ fetched rows / total rows = 4/4
+ +------------------+-----------------------+
+ | account_number | email |
+ |------------------+-----------------------|
+ | 1 | amberduke@pyrami.com |
+ | 6 | hattiebond@netagy.com |
+ | 13 | null |
+ | 18 | daleadams@boink.com |
+ +------------------+-----------------------+
+
+The example show dedup the document by ignore the empty value field.
+
+PPL query:
+
+ os> source=accounts | dedup email | fields account_number, email;
+ fetched rows / total rows = 3/3
+ +------------------+-----------------------+
+ | account_number | email |
+ |------------------+-----------------------|
+ | 1 | amberduke@pyrami.com |
+ | 6 | hattiebond@netagy.com |
+ | 18 | daleadams@boink.com |
+ +------------------+-----------------------+
+
+#### Example 4: Dedup in consecutive document
+
+The example show dedup the consecutive document.
+
+PPL query:
+
+ os> source=accounts | dedup gender consecutive=true | fields account_number, gender;
+ fetched rows / total rows = 3/3
+ +------------------+----------+
+ | account_number | gender |
+ |------------------+----------|
+ | 1 | M |
+ | 13 | F |
+ | 18 | M |
+ +------------------+----------+
+
+#### Limitation
+The \`dedup\` command is not rewritten to OpenSearch DSL, it is only executed on the coordination node.
+`;
\ No newline at end of file
diff --git a/public/components/common/helpers/ppl_docs/commands/eval.ts b/public/components/common/helpers/ppl_docs/commands/eval.ts
new file mode 100644
index 0000000000..52a9429ed1
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/commands/eval.ts
@@ -0,0 +1,79 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const evalCmd = `## eval
+---
+
+### Description
+
+The \'eval\' command evaluate the expression and append the result to the
+search result.
+
+### Syntax
+
+eval <field>=<expression> \[","
+<field>=<expression> \]...
+
+- field: mandatory. If the field name not exist, a new field is added.
+ If the field name already exists, it will be overrided.
+- expression: mandatory. Any expression support by the system.
+
+### Example 1: Create the new field
+
+The example show to create new field doubleAge for each document. The
+new doubleAge is the evaluation result of age multiply by 2.
+
+PPL query:
+
+ os> source=accounts | eval doubleAge = age * 2 | fields age, doubleAge ;
+ fetched rows / total rows = 4/4
+ +-------+-------------+
+ | age | doubleAge |
+ |-------+-------------|
+ | 32 | 64 |
+ | 36 | 72 |
+ | 28 | 56 |
+ | 33 | 66 |
+ +-------+-------------+
+
+### Example 2: Override the existing field
+
+The example show to override the exist age field with age plus 1.
+
+PPL query:
+
+ os> source=accounts | eval age = age + 1 | fields age ;
+ fetched rows / total rows = 4/4
+ +-------+
+ | age |
+ |-------|
+ | 33 |
+ | 37 |
+ | 29 |
+ | 34 |
+ +-------+
+
+### Example 3: Create the new field with field defined in eval
+
+The example show to create a new field ddAge with field defined in eval
+command. The new field ddAge is the evaluation result of doubleAge
+multiply by 2, the doubleAge is defined in the eval command.
+
+PPL query:
+
+ os> source=accounts | eval doubleAge = age * 2, ddAge = doubleAge * 2 | fields age, doubleAge, ddAge ;
+ fetched rows / total rows = 4/4
+ +-------+-------------+---------+
+ | age | doubleAge | ddAge |
+ |-------+-------------+---------|
+ | 32 | 64 | 128 |
+ | 36 | 72 | 144 |
+ | 28 | 56 | 112 |
+ | 33 | 66 | 132 |
+ +-------+-------------+---------+
+
+#### Limitation
+The \`eval\` command is not rewritten to OpenSearch DSL, it is only executed on the coordination node.
+`;
\ No newline at end of file
diff --git a/public/components/common/helpers/ppl_docs/commands/fields.ts b/public/components/common/helpers/ppl_docs/commands/fields.ts
new file mode 100644
index 0000000000..61a6954fd6
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/commands/fields.ts
@@ -0,0 +1,55 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const fieldsCmd = `## fields
+---
+### Description
+
+Using \`fields\` command to keep or remove fields from the search result.
+
+### Syntax
+
+fields \[+\|-\] <field-list>
+
+- index: optional. if the plus (+) is used, only the fields specified
+ in the field list will be keep. if the minus (-) is used, all the
+ fields specified in the field list will be removed. **Default** +
+- field list: mandatory. comma-delimited keep or remove fields.
+
+### Example 1: Select specified fields from result
+
+The example show fetch account\_number, firstname and lastname fields
+from search results.
+
+PPL query:
+
+ os> source=accounts | fields account_number, firstname, lastname;
+ fetched rows / total rows = 4/4
+ +------------------+-------------+------------+
+ | account_number | firstname | lastname |
+ |------------------+-------------+------------|
+ | 1 | Amber | Duke |
+ | 6 | Hattie | Bond |
+ | 13 | Nanette | Bates |
+ | 18 | Dale | Adams |
+ +------------------+-------------+------------+
+
+### Example 2: Remove specified fields from result
+
+The example show fetch remove account\_number field from search results.
+
+PPL query:
+
+ os> source=accounts | fields account_number, firstname, lastname | fields - account_number ;
+ fetched rows / total rows = 4/4
+ +-------------+------------+
+ | firstname | lastname |
+ |-------------+------------|
+ | Amber | Duke |
+ | Hattie | Bond |
+ | Nanette | Bates |
+ | Dale | Adams |
+ +-------------+------------+
+`;
\ No newline at end of file
diff --git a/public/components/common/helpers/ppl_docs/commands/head.ts b/public/components/common/helpers/ppl_docs/commands/head.ts
new file mode 100644
index 0000000000..78ffe7b947
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/commands/head.ts
@@ -0,0 +1,61 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const headCmd = `## head
+---
+
+### Description
+
+The \`head\` command returns the first N number of specified results in
+search order.
+
+### Syntax
+
+head \[N\]
+
+- N: optional. number of results to return. **Default:** 10
+
+### Example 1: Get first 10 results
+
+The example show first 10 results from accounts index.
+
+PPL query:
+
+ os> source=accounts | fields firstname, age | head;
+ fetched rows / total rows = 10/10
+ +---------------+-----------+
+ | firstname | age |
+ |---------------+-----------|
+ | Amber | 32 |
+ | Hattie | 36 |
+ | Nanette | 28 |
+ | Dale | 33 |
+ | Elinor | 36 |
+ | Virginia | 39 |
+ | Dillard | 34 |
+ | Mcgee | 39 |
+ | Aurelia | 37 |
+ | Fulton | 23 |
+ +---------------+-----------+
+
+### Example 2: Get first N results
+
+The example show first N results from accounts index.
+
+PPL query:
+
+ os> source=accounts | fields firstname, age | head 3;
+ fetched rows / total rows = 3/3
+ +---------------+-----------+
+ | firstname | age |
+ |---------------+-----------|
+ | Amber | 32 |
+ | Hattie | 36 |
+ | Nanette | 28 |
+ +---------------+-----------+
+
+#### Limitation
+The \`head\` command is not rewritten to OpenSearch DSL, it is only executed on the coordination node.
+`;
\ No newline at end of file
diff --git a/public/components/common/helpers/ppl_docs/commands/index.ts b/public/components/common/helpers/ppl_docs/commands/index.ts
new file mode 100644
index 0000000000..27328a4c2b
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/commands/index.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { dedupCmd } from './dedup';
+export { evalCmd } from './eval';
+export { fieldsCmd } from './fields';
+export { headCmd } from './head';
+export { parseCmd } from './parse';
+export { rareCmd } from './rare';
+export { renameCmd } from './rename';
+export { searchCmd } from './search';
+export { sortCmd } from './sort';
+export { statsCmd } from './stats';
+export { syntaxCmd } from './syntax';
+export { topCmd } from './top';
+export { whereCmd } from './where';
diff --git a/public/components/common/helpers/ppl_docs/commands/parse.ts b/public/components/common/helpers/ppl_docs/commands/parse.ts
new file mode 100644
index 0000000000..ee752c1ea6
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/commands/parse.ts
@@ -0,0 +1,110 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const parseCmd = `## parse
+---
+### Description
+
+The \`parse\` command parses a text field using a regular expression and append
+the result to the search result.
+
+### Syntax
+
+parse <field> <regular-expression>
+
+- field: mandatory. The field must be a text field.
+- regular-expression: mandatory. The regular expression used to extract new
+fields from given text field. If a new field name already exists, it will
+replace the original field.
+
+### Regular Expression
+
+The regular expression is used to match the whole text field of each document
+with Java regex engine. Each named capture group in the expression will become
+a new \`STRING\` field.
+
+### Example 1: Create the new field
+
+The example shows how to create new field \`host\` for each document. \`host\`
+will be the host name after \`@\` in \`email\` field. Parsing a null field will
+return an empty string.
+
+PPL query:
+
+ os> source=accounts | parse email '.+@(?.+)' | fields email, host ;
+ fetched rows / total rows = 4/4
+ +-----------------------+------------+
+ | email | host |
+ |-----------------------+------------|
+ | amberduke@pyrami.com | pyrami.com |
+ | hattiebond@netagy.com | netagy.com |
+ | null | |
+ | daleadams@boink.com | boink.com |
+ +-----------------------+------------+
+
+### Example 2: Override the existing field
+
+The example shows how to override the existing \`address\` field with street
+number removed.
+
+PPL query:
+
+ os> source=accounts | parse address '\\d+ (?.+)' | fields address ;
+ fetched rows / total rows = 4/4
+ +------------------+
+ | address |
+ |------------------|
+ | Holmes Lane |
+ | Bristol Street |
+ | Madison Street |
+ | Hutchinson Court |
+ +------------------+
+
+### Example 3: Filter and sort by casted parsed field
+
+The example shows how to sort street numbers that are higher than 500 in
+\`address\` field.
+
+PPL query:
+
+ os> source=accounts | parse address '(?\d+) (?.+)' | where cast(streetNumber as int) > 500 | sort num(streetNumber) | fields streetNumber, street ;
+ fetched rows / total rows = 3/3
+ +----------------+----------------+
+ | streetNumber | street |
+ |----------------+----------------|
+ | 671 | Bristol Street |
+ | 789 | Madison Street |
+ | 880 | Holmes Lane |
+ +----------------+----------------+
+
+### Limitation
+
+There are a few limitations with parse command:
+
+- Fields defined by parse cannot be parsed again.
+
+ The following command will not work:
+
+ source=accounts | parse address '\\d+ (?.+)' | parse street '\\w+ (?\\w+)' ;
+
+- Fields defined by parse cannot be overridden with other commands.
+
+ \`where\` will not match any documents since \`street\` cannot be overridden:
+
+ source=accounts | parse address '\\d+ (?.+)' | eval street='1' | where street='1' ;
+
+- The text field used by parse cannot be overridden.
+
+ \`street\` will not be successfully parsed since \`address\` is overridden:
+
+ source=accounts | parse address '\\d+ (?.+)' | eval address='1' ;
+
+- Fields defined by parse cannot be filtered/sorted after using them in
+\`stats\` command.
+
+ \`where\` in the following command will not work:
+
+ source=accounts | parse email '.+@(?.+)' | stats avg(age) by host | where host=pyrami.com ;
+`;
diff --git a/public/components/common/helpers/ppl_docs/commands/rare.ts b/public/components/common/helpers/ppl_docs/commands/rare.ts
new file mode 100644
index 0000000000..37e504f338
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/commands/rare.ts
@@ -0,0 +1,75 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const rareCmd = `## rare
+---
+
+### Description
+
+Using \`rare\` command to find the least common tuple of values of all
+fields in the field list.
+
+**Note**: A maximum of 10 results is returned for each distinct tuple of
+values of the group-by fields.
+
+### Syntax
+
+rare <field-list> \[by-clause\]
+
+- field-list: mandatory. comma-delimited list of field names.
+- by-clause: optional. one or more fields to group the results by.
+
+### Example 1: Find the least common values in a field
+
+The example finds least common gender of all the accounts.
+
+PPL query:
+
+ os> source=accounts | rare gender;
+ fetched rows / total rows = 2/2
+ +------------+
+ | gender |
+ |------------|
+ | F |
+ |------------|
+ | M |
+ +------------+
+
+### Example 2: Find the least common values organized by gender
+
+The example finds least common age of all the accounts group by gender.
+
+PPL query:
+
+ os> source=accounts | rare age by gender;
+ fetched rows / total rows = 20/20
+ +----------+----------+
+ | gender | age |
+ |----------+----------|
+ | F | 29 |
+ | F | 20 |
+ | F | 23 |
+ | F | 25 |
+ | F | 37 |
+ | F | 38 |
+ | F | 40 |
+ | F | 27 |
+ | F | 36 |
+ | F | 24 |
+ | M | 27 |
+ | M | 24 |
+ | M | 34 |
+ | M | 38 |
+ | M | 28 |
+ | M | 39 |
+ | M | 21 |
+ | M | 30 |
+ | M | 25 |
+ | M | 29 |
+ +----------+----------+
+
+#### Limitation
+The \`rare\` command is not rewritten to OpenSearch DSL, it is only executed on the coordination node.
+`;
\ No newline at end of file
diff --git a/public/components/common/helpers/ppl_docs/commands/rename.ts b/public/components/common/helpers/ppl_docs/commands/rename.ts
new file mode 100644
index 0000000000..46238384ba
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/commands/rename.ts
@@ -0,0 +1,57 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const renameCmd = `## rename
+---
+### Description
+
+Using \`rename\` command to rename one or more fields in the search
+result.
+
+### Syntax
+
+rename <source-field> AS <target-field>\[","
+<source-field> AS <target-field>\]...
+
+- source-field: mandatory. The name of the field you want to rename.
+- field list: mandatory. The name you want to rename to.
+
+### Example 1: Rename one field
+
+The example show rename one field.
+
+PPL query:
+
+ os> source=accounts | rename account_number as an | fields an;
+ fetched rows / total rows = 4/4
+ +------+
+ | an |
+ |------|
+ | 1 |
+ | 6 |
+ | 13 |
+ | 18 |
+ +------+
+
+### Example 2: Rename multiple fields
+
+The example show rename multiple fields.
+
+PPL query:
+
+ os> source=accounts | rename account_number as an, employer as emp | fields an, emp;
+ fetched rows / total rows = 4/4
+ +------+---------+
+ | an | emp |
+ |------+---------|
+ | 1 | Pyrami |
+ | 6 | Netagy |
+ | 13 | Quility |
+ | 18 | null |
+ +------+---------+
+
+#### Limitation
+The \`rename\` command is not rewritten to OpenSearch DSL, it is only executed on the coordination node.
+`;
\ No newline at end of file
diff --git a/public/components/common/helpers/ppl_docs/commands/search.ts b/public/components/common/helpers/ppl_docs/commands/search.ts
new file mode 100644
index 0000000000..b54d5a739d
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/commands/search.ts
@@ -0,0 +1,55 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const searchCmd = `## search
+---
+
+### Description
+
+Using \`search\` command to retrieve document from the index. \`search\`
+command could be only used as the first command in the PPL query.
+
+### Syntax
+
+search source=<index> \[boolean-expression\]
+
+- search: search keywords, which could be ignore.
+- index: mandatory. search command must specify which index to query
+ from.
+- bool-expression: optional. any expression which could be evaluated
+ to boolean value.
+
+### Example 1: Fetch all the data
+
+The example show fetch all the document from accounts index.
+
+PPL query:
+
+ os> source=accounts;
+ fetched rows / total rows = 4/4
+ +----------------+-----------+----------------------+---------+--------+--------+----------+-------+-----+-----------------------+----------+
+ | account_number | firstname | address | balance | gender | city | employer | state | age | email | lastname |
+ +----------------+-----------+----------------------+---------+--------+--------+----------+-------+-----+-----------------------+----------+
+ | 1 | Amber | 880 Holmes Lane | 39225 | M | Brogan | Pyrami | IL | 32 | amberduke@pyrami.com | Duke |
+ | 6 | Hattie | 671 Bristol Street | 5686 | M | Dante | Netagy | TN | 36 | hattiebond@netagy.com | Bond |
+ | 13 | Nanette | 789 Madison Street | 32838 | F | Nogal | Quility | VA | 28 | null | Bates |
+ | 18 | Dale | 467 Hutchinson Court | 4180 | M | Orick | null | MD | 33 | daleadams@boink.com | Adams |
+ +----------------+-----------+----------------------+---------+--------+--------+----------+-------+-----+-----------------------+----------+
+
+### Example 2: Fetch data with condition
+
+The example show fetch all the document from accounts index with .
+
+PPL query:
+
+ os> source=accounts account_number=1 or gender="F";
+ fetched rows / total rows = 2/2
+ +------------------+-------------+--------------------+-----------+----------+--------+------------+---------+-------+----------------------+------------+
+ | account_number | firstname | address | balance | gender | city | employer | state | age | email | lastname |
+ |------------------+-------------+--------------------+-----------+----------+--------+------------+---------+-------+----------------------+------------|
+ | 1 | Amber | 880 Holmes Lane | 39225 | M | Brogan | Pyrami | IL | 32 | amberduke@pyrami.com | Duke |
+ | 13 | Nanette | 789 Madison Street | 32838 | F | Nogal | Quility | VA | 28 | null | Bates |
+ +------------------+-------------+--------------------+-----------+----------+--------+------------+---------+-------+----------------------+------------+
+`;
\ No newline at end of file
diff --git a/public/components/common/helpers/ppl_docs/commands/sort.ts b/public/components/common/helpers/ppl_docs/commands/sort.ts
new file mode 100644
index 0000000000..e4c1f94044
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/commands/sort.ts
@@ -0,0 +1,112 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const sortCmd = `## sort
+---
+### Description
+
+Using \`sort\` command to sorts all the search result by the specified
+fields.
+
+### Syntax
+
+sort <\[+\|-\] sort-field>...
+
+- \[+\|-\]: optional. The plus \[+\] stands for ascending order and
+ NULL/MISSING first and a minus \[-\] stands for descending order and
+ NULL/MISSING last. **Default:** ascending order and NULL/MISSING
+ first.
+- sort-field: mandatory. The field used to sort.
+
+### Example 1: Sort by one field
+
+The example show sort all the document with age field in ascending
+order.
+
+PPL query:
+
+ os> source=accounts | sort age | fields account_number, age;
+ fetched rows / total rows = 4/4
+ +------------------+-------+
+ | account_number | age |
+ |------------------+-------|
+ | 13 | 28 |
+ | 1 | 32 |
+ | 18 | 33 |
+ | 6 | 36 |
+ +------------------+-------+
+
+### Example 2: Sort by one field return all the result
+
+The example show sort all the document with age field in ascending
+order.
+
+PPL query:
+
+ os> source=accounts | sort age | fields account_number, age;
+ fetched rows / total rows = 4/4
+ +------------------+-------+
+ | account_number | age |
+ |------------------+-------|
+ | 13 | 28 |
+ | 1 | 32 |
+ | 18 | 33 |
+ | 6 | 36 |
+ +------------------+-------+
+
+### Example 3: Sort by one field in descending order
+
+The example show sort all the document with age field in descending
+order.
+
+PPL query:
+
+ os> source=accounts | sort - age | fields account_number, age;
+ fetched rows / total rows = 4/4
+ +------------------+-------+
+ | account_number | age |
+ |------------------+-------|
+ | 6 | 36 |
+ | 18 | 33 |
+ | 1 | 32 |
+ | 13 | 28 |
+ +------------------+-------+
+
+### Example 4: Sort by multiple field
+
+The example show sort all the document with gender field in ascending
+order and age field in descending.
+
+PPL query:
+
+ os> source=accounts | sort + gender, - age | fields account_number, gender, age;
+ fetched rows / total rows = 4/4
+ +------------------+----------+-------+
+ | account_number | gender | age |
+ |------------------+----------+-------|
+ | 13 | F | 28 |
+ | 6 | M | 36 |
+ | 18 | M | 33 |
+ | 1 | M | 32 |
+ +------------------+----------+-------+
+
+### Example 5: Sort by field include null value
+
+The example show sort employer field by default option (ascending order
+and null first), the result show that null value is in the first row.
+
+PPL query:
+
+ os> source=accounts | sort employer | fields employer;
+ fetched rows / total rows = 4/4
+ +------------+
+ | employer |
+ |------------|
+ | null |
+ | Netagy |
+ | Pyrami |
+ | Quility |
+ +------------+
+`;
\ No newline at end of file
diff --git a/public/components/common/helpers/ppl_docs/commands/stats.ts b/public/components/common/helpers/ppl_docs/commands/stats.ts
new file mode 100644
index 0000000000..a3533193ba
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/commands/stats.ts
@@ -0,0 +1,353 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const statsCmd = `## stats
+---
+
+### Description
+
+Using \`stats\` command to calculate the aggregation from search result.
+
+The following table catalogs the aggregation functions and also
+indicates how the NULL/MISSING values is handled:
+
+| | | |
+|----------|-------------|-------------|
+| Function | NULL | MISSING |
+| COUNT | Not counted | Not counted |
+| SUM | Ignore | Ignore |
+| AVG | Ignore | Ignore |
+| MAX | Ignore | Ignore |
+| MIN | Ignore | Ignore |
+
+### Syntax
+
+stats <aggregation>... \[by-clause\]...
+
+- aggregation: mandatory. A aggregation function. The argument of
+ aggregation must be field.
+- by-clause: optional. The one or more fields to group the results by.
+ **Default**: If no <by-clause> is specified, the stats command
+ returns only one row, which is the aggregation over the entire
+ result set.
+
+### **Aggregation Functions**
+---
+### **COUNT**
+
+**Description**
+
+Usage: Returns a count of the number of expr in the rows retrieved by a
+SELECT statement.
+
+Example:
+
+ os> source=accounts | stats count();
+ fetched rows / total rows = 1/1
+ +-----------+
+ | count() |
+ |-----------|
+ | 4 |
+ +-----------+
+
+### **SUM**
+
+**Description**
+
+Usage: SUM(expr). Returns the sum of expr.
+
+Example:
+
+ os> source=accounts | stats sum(age) by gender;
+ fetched rows / total rows = 2/2
+ +------------+----------+
+ | sum(age) | gender |
+ |------------+----------|
+ | 28 | F |
+ | 101 | M |
+ +------------+----------+
+
+### **AVG**
+
+**Description**
+
+Usage: AVG(expr). Returns the average value of expr.
+
+Example:
+
+ os> source=accounts | stats avg(age) by gender;
+ fetched rows / total rows = 2/2
+ +--------------------+----------+
+ | avg(age) | gender |
+ |--------------------+----------|
+ | 28.0 | F |
+ | 33.666666666666664 | M |
+ +--------------------+----------+
+
+### **MAX**
+
+**Description**
+
+Usage: MAX(expr). Returns the maximum value of expr.
+
+Example:
+
+ os> source=accounts | stats max(age);
+ fetched rows / total rows = 1/1
+ +------------+
+ | max(age) |
+ |------------|
+ | 36 |
+ +------------+
+
+### **MIN**
+
+**Description**
+
+Usage: MIN(expr). Returns the minimum value of expr.
+
+Example:
+
+ os> source=accounts | stats min(age);
+ fetched rows / total rows = 1/1
+ +------------+
+ | min(age) |
+ |------------|
+ | 28 |
+ +------------+
+
+### **VAR\_SAMP**
+
+**Description**
+
+Usage: VAR\_SAMP(expr). Returns the sample variance of expr.
+
+Example:
+
+ os> source=accounts | stats var_samp(age);
+ fetched rows / total rows = 1/1
+ +--------------------+
+ | var_samp(age) |
+ |--------------------|
+ | 10.916666666666666 |
+ +--------------------+
+
+### **VAR\_POP**
+
+**Description**
+
+Usage: VAR\_POP(expr). Returns the population standard variance of expr.
+
+Example:
+
+ os> source=accounts | stats var_pop(age);
+ fetched rows / total rows = 1/1
+ +----------------+
+ | var_pop(age) |
+ |----------------|
+ | 8.1875 |
+ +----------------+
+
+### **STDDEV\_SAMP**
+
+**Description**
+
+Usage: STDDEV\_SAMP(expr). Return the sample standard deviation of expr.
+
+Example:
+
+ os> source=accounts | stats stddev_samp(age);
+ fetched rows / total rows = 1/1
+ +--------------------+
+ | stddev_samp(age) |
+ |--------------------|
+ | 3.304037933599835 |
+ +--------------------+
+
+### **STDDEV\_POP**
+
+**Description**
+
+Usage: STDDEV\_POP(expr). Return the population standard deviation of
+expr.
+
+Example:
+
+ os> source=accounts | stats stddev_pop(age);
+ fetched rows / total rows = 1/1
+ +--------------------+
+ | stddev_pop(age) |
+ |--------------------|
+ | 2.8613807855648994 |
+ +--------------------+
+
+### **By Clause**
+
+The by clause could be the fields and expressions like scalar functions
+and aggregation functions. Besides, the span clause can also be used in
+the by clause to split specific field into buckets in the same interval,
+the stats then does the aggregation by these span buckets.
+
+The span syntax is \`span(field_expr, interval_expr)\`, the unit of the
+interval expression is the natural unit by default. If the field is a
+date and time type field, and the interval is in date/time units, you
+will need to specify the unit in the interval expression. For example,
+to split the field \`age\` into buckets by 10 years, it looks like
+\`span(age, 10)\`. And here is another example of time span, the span to
+split a \`timestamp\` field into hourly intervals, it looks like
+\`span(timestamp, 1h)\`.
+
+Available time unit:
+
+| Span Interval Units |
+|----------------------------|
+| millisecond (ms) |
+| second (s) |
+| minute (m, case sensitive) |
+| hour (h) |
+| day (d) |
+| week (w) |
+| month (M, case sensitive) |
+| quarter (q) |
+| year (y) |
+
+### Example 1: Calculate the count of events
+
+The example show calculate the count of events in the accounts.
+
+PPL query:
+
+ os> source=accounts | stats count();
+ fetched rows / total rows = 1/1
+ +-----------+
+ | count() |
+ |-----------|
+ | 4 |
+ +-----------+
+
+### Example 2: Calculate the average of a field
+
+The example show calculate the average age of all the accounts.
+
+PPL query:
+
+ os> source=accounts | stats avg(age);
+ fetched rows / total rows = 1/1
+ +------------+
+ | avg(age) |
+ |------------|
+ | 32.25 |
+ +------------+
+
+### Example 3: Calculate the average of a field by group
+
+The example show calculate the average age of all the accounts group by
+gender.
+
+PPL query:
+
+ os> source=accounts | stats avg(age) by gender;
+ fetched rows / total rows = 2/2
+ +--------------------+----------+
+ | avg(age) | gender |
+ |--------------------+----------|
+ | 28.0 | F |
+ | 33.666666666666664 | M |
+ +--------------------+----------+
+
+### Example 4: Calculate the average, sum and count of a field by group
+
+The example show calculate the average age, sum age and count of events
+of all the accounts group by gender.
+
+PPL query:
+
+ os> source=accounts | stats avg(age), sum(age), count() by gender;
+ fetched rows / total rows = 2/2
+ +--------------------+------------+-----------+----------+
+ | avg(age) | sum(age) | count() | gender |
+ |--------------------+------------+-----------+----------|
+ | 28.0 | 28 | 1 | F |
+ | 33.666666666666664 | 101 | 3 | M |
+ +--------------------+------------+-----------+----------+
+
+### Example 5: Calculate the maximum of a field
+
+The example calculates the max age of all the accounts.
+
+PPL query:
+
+ os> source=accounts | stats max(age);
+ fetched rows / total rows = 1/1
+ +------------+
+ | max(age) |
+ |------------|
+ | 36 |
+ +------------+
+
+### Example 6: Calculate the maximum and minimum of a field by group
+
+The example calculates the max and min age values of all the accounts
+group by gender.
+
+PPL query:
+
+ os> source=accounts | stats max(age), min(age) by gender;
+ fetched rows / total rows = 2/2
+ +------------+------------+----------+
+ | max(age) | min(age) | gender |
+ |------------+------------+----------|
+ | 28 | 28 | F |
+ | 36 | 32 | M |
+ +------------+------------+----------+
+
+### Example 7: Calculate the distinct count of a field
+
+To get the count of distinct values of a field, you can use
+\`DISTINCT_COUNT\` (or \`DC\`) function instead of \`COUNT\`. The example
+calculates both the count and the distinct count of gender field of all
+the accounts.
+
+PPL query:
+
+ os> source=accounts | stats count(gender), distinct_count(gender);
+ fetched rows / total rows = 1/1
+ +-----------------+--------------------------+
+ | count(gender) | distinct_count(gender) |
+ |-----------------+--------------------------|
+ | 4 | 2 |
+ +-----------------+--------------------------+
+
+### Example 8: Calculate the count by a span
+
+The example gets the count of age by the interval of 10 years.
+
+PPL query:
+
+ os> source=accounts | stats count(age) by span(age, 10) as age_span
+ fetched rows / total rows = 2/2
+ +--------------+------------+
+ | count(age) | age_span |
+ |--------------+------------|
+ | 1 | 20 |
+ | 3 | 30 |
+ +--------------+------------+
+
+### Example 9: Calculate the count by a gender and span
+
+The example gets the count of age by the interval of 10 years and group by gender.
+
+PPL query::
+
+ os> source=accounts | stats count() as cnt by span(age, 5) as age_span, gender
+ fetched rows / total rows = 3/3
+ +-------+------------+----------+
+ | cnt | age_span | gender |
+ |-------+------------+----------|
+ | 1 | 25 | F |
+ | 2 | 30 | M |
+ | 1 | 35 | M |
+ +-------+------------+----------+
+`;
\ No newline at end of file
diff --git a/public/components/common/helpers/ppl_docs/commands/syntax.ts b/public/components/common/helpers/ppl_docs/commands/syntax.ts
new file mode 100644
index 0000000000..b579ac5172
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/commands/syntax.ts
@@ -0,0 +1,27 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const syntaxCmd = `## Syntax
+---
+### Command Order
+
+The PPL query started with \`search\` command to reference a table search
+from. All the following command could be in any order. In the following
+example, \`search\` command refer the accounts index as the source, then
+using fields and where command to do the further processing.
+
+\`\`\`
+search source=accounts
+| where age > 18
+| fields firstname, lastname
+\`\`\`
+
+### Required arguments
+
+Required arguments are shown in angle brackets \< \>.
+
+### Optional arguments
+
+Optional arguments are enclosed in square brackets \[ \].`;
\ No newline at end of file
diff --git a/public/components/common/helpers/ppl_docs/commands/top.ts b/public/components/common/helpers/ppl_docs/commands/top.ts
new file mode 100644
index 0000000000..aa7db2958d
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/commands/top.ts
@@ -0,0 +1,68 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const topCmd = `## top
+---
+### Description
+
+Using \`top\` command to find the most common tuple of values of all
+fields in the field list.
+
+### Syntax
+
+top \[N\] <field-list> \[by-clause\]
+
+- N: number of results to return. **Default**: 10
+- field-list: mandatory. comma-delimited list of field names.
+- by-clause: optional. one or more fields to group the results by.
+
+### Example 1: Find the most common values in a field
+
+The example finds most common gender of all the accounts.
+
+PPL query:
+
+ os> source=accounts | top gender;
+ fetched rows / total rows = 2/2
+ +------------+
+ | gender |
+ |------------|
+ | M |
+ |------------|
+ | F |
+ +------------+
+
+### Example 2: Find the most common values in a field
+
+The example finds most common gender of all the accounts.
+
+PPL query:
+
+ os> source=accounts | top 1 gender;
+ fetched rows / total rows = 1/1
+ +------------+
+ | gender |
+ |------------|
+ | M |
+ +------------+
+
+### Example 3: Find the most common values organized by gender
+
+The example finds most common age of all the accounts group by gender.
+
+PPL query:
+
+ os> source=accounts | top 1 age by gender;
+ fetched rows / total rows = 2/2
+ +----------+----------+
+ | gender | age |
+ |----------+----------|
+ | F | 39 |
+ | M | 31 |
+ +----------+----------+
+
+#### Limitation
+The \`top\` command is not rewritten to OpenSearch DSL, it is only executed on the coordination node.
+`;
diff --git a/public/components/common/helpers/ppl_docs/commands/where.ts b/public/components/common/helpers/ppl_docs/commands/where.ts
new file mode 100644
index 0000000000..9adbcb739e
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/commands/where.ts
@@ -0,0 +1,36 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const whereCmd = `## where
+---
+
+### Description
+
+The \`where\` command bool-expression to filter the search result. The
+\`where\` command only return the result when bool-expression evaluated to
+true.
+
+### Syntax
+
+where <boolean-expression>
+
+- bool-expression: optional. any expression which could be evaluated
+ to boolean value.
+
+### Example 1: Filter result set with condition
+
+The example show fetch all the document from accounts index with .
+
+PPL query:
+
+ os> source=accounts | where account_number=1 or gender="F" | fields account_number, gender;
+ fetched rows / total rows = 2/2
+ +------------------+----------+
+ | account_number | gender |
+ |------------------+----------|
+ | 1 | M |
+ | 13 | F |
+ +------------------+----------+
+`;
diff --git a/public/components/common/helpers/ppl_docs/functions/condition.ts b/public/components/common/helpers/ppl_docs/functions/condition.ts
new file mode 100644
index 0000000000..85e3ed0747
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/functions/condition.ts
@@ -0,0 +1,176 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const conditionFunction = `## Condition
+---
+
+### Description
+
+Usage: isnull(field) return true if field is null.
+
+Argument type: all the supported data type.
+
+Return type: BOOLEAN
+
+Example:
+
+ os> source=accounts | eval result = isnull(employer) | fields result, employer, firstname
+ fetched rows / total rows = 4/4
+ +----------+------------+-------------+
+ | result | employer | firstname |
+ |----------+------------+-------------|
+ | False | Pyrami | Amber |
+ | False | Netagy | Hattie |
+ | False | Quility | Nanette |
+ | True | null | Dale |
+ +----------+------------+-------------+
+
+### **ISNOTNULL**
+
+**Description**
+
+Usage: isnotnull(field) return true if field is not null.
+
+Argument type: all the supported data type.
+
+Return type: BOOLEAN
+
+Example:
+
+ os> source=accounts | where not isnotnull(employer) | fields account_number, employer
+ fetched rows / total rows = 1/1
+ +------------------+------------+
+ | account_number | employer |
+ |------------------+------------|
+ | 18 | null |
+ +------------------+------------+
+
+### **EXISTS**
+
+[Because OpenSearch doesn't differentiate null and
+missing](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-exists-query.html).
+so we can't provide function like ismissing/isnotmissing to test field
+exist or not. But you can still use isnull/isnotnull for such purpose.
+
+Example, the account 13 doesn't have email field:
+
+ os> source=accounts | where isnull(email) | fields account_number, email
+ fetched rows / total rows = 1/1
+ +------------------+---------+
+ | account_number | email |
+ |------------------+---------|
+ | 13 | null |
+ +------------------+---------+
+
+### **IFNULL**
+
+**Description**
+
+Usage: ifnull(field1, field2) return field2 if field1 is null.
+
+Argument type: all the supported data type, (NOTE : if two parameters
+has different type, you will fail semantic check.)
+
+Return type: any
+
+Example:
+
+ os> source=accounts | eval result = ifnull(employer, 'default') | fields result, employer, firstname
+ fetched rows / total rows = 4/4
+ +----------+------------+-------------+
+ | result | employer | firstname |
+ |----------+------------+-------------|
+ | Pyrami | Pyrami | Amber |
+ | Netagy | Netagy | Hattie |
+ | Quility | Quility | Nanette |
+ | default | null | Dale |
+ +----------+------------+-------------+
+
+### **NULLIF**
+
+**Description**
+
+Usage: nullif(field1, field2) return null if two parameters are same,
+otherwiser return field1.
+
+Argument type: all the supported data type, (NOTE : if two parameters
+has different type, if two parameters has different type, you will fail
+semantic check)
+
+Return type: any
+
+Example:
+
+ os> source=accounts | eval result = nullif(employer, 'Pyrami') | fields result, employer, firstname
+ fetched rows / total rows = 4/4
+ +----------+------------+-------------+
+ | result | employer | firstname |
+ |----------+------------+-------------|
+ | null | Pyrami | Amber |
+ | Netagy | Netagy | Hattie |
+ | Quility | Quility | Nanette |
+ | null | null | Dale |
+ +----------+------------+-------------+
+
+### **ISNULL**
+
+**Description**
+
+Usage: isnull(field1, field2) return null if two parameters are same,
+otherwise return field1.
+
+Argument type: all the supported data type
+
+Return type: any
+
+Example:
+
+ os> source=accounts | eval result = isnull(employer) | fields result, employer, firstname
+ fetched rows / total rows = 4/4
+ +----------+------------+-------------+
+ | result | employer | firstname |
+ |----------+------------+-------------|
+ | False | Pyrami | Amber |
+ | False | Netagy | Hattie |
+ | False | Quility | Nanette |
+ | True | null | Dale |
+ +----------+------------+-------------+
+
+### **IF**
+
+**Description**
+
+Usage: if(condition, expr1, expr2) return expr1 if condition is true,
+otherwiser return expr2.
+
+Argument type: all the supported data type, (NOTE : if expr1 and expr2
+are different type, you will fail semantic check
+
+Return type: any
+
+Example:
+
+ os> source=accounts | eval result = if(true, firstname, lastname) | fields result, firstname, lastname
+ fetched rows / total rows = 4/4
+ +----------+-------------+------------+
+ | result | firstname | lastname |
+ |----------+-------------+------------|
+ | Amber | Amber | Duke |
+ | Hattie | Hattie | Bond |
+ | Nanette | Nanette | Bates |
+ | Dale | Dale | Adams |
+ +----------+-------------+------------+
+
+ os> source=accounts | eval result = if(false, firstname, lastname) | fields result, firstname, lastname
+ fetched rows / total rows = 4/4
+ +----------+-------------+------------+
+ | result | firstname | lastname |
+ |----------+-------------+------------|
+ | Duke | Amber | Duke |
+ | Bond | Hattie | Bond |
+ | Bates | Nanette | Bates |
+ | Adams | Dale | Adams |
+ +----------+-------------+------------+
+`;
diff --git a/public/components/common/helpers/ppl_docs/functions/datetime.ts b/public/components/common/helpers/ppl_docs/functions/datetime.ts
new file mode 100644
index 0000000000..a593b1c560
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/functions/datetime.ts
@@ -0,0 +1,640 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const datetimeFunction = `## Datetime
+---
+
+### **ADDDATE**
+
+Description
+
+Usage: adddate(date, INTERVAL expr unit)/ adddate(date, expr) adds the
+time interval of second argument to date; adddate(date, days) adds the
+second argument as integer number of days to date.
+
+Argument type: DATE/DATETIME/TIMESTAMP/STRING, INTERVAL/LONG
+
+Return type map:
+
+(DATE/DATETIME/TIMESTAMP/STRING, INTERVAL) -> DATETIME
+
+(DATE, LONG) -> DATE
+
+(DATETIME/TIMESTAMP/STRING, LONG) -> DATETIME
+
+Synonyms: [DATE\_ADD](#date_add)
+
+Example:
+
+ os> source=people | eval \`ADDDATE(DATE('2020-08-26'), INTERVAL 1 HOUR)\` = ADDDATE(DATE('2020-08-26'), INTERVAL 1 HOUR), \`ADDDATE(DATE('2020-08-26'), 1)\` = ADDDATE(DATE('2020-08-26'), 1), \`ADDDATE(TIMESTAMP('2020-08-26 01:01:01'), 1)\` = ADDDATE(TIMESTAMP('2020-08-26 01:01:01'), 1) | fields \`ADDDATE(DATE('2020-08-26'), INTERVAL 1 HOUR)\`, \`ADDDATE(DATE('2020-08-26'), 1)\`, \`ADDDATE(TIMESTAMP('2020-08-26 01:01:01'), 1)\`
+ fetched rows / total rows = 1/1
+ +------------------------------------------------+----------------------------------+------------------------------------------------+
+ | ADDDATE(DATE('2020-08-26'), INTERVAL 1 HOUR) | ADDDATE(DATE('2020-08-26'), 1) | ADDDATE(TIMESTAMP('2020-08-26 01:01:01'), 1) |
+ |------------------------------------------------+----------------------------------+------------------------------------------------|
+ | 2020-08-26 01:00:00 | 2020-08-27 | 2020-08-27 01:01:01 |
+ +------------------------------------------------+----------------------------------+------------------------------------------------+
+
+### **DATE**
+
+**Description**
+
+Usage: date(expr) constructs a date type with the input string expr as a
+date. If the argument is of date/datetime/timestamp, it extracts the
+date value part from the expression.
+
+Argument type: STRING/DATE/DATETIME/TIMESTAMP
+
+Return type: DATE
+
+Example:
+
+ >od source=people | eval \`DATE('2020-08-26')\` = DATE('2020-08-26'), \`DATE(TIMESTAMP('2020-08-26 13:49:00'))\` = DATE(TIMESTAMP('2020-08-26 13:49:00')) | fields \`DATE('2020-08-26')\`, \`DATE(TIMESTAMP('2020-08-26 13:49:00'))\`
+ fetched rows / total rows = 1/1
+ +----------------------+------------------------------------------+
+ | DATE('2020-08-26') | DATE(TIMESTAMP('2020-08-26 13:49:00')) |
+ |----------------------+------------------------------------------|
+ | DATE '2020-08-26' | DATE '2020-08-26' |
+ +----------------------+------------------------------------------+
+
+### **DATE\_ADD**
+
+**Description**
+
+Usage: date\_add(date, INTERVAL expr unit)/ date\_add(date, expr) adds
+the time interval expr to date
+
+Argument type: DATE/DATETIME/TIMESTAMP/STRING, INTERVAL/LONG
+
+Return type map:
+
+DATE/DATETIME/TIMESTAMP/STRING, INTERVAL -> DATETIME
+
+DATE, LONG -> DATE
+
+DATETIME/TIMESTAMP/STRING, LONG -> DATETIME
+
+Synonyms: [ADDDATE](#adddate)
+
+Example:
+
+ os> source=people | eval \`DATE_ADD(DATE('2020-08-26'), INTERVAL 1 HOUR)\` = DATE_ADD(DATE('2020-08-26'), INTERVAL 1 HOUR), \`DATE_ADD(DATE('2020-08-26'), 1)\` = DATE_ADD(DATE('2020-08-26'), 1), \`DATE_ADD(TIMESTAMP('2020-08-26 01:01:01'), 1)\` = DATE_ADD(TIMESTAMP('2020-08-26 01:01:01'), 1) | fields \`DATE_ADD(DATE('2020-08-26'), INTERVAL 1 HOUR)\`, \`DATE_ADD(DATE('2020-08-26'), 1)\`, \`DATE_ADD(TIMESTAMP('2020-08-26 01:01:01'), 1)\`
+ fetched rows / total rows = 1/1
+ +-------------------------------------------------+-----------------------------------+-------------------------------------------------+
+ | DATE_ADD(DATE('2020-08-26'), INTERVAL 1 HOUR) | DATE_ADD(DATE('2020-08-26'), 1) | DATE_ADD(TIMESTAMP('2020-08-26 01:01:01'), 1) |
+ |-------------------------------------------------+-----------------------------------+-------------------------------------------------|
+ | 2020-08-26 01:00:00 | 2020-08-27 | 2020-08-27 01:01:01 |
+ +-------------------------------------------------+-----------------------------------+-------------------------------------------------+
+
+### **DATE\_FORMAT**
+
+**Description**
+
+Usage: date\_format(date, format) formats the date argument using the
+specifiers in the format argument.
+
+| Specifier | Description |
+|-----------|--------------------------------------------------------------------------------------------------|
+| %a | Abbreviated weekday name (Sun..Sat) |
+| %b | Abbreviated month name (Jan..Dec) |
+| %c | Month, numeric (0..12) |
+| %D | Day of the month with English suffix (0th, 1st, 2nd, 3rd, …) |
+| %d | Day of the month, numeric (00..31) |
+| %e | Day of the month, numeric (0..31) |
+| %f | Microseconds (000000..999999) |
+| %H | Hour (00..23) |
+| %h | Hour (01..12) |
+| %I | Hour (01..12) |
+| %i | Minutes, numeric (00..59) |
+| %j | Day of year (001..366) |
+| %k | Hour (0..23) |
+| %l | Hour (1..12) |
+| %M | Month name (January..December) |
+| %m | Month, numeric (00..12) |
+| %p | AM or PM |
+| %r | Time, 12-hour (hh:mm:ss followed by AM or PM) |
+| %S | Seconds (00..59) |
+| %s | Seconds (00..59) |
+| %T | Time, 24-hour (hh:mm:ss) |
+| %U | Week (00..53), where Sunday is the first day of the week; WEEK() mode 0 |
+| %u | Week (00..53), where Monday is the first day of the week; WEEK() mode 1 |
+| %V | Week (01..53), where Sunday is the first day of the week; WEEK() mode 2; used with %X |
+| %v | Week (01..53), where Monday is the first day of the week; WEEK() mode 3; used with %x |
+| %W | Weekday name (Sunday..Saturday) |
+| %w | Day of the week (0=Sunday..6=Saturday) |
+| %X | Year for the week where Sunday is the first day of the week, numeric, four digits; used with %V |
+| %x | Year for the week, where Monday is the first day of the week, numeric, four digits; used with %v |
+| %Y | Year, numeric, four digits |
+| %y | Year, numeric (two digits) |
+| %% | A literal % character |
+| %x | x, for any “x” not listed above |
+
+The following table describes the available specifier arguments.
+
+Argument type: STRING/DATE/DATETIME/TIMESTAMP, STRING
+
+Return type: STRING
+
+Example:
+
+ >od source=people | eval \`DATE_FORMAT('1998-01-31 13:14:15.012345', '%T.%f')\` = DATE_FORMAT('1998-01-31 13:14:15.012345', '%T.%f'), \`DATE_FORMAT(TIMESTAMP('1998-01-31 13:14:15.012345'), '%Y-%b-%D %r')\` = DATE_FORMAT(TIMESTAMP('1998-01-31 13:14:15.012345'), '%Y-%b-%D %r') | fields \`DATE_FORMAT('1998-01-31 13:14:15.012345', '%T.%f')\`, \`DATE_FORMAT(TIMESTAMP('1998-01-31 13:14:15.012345'), '%Y-%b-%D %r')\`
+ fetched rows / total rows = 1/1
+ +-----------------------------------------------+----------------------------------------------------------------+
+ | DATE('1998-01-31 13:14:15.012345', '%T.%f') | DATE(TIMESTAMP('1998-01-31 13:14:15.012345'), '%Y-%b-%D %r') |
+ |-----------------------------------------------+----------------------------------------------------------------|
+ | '13:14:15.012345' | '1998-Jan-31st 01:14:15 PM' |
+ +-----------------------------------------------+----------------------------------------------------------------+
+
+### **DATE\_SUB**
+
+**Description**
+
+Usage: date\_sub(date, INTERVAL expr unit)/ date\_sub(date, expr)
+subtracts the time interval expr from date
+
+Argument type: DATE/DATETIME/TIMESTAMP/STRING, INTERVAL/LONG
+
+Return type map:
+
+DATE/DATETIME/TIMESTAMP/STRING, INTERVAL -> DATETIME
+
+DATE, LONG -> DATE
+
+DATETIME/TIMESTAMP/STRING, LONG -> DATETIME
+
+Synonyms: [SUBDATE](#subdate)
+
+Example:
+
+ os> source=people | eval \`DATE_SUB(DATE('2008-01-02'), INTERVAL 31 DAY)\` = DATE_SUB(DATE('2008-01-02'), INTERVAL 31 DAY), \`DATE_SUB(DATE('2020-08-26'), 1)\` = DATE_SUB(DATE('2020-08-26'), 1), \`DATE_SUB(TIMESTAMP('2020-08-26 01:01:01'), 1)\` = DATE_SUB(TIMESTAMP('2020-08-26 01:01:01'), 1) | fields \`DATE_SUB(DATE('2008-01-02'), INTERVAL 31 DAY)\`, \`DATE_SUB(DATE('2020-08-26'), 1)\`, \`DATE_SUB(TIMESTAMP('2020-08-26 01:01:01'), 1)\`
+ fetched rows / total rows = 1/1
+ +-------------------------------------------------+-----------------------------------+-------------------------------------------------+
+ | DATE_SUB(DATE('2008-01-02'), INTERVAL 31 DAY) | DATE_SUB(DATE('2020-08-26'), 1) | DATE_SUB(TIMESTAMP('2020-08-26 01:01:01'), 1) |
+ |-------------------------------------------------+-----------------------------------+-------------------------------------------------|
+ | 2007-12-02 | 2020-08-25 | 2020-08-25 01:01:01 |
+ +-------------------------------------------------+-----------------------------------+-------------------------------------------------+
+
+### **DAY**
+
+**Description**
+
+Usage: day(date) extracts the day of the month for date, in the range 1
+to 31. The dates with value 0 such as '0000-00-00' or '2008-00-00' are
+invalid.
+
+Argument type: STRING/DATE/DATETIME/TIMESTAMP
+
+Return type: INTEGER
+
+Synonyms: DAYOFMONTH
+
+Example:
+
+ os> source=people | eval \`DAY(DATE('2020-08-26'))\` = DAY(DATE('2020-08-26')) | fields \`DAY(DATE('2020-08-26'))\`
+ fetched rows / total rows = 1/1
+ +---------------------------+
+ | DAY(DATE('2020-08-26')) |
+ |---------------------------|
+ | 26 |
+ +---------------------------+
+
+### **DAYNAME**
+
+**Description**
+
+Usage: dayname(date) returns the name of the weekday for date, including
+Monday, Tuesday, Wednesday, Thursday, Friday, Saturday and Sunday.
+
+Argument type: STRING/DATE/DATETIME/TIMESTAMP
+
+Return type: STRING
+
+Example:
+
+ os> source=people | eval \`DAYNAME(DATE('2020-08-26'))\` = DAYNAME(DATE('2020-08-26')) | fields \`DAYNAME(DATE('2020-08-26'))\`
+ fetched rows / total rows = 1/1
+ +-------------------------------+
+ | DAYNAME(DATE('2020-08-26')) |
+ |-------------------------------|
+ | Wednesday |
+ +-------------------------------+
+
+### **DAYOFMONTH**
+
+**Description**
+
+Usage: dayofmonth(date) extracts the day of the month for date, in the
+range 1 to 31. The dates with value 0 such as '0000-00-00' or
+'2008-00-00' are invalid.
+
+Argument type: STRING/DATE/DATETIME/TIMESTAMP
+
+Return type: INTEGER
+
+Synonyms: DAY
+
+Example:
+
+ os> source=people | eval \`DAYOFMONTH(DATE('2020-08-26'))\` = DAYOFMONTH(DATE('2020-08-26')) | fields \`DAYOFMONTH(DATE('2020-08-26'))\`
+ fetched rows / total rows = 1/1
+ +----------------------------------+
+ | DAYOFMONTH(DATE('2020-08-26')) |
+ |----------------------------------|
+ | 26 |
+ +----------------------------------+
+
+### **DAYOFWEEK**
+
+**Description**
+
+Usage: dayofweek(date) returns the weekday index for date (1 = Sunday, 2
+= Monday, …, 7 = Saturday).
+
+Argument type: STRING/DATE/DATETIME/TIMESTAMP
+
+Return type: INTEGER
+
+Example:
+
+ os> source=people | eval \`DAYOFWEEK(DATE('2020-08-26'))\` = DAYOFWEEK(DATE('2020-08-26')) | fields \`DAYOFWEEK(DATE('2020-08-26'))\`
+ fetched rows / total rows = 1/1
+ +---------------------------------+
+ | DAYOFWEEK(DATE('2020-08-26')) |
+ |---------------------------------|
+ | 4 |
+ +---------------------------------+
+
+### **DAYOFYEAR**
+
+**Description**
+
+Usage: dayofyear(date) returns the day of the year for date, in the
+range 1 to 366.
+
+Argument type: STRING/DATE/DATETIME/TIMESTAMP
+
+Return type: INTEGER
+
+Example:
+
+ os> source=people | eval \`DAYOFYEAR(DATE('2020-08-26'))\` = DAYOFYEAR(DATE('2020-08-26')) | fields \`DAYOFYEAR(DATE('2020-08-26'))\`
+ fetched rows / total rows = 1/1
+ +---------------------------------+
+ | DAYOFYEAR(DATE('2020-08-26')) |
+ |---------------------------------|
+ | 239 |
+ +---------------------------------+
+
+### **FROM\_DAYS**
+
+**Description**
+
+Usage: from\_days(N) returns the date value given the day number N.
+
+Argument type: INTEGER/LONG
+
+Return type: DATE
+
+Example:
+
+ os> source=people | eval \`FROM_DAYS(733687)\` = FROM_DAYS(733687) | fields \`FROM_DAYS(733687)\`
+ fetched rows / total rows = 1/1
+ +---------------------+
+ | FROM_DAYS(733687) |
+ |---------------------|
+ | 2008-10-07 |
+ +---------------------+
+
+### **HOUR**
+
+**Description**
+
+Usage: hour(time) extracts the hour value for time. Different from the
+time of day value, the time value has a large range and can be greater
+than 23, so the return value of hour(time) can be also greater than 23.
+
+Argument type: STRING/TIME/DATETIME/TIMESTAMP
+
+Return type: INTEGER
+
+Example:
+
+ os> source=people | eval \`HOUR(TIME('01:02:03'))\` = HOUR(TIME('01:02:03')) | fields \`HOUR(TIME('01:02:03'))\`
+ fetched rows / total rows = 1/1
+ +--------------------------+
+ | HOUR(TIME('01:02:03')) |
+ |--------------------------|
+ | 1 |
+ +--------------------------+
+
+### **MAKETIME**
+
+**Description**
+
+Specifications:
+
+1. MAKETIME(INTEGER, INTEGER, INTEGER) -> DATE
+
+### **MICROSECOND**
+
+**Description**
+
+Usage: microsecond(expr) returns the microseconds from the time or
+datetime expression expr as a number in the range from 0 to 999999.
+
+Argument type: STRING/TIME/DATETIME/TIMESTAMP
+
+Return type: INTEGER
+
+Example:
+
+ os> source=people | eval \`MICROSECOND(TIME('01:02:03.123456'))\` = MICROSECOND(TIME('01:02:03.123456')) | fields \`MICROSECOND(TIME('01:02:03.123456'))\`
+ fetched rows / total rows = 1/1
+ +----------------------------------------+
+ | MICROSECOND(TIME('01:02:03.123456')) |
+ |----------------------------------------|
+ | 123456 |
+ +----------------------------------------+
+
+### **MINUTE**
+
+**Description**
+
+Usage: minute(time) returns the minute for time, in the range 0 to 59.
+
+Argument type: STRING/TIME/DATETIME/TIMESTAMP
+
+Return type: INTEGER
+
+Example:
+
+ os> source=people | eval \`MINUTE(TIME('01:02:03'))\` = MINUTE(TIME('01:02:03')) | fields \`MINUTE(TIME('01:02:03'))\`
+ fetched rows / total rows = 1/1
+ +----------------------------+
+ | MINUTE(TIME('01:02:03')) |
+ |----------------------------|
+ | 2 |
+ +----------------------------+
+
+### **MONTH**
+
+**Description**
+
+Usage: month(date) returns the month for date, in the range 1 to 12 for
+January to December. The dates with value 0 such as '0000-00-00' or
+'2008-00-00' are invalid.
+
+Argument type: STRING/DATE/DATETIME/TIMESTAMP
+
+Return type: INTEGER
+
+Example:
+
+ os> source=people | eval \`MONTH(DATE('2020-08-26'))\` = MONTH(DATE('2020-08-26')) | fields \`MONTH(DATE('2020-08-26'))\`
+ fetched rows / total rows = 1/1
+ +-----------------------------+
+ | MONTH(DATE('2020-08-26')) |
+ |-----------------------------|
+ | 8 |
+ +-----------------------------+
+
+### **MONTHNAME**
+
+**Description**
+
+Usage: monthname(date) returns the full name of the month for date.
+
+Argument type: STRING/DATE/DATETIME/TIMESTAMP
+
+Return type: STRING
+
+Example:
+
+ os> source=people | eval \`MONTHNAME(DATE('2020-08-26'))\` = MONTHNAME(DATE('2020-08-26')) | fields \`MONTHNAME(DATE('2020-08-26'))\`
+ fetched rows / total rows = 1/1
+ +---------------------------------+
+ | MONTHNAME(DATE('2020-08-26')) |
+ |---------------------------------|
+ | August |
+ +---------------------------------+
+
+### **NOW**
+
+**Description**
+
+Specifications:
+
+1. NOW() -> DATE
+
+### **QUARTER**
+
+**Description**
+
+Usage: quarter(date) returns the quarter of the year for date, in the
+range 1 to 4.
+
+Argument type: STRING/DATE/DATETIME/TIMESTAMP
+
+Return type: INTEGER
+
+Example:
+
+ os> source=people | eval \`QUARTER(DATE('2020-08-26'))\` = QUARTER(DATE('2020-08-26')) | fields \`QUARTER(DATE('2020-08-26'))\`
+ fetched rows / total rows = 1/1
+ +-------------------------------+
+ | QUARTER(DATE('2020-08-26')) |
+ |-------------------------------|
+ | 3 |
+ +-------------------------------+
+
+### **SECOND**
+
+**Description**
+
+Usage: second(time) returns the second for time, in the range 0 to 59.
+
+Argument type: STRING/TIME/DATETIME/TIMESTAMP
+
+Return type: INTEGER
+
+Example:
+
+ os> source=people | eval \`SECOND(TIME('01:02:03'))\` = SECOND(TIME('01:02:03')) | fields \`SECOND(TIME('01:02:03'))\`
+ fetched rows / total rows = 1/1
+ +----------------------------+
+ | SECOND(TIME('01:02:03')) |
+ |----------------------------|
+ | 3 |
+ +----------------------------+
+
+### **SUBDATE**
+
+**Description**
+
+Usage: subdate(date, INTERVAL expr unit)/ subdate(date, expr) subtracts
+the time interval expr from date
+
+Argument type: DATE/DATETIME/TIMESTAMP/STRING, INTERVAL/LONG
+
+Return type map:
+
+DATE/DATETIME/TIMESTAMP/STRING, INTERVAL -> DATETIME
+
+DATE, LONG -> DATE
+
+DATETIME/TIMESTAMP/STRING, LONG -> DATETIME
+
+Synonyms: [DATE\_SUB](#date_sub)
+
+Example:
+
+ os> source=people | eval \`SUBDATE(DATE('2008-01-02'), INTERVAL 31 DAY)\` = SUBDATE(DATE('2008-01-02'), INTERVAL 31 DAY), \`SUBDATE(DATE('2020-08-26'), 1)\` = SUBDATE(DATE('2020-08-26'), 1), \`SUBDATE(TIMESTAMP('2020-08-26 01:01:01'), 1)\` = SUBDATE(TIMESTAMP('2020-08-26 01:01:01'), 1) | fields \`SUBDATE(DATE('2008-01-02'), INTERVAL 31 DAY)\`, \`SUBDATE(DATE('2020-08-26'), 1)\`, \`SUBDATE(TIMESTAMP('2020-08-26 01:01:01'), 1)\`
+ fetched rows / total rows = 1/1
+ +------------------------------------------------+----------------------------------+------------------------------------------------+
+ | SUBDATE(DATE('2008-01-02'), INTERVAL 31 DAY) | SUBDATE(DATE('2020-08-26'), 1) | SUBDATE(TIMESTAMP('2020-08-26 01:01:01'), 1) |
+ |------------------------------------------------+----------------------------------+------------------------------------------------|
+ | 2007-12-02 | 2020-08-25 | 2020-08-25 01:01:01 |
+ +------------------------------------------------+----------------------------------+------------------------------------------------+
+
+### **TIME**
+
+**Description**
+
+Usage: time(expr) constructs a time type with the input string expr as a
+time. If the argument is of date/datetime/time/timestamp, it extracts
+the time value part from the expression.
+
+Argument type: STRING/DATE/DATETIME/TIME/TIMESTAMP
+
+Return type: TIME
+
+Example:
+
+ >od source=people | eval \`TIME('13:49:00')\` = TIME('13:49:00'), \`TIME(TIMESTAMP('2020-08-26 13:49:00'))\` = TIME(TIMESTAMP('2020-08-26 13:49:00')) | fields \`TIME('13:49:00')\`, \`TIME(TIMESTAMP('2020-08-26 13:49:00'))\`
+ fetched rows / total rows = 1/1
+ +--------------------+------------------------------------------+
+ | TIME('13:49:00') | TIME(TIMESTAMP('2020-08-26 13:49:00')) |
+ |--------------------+------------------------------------------|
+ | TIME '13:49:00' | TIME '13:49:00' |
+ +--------------------+------------------------------------------+
+
+### **TIME\_TO\_SEC**
+
+**Description**
+
+Usage: time\_to\_sec(time) returns the time argument, converted to
+seconds.
+
+Argument type: STRING/TIME/DATETIME/TIMESTAMP
+
+Return type: LONG
+
+Example:
+
+ os> source=people | eval \`TIME_TO_SEC(TIME('22:23:00'))\` = TIME_TO_SEC(TIME('22:23:00')) | fields \`TIME_TO_SEC(TIME('22:23:00'))\`
+ fetched rows / total rows = 1/1
+ +---------------------------------+
+ | TIME_TO_SEC(TIME('22:23:00')) |
+ |---------------------------------|
+ | 80580 |
+ +---------------------------------+
+
+### **TIMESTAMP**
+
+**Description**
+
+Usage: timestamp(expr) construct a timestamp type with the input string
+expr as an timestamp. If the argument is of date/datetime/timestamp
+type, cast expr to timestamp type with default timezone UTC.
+
+Argument type: STRING/DATE/DATETIME/TIMESTAMP
+
+Return type: TIMESTAMP
+
+Example:
+
+ >od source=people | eval \`TIMESTAMP('2020-08-26 13:49:00')\` = TIMESTAMP('2020-08-26 13:49:00') | fields \`TIMESTAMP('2020-08-26 13:49:00')\`
+ fetched rows / total rows = 1/1
+ +------------------------------------+
+ | TIMESTAMP('2020-08-26 13:49:00') |
+ |------------------------------------|
+ | TIMESTAMP '2020-08-26 13:49:00 |
+ +------------------------------------+
+
+### **TO\_DAYS**
+
+**Description**
+
+Usage: to\_days(date) returns the day number (the number of days since
+year 0) of the given date. Returns NULL if date is invalid.
+
+Argument type: STRING/DATE/DATETIME/TIMESTAMP
+
+Return type: LONG
+
+Example:
+
+ os> source=people | eval \`TO_DAYS(DATE('2008-10-07'))\` = TO_DAYS(DATE('2008-10-07')) | fields \`TO_DAYS(DATE('2008-10-07'))\`
+ fetched rows / total rows = 1/1
+ +-------------------------------+
+ | TO_DAYS(DATE('2008-10-07')) |
+ |-------------------------------|
+ | 733687 |
+ +-------------------------------+
+
+### **WEEK**
+
+**Description**
+
+Usage: week(date\[, mode\]) returns the week number for date. If the
+mode argument is omitted, the default mode 0 is used.
+
+| Mode | First day of week | Range | Week 1 is the first week … |
+|------|-------------------|-------|-------------------------------|
+| 0 | Sunday | 0-53 | with a Sunday in this year |
+| 1 | Monday | 0-53 | with 4 or more days this year |
+| 2 | Sunday | 1-53 | with a Sunday in this year |
+| 3 | Monday | 1-53 | with 4 or more days this year |
+| 4 | Sunday | 0-53 | with 4 or more days this year |
+| 5 | Monday | 0-53 | with a Monday in this year |
+| 6 | Sunday | 1-53 | with 4 or more days this year |
+| 7 | Monday | 1-53 | with a Monday in this year |
+
+The following table describes how the mode argument works.
+
+Argument type: DATE/DATETIME/TIMESTAMP/STRING
+
+Return type: INTEGER
+
+Example:
+
+ >od source=people | eval \`WEEK(DATE('2008-02-20'))\` = WEEK(DATE('2008-02-20')), \`WEEK(DATE('2008-02-20'), 1)\` = WEEK(DATE('2008-02-20'), 1) | fields \`WEEK(DATE('2008-02-20'))\`, \`WEEK(DATE('2008-02-20'), 1)\`
+ fetched rows / total rows = 1/1
+ +----------------------------+-------------------------------+
+ | WEEK(DATE('2008-02-20')) | WEEK(DATE('2008-02-20'), 1) |
+ |----------------------------|-------------------------------|
+ | 7 | 8 |
+ +----------------------------+-------------------------------+
+
+### **YEAR**
+
+**Description**
+
+Usage: year(date) returns the year for date, in the range 1000 to 9999,
+or 0 for the “zero” date.
+
+Argument type: STRING/DATE/DATETIME/TIMESTAMP
+
+Return type: INTEGER
+
+Example:
+
+ os> source=people | eval \`YEAR(DATE('2020-08-26'))\` = YEAR(DATE('2020-08-26')) | fields \`YEAR(DATE('2020-08-26'))\`
+ fetched rows / total rows = 1/1
+ +----------------------------+
+ | YEAR(DATE('2020-08-26')) |
+ |----------------------------|
+ | 2020 |
+ +----------------------------+
+`;
diff --git a/public/components/common/helpers/ppl_docs/functions/full_text_search.ts b/public/components/common/helpers/ppl_docs/functions/full_text_search.ts
new file mode 100644
index 0000000000..4704df6ade
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/functions/full_text_search.ts
@@ -0,0 +1,82 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const fullTextSearchFunction = `## Full Text Search
+---
+
+The full text search based functions enable users to search the index for
+documents by the full text search of the input query. The functions are built
+on the top of the search queries of the OpenSearch engine, but in memory
+execution within the plugin is not supported. These functions are able
+to perform the global filter of a query, for example the condition
+expression in a \`WHERE\` clause or in a \`HAVING\` clause. For more details
+of the full text search based search, check out the design here: [Relevance
+Based Search With SQL/PPL Query
+Engine](https://github.com/opensearch-project/sql/issues/182)
+
+### MATCH
+
+**Description**
+
+\`match(field_expression, query_expression[, option=]*)\`
+
+The match function maps to the match query used in search engine, to
+return the documents that match a provided text, number, date or boolean
+value with a given field. Available parameters include:
+
+- analyzer
+- auto\_generate\_synonyms\_phrase
+- fuzziness
+- max\_expansions
+- prefix\_length
+- fuzzy\_transpositions
+- fuzzy\_rewrite
+- lenient
+- operator
+- minimum\_should\_match
+- zero\_terms\_query
+- boost
+
+Example with only \`field\` and \`query\` expressions, and all other
+parameters are set default values:
+
+ os> source=accounts | where match(address, 'Street') | fields lastname, address;
+ fetched rows / total rows = 2/2
+ +------------+--------------------+
+ | lastname | address |
+ |------------+--------------------|
+ | Bond | 671 Bristol Street |
+ | Bates | 789 Madison Street |
+ +------------+--------------------+
+
+Another example to show how to set custom values for the optional
+parameters:
+
+ os> source=accounts | where match(firstname, 'Hattie', operator='AND', boost=2.0) | fields lastname;
+ fetched rows / total rows = 1/1
+ +------------+
+ | lastname |
+ |------------|
+ | Bond |
+ +------------+
+
+### Limitations
+
+The full text search functions are available to execute only in OpenSearch DSL
+but not in memory as of now, so the full text search might fail for
+queries that are too complex to translate into DSL if the full text search
+function is following after a complex PPL query. To make your queries
+always work-able, it is recommended to place the full text search commands as
+close to the search command as possible, to ensure the full text search
+functions are eligible to push down. For example, a complex query like
+\`search source = people | rename firstname as name | dedup account_number | fields name, account_number, balance, employer | where match(employer, 'Open Search') | stats count() by city\`
+could fail because it is difficult to translate to DSL, but it would be
+better if we rewrite it to an equivalent query as
+\`search source = people | where match(employer, 'Open Search') | rename firstname as name | dedup account_number | fields name, account_number, balance, employer | stats count() by city\`
+by moving the where command with full text search function to the second
+command right after the search command, and the full text search would be
+optimized and executed smoothly in OpenSearch DSL. See [Optimization](https://github.com/opensearch-project/sql/blob/22924b13d9cb46759c8d213a7ce903effe06ab47/docs/user/optimization/optimization.rst)
+to get more details about the query engine optimization.
+`;
diff --git a/public/components/common/helpers/ppl_docs/functions/index.ts b/public/components/common/helpers/ppl_docs/functions/index.ts
new file mode 100644
index 0000000000..e061c6188e
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/functions/index.ts
@@ -0,0 +1,10 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { datetimeFunction } from './datetime';
+export { conditionFunction } from './condition';
+export { mathFunction } from './math';
+export { stringFunction } from './string';
+export { fullTextSearchFunction } from './full_text_search';
diff --git a/public/components/common/helpers/ppl_docs/functions/math.ts b/public/components/common/helpers/ppl_docs/functions/math.ts
new file mode 100644
index 0000000000..33d63f17c5
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/functions/math.ts
@@ -0,0 +1,600 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const mathFunction = `## Math
+---
+
+### ABS
+
+**Description**
+
+Usage: abs(x) calculate the abs x.
+
+Argument type: INTEGER/LONG/FLOAT/DOUBLE
+
+Return type: INTEGER/LONG/FLOAT/DOUBLE
+
+Example:
+
+ os> source=people | eval \`ABS(-1)\` = ABS(-1) | fields \`ABS(-1)\`
+ fetched rows / total rows = 1/1
+ +-----------+
+ | ABS(-1) |
+ |-----------|
+ | 1 |
+ +-----------+
+
+### ACOS
+
+**Description**
+
+Usage: acos(x) calculate the arc cosine of x. Returns NULL if x is not
+in the range -1 to 1.
+
+Argument type: INTEGER/LONG/FLOAT/DOUBLE
+
+Return type: DOUBLE
+
+Example:
+
+ os> source=people | eval \`ACOS(0)\` = ACOS(0) | fields \`ACOS(0)\`
+ fetched rows / total rows = 1/1
+ +--------------------+
+ | ACOS(0) |
+ |--------------------|
+ | 1.5707963267948966 |
+ +--------------------+
+
+### ASIN
+
+**Description**
+
+Usage: asin(x) calculate the arc sine of x. Returns NULL if x is not in
+the range -1 to 1.
+
+Argument type: INTEGER/LONG/FLOAT/DOUBLE
+
+Return type: DOUBLE
+
+Example:
+
+ os> source=people | eval \`ASIN(0)\` = ASIN(0) | fields \`ASIN(0)\`
+ fetched rows / total rows = 1/1
+ +-----------+
+ | ASIN(0) |
+ |-----------|
+ | 0.0 |
+ +-----------+
+
+### ATAN
+
+**Description**
+
+Usage: atan(x) calculates the arc tangent of x. atan(y, x) calculates
+the arc tangent of y / x, except that the signs of both arguments are
+used to determine the quadrant of the result.
+
+Argument type: INTEGER/LONG/FLOAT/DOUBLE
+
+Return type: DOUBLE
+
+Example:
+
+ os> source=people | eval \`ATAN(2)\` = ATAN(2), \`ATAN(2, 3)\` = ATAN(2, 3) | fields \`ATAN(2)\`, \`ATAN(2, 3)\`
+ fetched rows / total rows = 1/1
+ +--------------------+--------------------+
+ | ATAN(2) | ATAN(2, 3) |
+ |--------------------+--------------------|
+ | 1.1071487177940904 | 0.5880026035475675 |
+ +--------------------+--------------------+
+
+### ATAN2
+
+**Description**
+
+Usage: atan2(y, x) calculates the arc tangent of y / x, except that the
+signs of both arguments are used to determine the quadrant of the
+result.
+
+Argument type: INTEGER/LONG/FLOAT/DOUBLE
+
+Return type: DOUBLE
+
+Example:
+
+ os> source=people | eval \`ATAN2(2, 3)\` = ATAN2(2, 3) | fields \`ATAN2(2, 3)\`
+ fetched rows / total rows = 1/1
+ +--------------------+
+ | ATAN2(2, 3) |
+ |--------------------|
+ | 0.5880026035475675 |
+ +--------------------+
+
+### CEIL
+
+**Description**
+
+Usage: ceil(x) return the smallest integer value this is greater or
+equal to x.
+
+Argument type: INTEGER/LONG/FLOAT/DOUBLE
+
+Return type: INTEGER
+
+Example:
+
+ os> source=people | eval \`CEIL(2.75)\` = CEIL(2.75) | fields \`CEIL(2.75)\`
+ fetched rows / total rows = 1/1
+ +--------------+
+ | CEIL(2.75) |
+ |--------------|
+ | 3 |
+ +--------------+
+
+### CONV
+
+**Description**
+
+Usage: CONV(x, a, b) converts the number x from a base to b base.
+
+Argument type: x: STRING, a: INTEGER, b: INTEGER
+
+Return type: STRING
+
+Example:
+
+ os> source=people | eval \`CONV('12', 10, 16)\` = CONV('12', 10, 16), \`CONV('2C', 16, 10)\` = CONV('2C', 16, 10), \`CONV(12, 10, 2)\` = CONV(12, 10, 2), \`CONV(1111, 2, 10)\` = CONV(1111, 2, 10) | fields \`CONV('12', 10, 16)\`, \`CONV('2C', 16, 10)\`, \`CONV(12, 10, 2)\`, \`CONV(1111, 2, 10)\`
+ fetched rows / total rows = 1/1
+ +----------------------+----------------------+-------------------+---------------------+
+ | CONV('12', 10, 16) | CONV('2C', 16, 10) | CONV(12, 10, 2) | CONV(1111, 2, 10) |
+ |----------------------+----------------------+-------------------+---------------------|
+ | c | 44 | 1100 | 15 |
+ +----------------------+----------------------+-------------------+---------------------+
+
+### COS
+
+**Description**
+
+Usage: cos(x) calculate the cosine of x, where x is given in radians.
+
+Argument type: INTEGER/LONG/FLOAT/DOUBLE
+
+Return type: DOUBLE
+
+Example:
+
+ os> source=people | eval \`COS(0)\` = COS(0) | fields \`COS(0)\`
+ fetched rows / total rows = 1/1
+ +----------+
+ | COS(0) |
+ |----------|
+ | 1.0 |
+ +----------+
+
+### COT
+
+**Description**
+
+Usage: cot(x) calculate the cotangent of x. Returns out-of-range error
+if x equals to 0.
+
+Argument type: INTEGER/LONG/FLOAT/DOUBLE
+
+Return type: DOUBLE
+
+Example:
+
+ os> source=people | eval \`COT(1)\` = COT(1) | fields \`COT(1)\`
+ fetched rows / total rows = 1/1
+ +--------------------+
+ | COT(1) |
+ |--------------------|
+ | 0.6420926159343306 |
+ +--------------------+
+
+### CRC32
+
+**Description**
+
+Usage: Calculates a cyclic redundancy check value and returns a 32-bit
+unsigned value.
+
+Argument type: STRING
+
+Return type: LONG
+
+Example:
+
+ os> source=people | eval \`CRC32('MySQL')\` = CRC32('MySQL') | fields \`CRC32('MySQL')\`
+ fetched rows / total rows = 1/1
+ +------------------+
+ | CRC32('MySQL') |
+ |------------------|
+ | 3259397556 |
+ +------------------+
+
+### DEGREES
+
+**Description**
+
+Usage: degrees(x) converts x from radians to degrees.
+
+Argument type: INTEGER/LONG/FLOAT/DOUBLE
+
+Return type: DOUBLE
+
+Example:
+
+ os> source=people | eval \`DEGREES(1.57)\` = DEGREES(1.57) | fields \`DEGREES(1.57)\`
+ fetched rows / total rows = 1/1
+ +-------------------+
+ | DEGREES(1.57) |
+ |-------------------|
+ | 89.95437383553924 |
+ +-------------------+
+
+### E
+
+**Description**
+
+Usage: E() returns the Euler's number
+
+Return type: DOUBLE
+
+Example:
+
+ os> source=people | eval \`E()\` = E() | fields \`E()\`
+ fetched rows / total rows = 1/1
+ +-------------------+
+ | E() |
+ |-------------------|
+ | 2.718281828459045 |
+ +-------------------+
+
+### EXP
+
+**Description**
+
+Usage: exp(x) return e raised to the power of x.
+
+Argument type: INTEGER/LONG/FLOAT/DOUBLE
+
+Return type: INTEGER
+
+Example:
+
+ os> source=people | eval \`EXP(2)\` = EXP(2) | fields \`EXP(2)\`
+ fetched rows / total rows = 1/1
+ +------------------+
+ | EXP(2) |
+ |------------------|
+ | 7.38905609893065 |
+ +------------------+
+
+### FLOOR
+
+**Description**
+
+Usage: floor(x) return the largest integer value this is smaller or
+equal to x.
+
+Argument type: INTEGER/LONG/FLOAT/DOUBLE
+
+Return type: INTEGER
+
+Example:
+
+ os> source=people | eval \`FLOOR(2.75)\` = FLOOR(2.75) | fields \`FLOOR(2.75)\`
+ fetched rows / total rows = 1/1
+ +---------------+
+ | FLOOR(2.75) |
+ |---------------|
+ | 2 |
+ +---------------+
+
+### LN
+
+**Description**
+
+Usage: ln(x) return the the natural logarithm of x.
+
+Argument type: INTEGER/LONG/FLOAT/DOUBLE
+
+Return type: DOUBLE
+
+Example:
+
+ os> source=people | eval \`LN(2)\` = LN(2) | fields \`LN(2)\`
+ fetched rows / total rows = 1/1
+ +--------------------+
+ | LN(2) |
+ |--------------------|
+ | 0.6931471805599453 |
+ +--------------------+
+
+### LOG
+
+**Description**
+
+Specifications:
+
+Usage: log(x) returns the natural logarithm of x that is the base e
+logarithm of the x. log(B, x) is equivalent to log(x)/log(B).
+
+Argument type: INTEGER/LONG/FLOAT/DOUBLE
+
+Return type: DOUBLE
+
+Example:
+
+ os> source=people | eval \`LOG(2)\` = LOG(2), \`LOG(2, 8)\` = LOG(2, 8) | fields \`LOG(2)\`, \`LOG(2, 8)\`
+ fetched rows / total rows = 1/1
+ +--------------------+-------------+
+ | LOG(2) | LOG(2, 8) |
+ |--------------------+-------------|
+ | 0.6931471805599453 | 3.0 |
+ +--------------------+-------------+
+
+### LOG2
+
+**Description**
+
+Specifications:
+
+Usage: log2(x) is equivalent to log(x)/log(2).
+
+Argument type: INTEGER/LONG/FLOAT/DOUBLE
+
+Return type: DOUBLE
+
+Example:
+
+ os> source=people | eval \`LOG2(8)\` = LOG2(8) | fields \`LOG2(8)\`
+ fetched rows / total rows = 1/1
+ +-----------+
+ | LOG2(8) |
+ |-----------|
+ | 3.0 |
+ +-----------+
+
+### LOG10
+
+**Description**
+
+Specifications:
+
+Usage: log10(x) is equivalent to log(x)/log(10).
+
+Argument type: INTEGER/LONG/FLOAT/DOUBLE
+
+Return type: DOUBLE
+
+Example:
+
+ os> source=people | eval \`LOG10(100)\` = LOG10(100) | fields \`LOG10(100)\`
+ fetched rows / total rows = 1/1
+ +--------------+
+ | LOG10(100) |
+ |--------------|
+ | 2.0 |
+ +--------------+
+
+### MOD
+
+**Description**
+
+Usage: MOD(n, m) calculates the remainder of the number n divided by m.
+
+Argument type: INTEGER/LONG/FLOAT/DOUBLE
+
+Return type: Wider type between types of n and m if m is nonzero value.
+If m equals to 0, then returns NULL.
+
+Example:
+
+ os> source=people | eval \`MOD(3, 2)\` = MOD(3, 2), \`MOD(3.1, 2)\` = MOD(3.1, 2) | fields \`MOD(3, 2)\`, \`MOD(3.1, 2)\`
+ fetched rows / total rows = 1/1
+ +-------------+---------------+
+ | MOD(3, 2) | MOD(3.1, 2) |
+ |-------------+---------------|
+ | 1 | 1.1 |
+ +-------------+---------------+
+
+### PI
+
+**Description**
+
+Usage: PI() returns the constant pi
+
+Return type: DOUBLE
+
+Example:
+
+ os> source=people | eval \`PI()\` = PI() | fields \`PI()\`
+ fetched rows / total rows = 1/1
+ +-------------------+
+ | PI() |
+ |-------------------|
+ | 3.141592653589793 |
+ +-------------------+
+
+### POW
+
+**Description**
+
+Usage: POW(x, y) calculates the value of x raised to the power of y. Bad
+inputs return NULL result.
+
+Argument type: INTEGER/LONG/FLOAT/DOUBLE
+
+Return type: DOUBLE
+
+Synonyms: [POWER](#power)
+
+Example:
+
+ os> source=people | eval \`POW(3, 2)\` = POW(3, 2), \`POW(-3, 2)\` = POW(-3, 2), \`POW(3, -2)\` = POW(3, -2) | fields \`POW(3, 2)\`, \`POW(-3, 2)\`, \`POW(3, -2)\`
+ fetched rows / total rows = 1/1
+ +-------------+--------------+--------------------+
+ | POW(3, 2) | POW(-3, 2) | POW(3, -2) |
+ |-------------+--------------+--------------------|
+ | 9.0 | 9.0 | 0.1111111111111111 |
+ +-------------+--------------+--------------------+
+
+### POWER
+
+**Description**
+
+Usage: POWER(x, y) calculates the value of x raised to the power of y.
+Bad inputs return NULL result.
+
+Argument type: INTEGER/LONG/FLOAT/DOUBLE
+
+Return type: DOUBLE
+
+Synonyms: [POW](#pow)
+
+Example:
+
+ os> source=people | eval \`POWER(3, 2)\` = POWER(3, 2), \`POWER(-3, 2)\` = POWER(-3, 2), \`POWER(3, -2)\` = POWER(3, -2) | fields \`POWER(3, 2)\`, \`POWER(-3, 2)\`, \`POWER(3, -2)\`
+ fetched rows / total rows = 1/1
+ +---------------+----------------+--------------------+
+ | POWER(3, 2) | POWER(-3, 2) | POWER(3, -2) |
+ |---------------+----------------+--------------------|
+ | 9.0 | 9.0 | 0.1111111111111111 |
+ +---------------+----------------+--------------------+
+
+### RADIANS
+
+**Description**
+
+Usage: radians(x) converts x from degrees to radians.
+
+Argument type: INTEGER/LONG/FLOAT/DOUBLE
+
+Return type: DOUBLE
+
+Example:
+
+ os> source=people | eval \`RADIANS(90)\` = RADIANS(90) | fields \`RADIANS(90)\`
+ fetched rows / total rows = 1/1
+ +--------------------+
+ | RADIANS(90) |
+ |--------------------|
+ | 1.5707963267948966 |
+ +--------------------+
+
+### RAND
+
+**Description**
+
+Usage: RAND()/RAND(N) returns a random floating-point value in the range
+0 <= value < 1.0. If integer N is specified, the seed is
+initialized prior to execution. One implication of this behavior is with
+identical argument N, rand(N) returns the same value each time, and thus
+produces a repeatable sequence of column values.
+
+Argument type: INTEGER
+
+Return type: FLOAT
+
+Example:
+
+ os> source=people | eval \`RAND(3)\` = RAND(3) | fields \`RAND(3)\`
+ fetched rows / total rows = 1/1
+ +------------+
+ | RAND(3) |
+ |------------|
+ | 0.73105735 |
+ +------------+
+
+### ROUND
+
+**Description**
+
+Usage: ROUND(x, d) rounds the argument x to d decimal places, d defaults
+to 0 if not specified
+
+Argument type: INTEGER/LONG/FLOAT/DOUBLE
+
+Return type map:
+
+(INTEGER/LONG \[,INTEGER\]) -> LONG (FLOAT/DOUBLE \[,INTEGER\]) ->
+LONG
+
+Example:
+
+ os> source=people | eval \`ROUND(12.34)\` = ROUND(12.34), \`ROUND(12.34, 1)\` = ROUND(12.34, 1), \`ROUND(12.34, -1)\` = ROUND(12.34, -1), \`ROUND(12, 1)\` = ROUND(12, 1) | fields \`ROUND(12.34)\`, \`ROUND(12.34, 1)\`, \`ROUND(12.34, -1)\`, \`ROUND(12, 1)\`
+ fetched rows / total rows = 1/1
+ +----------------+-------------------+--------------------+----------------+
+ | ROUND(12.34) | ROUND(12.34, 1) | ROUND(12.34, -1) | ROUND(12, 1) |
+ |----------------+-------------------+--------------------+----------------|
+ | 12.0 | 12.3 | 10.0 | 12 |
+ +----------------+-------------------+--------------------+----------------+
+
+### SIGN
+
+**Description**
+
+Usage: Returns the sign of the argument as -1, 0, or 1, depending on
+whether the number is negative, zero, or positive
+
+Argument type: INTEGER/LONG/FLOAT/DOUBLE
+
+Return type: INTEGER
+
+Example:
+
+ os> source=people | eval \`SIGN(1)\` = SIGN(1), \`SIGN(0)\` = SIGN(0), \`SIGN(-1.1)\` = SIGN(-1.1) | fields \`SIGN(1)\`, \`SIGN(0)\`, \`SIGN(-1.1)\`
+ fetched rows / total rows = 1/1
+ +-----------+-----------+--------------+
+ | SIGN(1) | SIGN(0) | SIGN(-1.1) |
+ |-----------+-----------+--------------|
+ | 1 | 0 | -1 |
+ +-----------+-----------+--------------+
+
+### SIN
+
+**Description**
+
+Usage: sin(x) calculate the sine of x, where x is given in radians.
+
+Argument type: INTEGER/LONG/FLOAT/DOUBLE
+
+Return type: DOUBLE
+
+Example:
+
+ os> source=people | eval \`SIN(0)\` = SIN(0) | fields \`SIN(0)\`
+ fetched rows / total rows = 1/1
+ +----------+
+ | SIN(0) |
+ |----------|
+ | 0.0 |
+ +----------+
+
+### SQRT
+
+**Description**
+
+Usage: Calculates the square root of a non-negative number
+
+Argument type: INTEGER/LONG/FLOAT/DOUBLE
+
+Return type map:
+
+(Non-negative) INTEGER/LONG/FLOAT/DOUBLE -> DOUBLE (Negative)
+INTEGER/LONG/FLOAT/DOUBLE -> NULL
+
+Example:
+
+ os> source=people | eval \`SQRT(4)\` = SQRT(4), \`SQRT(4.41)\` = SQRT(4.41) | fields \`SQRT(4)\`, \`SQRT(4.41)\`
+ fetched rows / total rows = 1/1
+ +-----------+--------------+
+ | SQRT(4) | SQRT(4.41) |
+ |-----------+--------------|
+ | 2.0 | 2.1 |
+ +-----------+--------------+
+`;
diff --git a/public/components/common/helpers/ppl_docs/functions/string.ts b/public/components/common/helpers/ppl_docs/functions/string.ts
new file mode 100644
index 0000000000..824727ae80
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/functions/string.ts
@@ -0,0 +1,240 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const stringFunction = `## String
+---
+
+### CONCAT
+
+**Description**
+
+Usage: CONCAT(str1, str2) returns str1 and str strings concatenated
+together.
+
+Argument type: STRING, STRING
+
+Return type: STRING
+
+Example:
+
+ os> source=people | eval \`CONCAT('hello', 'world')\` = CONCAT('hello', 'world') | fields \`CONCAT('hello', 'world')\`
+ fetched rows / total rows = 1/1
+ +----------------------------+
+ | CONCAT('hello', 'world') |
+ |----------------------------|
+ | helloworld |
+ +----------------------------+
+
+### CONCAT\_WS
+
+**Description**
+
+Usage: CONCAT\_WS(sep, str1, str2) returns str1 concatenated with str2
+using sep as a separator between them.
+
+Argument type: STRING, STRING, STRING
+
+Return type: STRING
+
+Example:
+
+ os> source=people | eval \`CONCAT_WS(',', 'hello', 'world')\` = CONCAT_WS(',', 'hello', 'world') | fields \`CONCAT_WS(',', 'hello', 'world')\`
+ fetched rows / total rows = 1/1
+ +------------------------------------+
+ | CONCAT_WS(',', 'hello', 'world') |
+ |------------------------------------|
+ | hello,world |
+ +------------------------------------+
+
+### LENGTH
+
+**Description**
+
+Specifications:
+
+1. LENGTH(STRING) -> INTEGER
+
+Usage: length(str) returns length of string measured in bytes.
+
+Argument type: STRING
+
+Return type: INTEGER
+
+Example:
+
+ os> source=people | eval \`LENGTH('helloworld')\` = LENGTH('helloworld') | fields \`LENGTH('helloworld')\`
+ fetched rows / total rows = 1/1
+ +------------------------+
+ | LENGTH('helloworld') |
+ |------------------------|
+ | 10 |
+ +------------------------+
+
+### LIKE
+
+**Description**
+
+Usage: like(string, PATTERN) return true if the string match the
+PATTERN.
+
+There are two wildcards often used in conjunction with the LIKE
+operator:
+
+- \`%\` - The percent sign represents zero, one, or multiple characters
+- \`_\` - The underscore represents a single character
+
+Example:
+
+ os> source=people | eval \`LIKE('hello world', '_ello%')\` = LIKE('hello world', '_ello%') | fields \`LIKE('hello world', '_ello%')\`
+ fetched rows / total rows = 1/1
+ +---------------------------------+
+ | LIKE('hello world', '_ello%') |
+ |---------------------------------|
+ | True |
+ +---------------------------------+
+
+### LOWER
+
+**Description**
+
+Usage: lower(string) converts the string to lowercase.
+
+Argument type: STRING
+
+Return type: STRING
+
+Example:
+
+ os> source=people | eval \`LOWER('helloworld')\` = LOWER('helloworld'), \`LOWER('HELLOWORLD')\` = LOWER('HELLOWORLD') | fields \`LOWER('helloworld')\`, \`LOWER('HELLOWORLD')\`
+ fetched rows / total rows = 1/1
+ +-----------------------+-----------------------+
+ | LOWER('helloworld') | LOWER('HELLOWORLD') |
+ |-----------------------+-----------------------|
+ | helloworld | helloworld |
+ +-----------------------+-----------------------+
+
+### LTRIM
+
+**Description**
+
+Usage: ltrim(str) trims leading space characters from the string.
+
+Argument type: STRING
+
+Return type: STRING
+
+Example:
+
+ os> source=people | eval \`LTRIM(' hello')\` = LTRIM(' hello'), \`LTRIM('hello ')\` = LTRIM('hello ') | fields \`LTRIM(' hello')\`, \`LTRIM('hello ')\`
+ fetched rows / total rows = 1/1
+ +---------------------+---------------------+
+ | LTRIM(' hello') | LTRIM('hello ') |
+ |---------------------+---------------------|
+ | hello | hello |
+ +---------------------+---------------------+
+
+### RIGHT
+
+**Description**
+
+Usage: right(str, len) returns the rightmost len characters from the
+string str, or NULL if any argument is NULL.
+
+Argument type: STRING, INTEGER
+
+Return type: STRING
+
+Example:
+
+ os> source=people | eval \`RIGHT('helloworld', 5)\` = RIGHT('helloworld', 5), \`RIGHT('HELLOWORLD', 0)\` = RIGHT('HELLOWORLD', 0) | fields \`RIGHT('helloworld', 5)\`, \`RIGHT('HELLOWORLD', 0)\`
+ fetched rows / total rows = 1/1
+ +--------------------------+--------------------------+
+ | RIGHT('helloworld', 5) | RIGHT('HELLOWORLD', 0) |
+ |--------------------------+--------------------------|
+ | world | |
+ +--------------------------+--------------------------+
+
+### RTRIM
+
+**Description**
+
+Usage: rtrim(str) trims trailing space characters from the string.
+
+Argument type: STRING
+
+Return type: STRING
+
+Example:
+
+ os> source=people | eval \`RTRIM(' hello')\` = RTRIM(' hello'), \`RTRIM('hello ')\` = RTRIM('hello ') | fields \`RTRIM(' hello')\`, \`RTRIM('hello ')\`
+ fetched rows / total rows = 1/1
+ +---------------------+---------------------+
+ | RTRIM(' hello') | RTRIM('hello ') |
+ |---------------------+---------------------|
+ | hello | hello |
+ +---------------------+---------------------+
+
+### SUBSTRING
+
+**Description**
+
+Usage: substring(str, start) or substring(str, start, length) returns
+substring using start and length. With no length, entire string from
+start is returned.
+
+Argument type: STRING, INTEGER, INTEGER
+
+Return type: STRING
+
+Synonyms: SUBSTR
+
+Example:
+
+ os> source=people | eval \`SUBSTRING('helloworld', 5)\` = SUBSTRING('helloworld', 5), \`SUBSTRING('helloworld', 5, 3)\` = SUBSTRING('helloworld', 5, 3) | fields \`SUBSTRING('helloworld', 5)\`, \`SUBSTRING('helloworld', 5, 3)\`
+ fetched rows / total rows = 1/1
+ +------------------------------+---------------------------------+
+ | SUBSTRING('helloworld', 5) | SUBSTRING('helloworld', 5, 3) |
+ |------------------------------+---------------------------------|
+ | oworld | owo |
+ +------------------------------+---------------------------------+
+
+### TRIM
+
+**Description**
+
+Argument Type: STRING
+
+Return type: STRING
+
+Example:
+
+ os> source=people | eval \`TRIM(' hello')\` = TRIM(' hello'), \`TRIM('hello ')\` = TRIM('hello ') | fields \`TRIM(' hello')\`, \`TRIM('hello ')\`
+ fetched rows / total rows = 1/1
+ +--------------------+--------------------+
+ | TRIM(' hello') | TRIM('hello ') |
+ |--------------------+--------------------|
+ | hello | hello |
+ +--------------------+--------------------+
+
+### UPPER
+
+**Description**
+
+Usage: upper(string) converts the string to uppercase.
+
+Argument type: STRING
+
+Return type: STRING
+
+Example:
+
+ os> source=people | eval \`UPPER('helloworld')\` = UPPER('helloworld'), \`UPPER('HELLOWORLD')\` = UPPER('HELLOWORLD') | fields \`UPPER('helloworld')\`, \`UPPER('HELLOWORLD')\`
+ fetched rows / total rows = 1/1
+ +-----------------------+-----------------------+
+ | UPPER('helloworld') | UPPER('HELLOWORLD') |
+ |-----------------------+-----------------------|
+ | HELLOWORLD | HELLOWORLD |
+ +-----------------------+-----------------------+
+`;
diff --git a/public/components/common/helpers/ppl_docs/groups.tsx b/public/components/common/helpers/ppl_docs/groups.tsx
new file mode 100644
index 0000000000..633def3014
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/groups.tsx
@@ -0,0 +1,126 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ dedupCmd,
+ evalCmd,
+ fieldsCmd,
+ headCmd,
+ parseCmd,
+ rareCmd,
+ renameCmd,
+ searchCmd,
+ sortCmd,
+ statsCmd,
+ syntaxCmd,
+ topCmd,
+ whereCmd,
+} from './commands';
+import {
+ mathFunction,
+ datetimeFunction,
+ stringFunction,
+ conditionFunction,
+ fullTextSearchFunction,
+} from './functions';
+import { pplDatatypes, pplIdentifiers } from './language_structure';
+
+export const Group1 = {
+ label: 'Commands',
+ options: [
+ {
+ label: 'Syntax',
+ value: syntaxCmd,
+ },
+ {
+ label: 'dedup',
+ value: dedupCmd,
+ },
+ {
+ label: 'eval',
+ value: evalCmd,
+ },
+ {
+ label: 'fields',
+ value: fieldsCmd,
+ },
+ {
+ label: 'rename',
+ value: renameCmd,
+ },
+ {
+ label: 'search',
+ value: searchCmd,
+ },
+ {
+ label: 'sort',
+ value: sortCmd,
+ },
+ {
+ label: 'stats',
+ value: statsCmd,
+ },
+ {
+ label: 'where',
+ value: whereCmd,
+ },
+ {
+ label: 'head',
+ value: headCmd,
+ },
+ {
+ label: 'parse',
+ value: parseCmd,
+ },
+ {
+ label: 'rare',
+ value: rareCmd,
+ },
+ {
+ label: 'top',
+ value: topCmd,
+ },
+ ],
+};
+
+export const Group2 = {
+ label: 'Functions',
+ options: [
+ {
+ label: 'Math',
+ value: mathFunction,
+ },
+ {
+ label: 'Date and Time',
+ value: datetimeFunction,
+ },
+ {
+ label: 'String',
+ value: stringFunction,
+ },
+ {
+ label: 'Condition',
+ value: conditionFunction,
+ },
+ {
+ label: 'Full Text Search',
+ value: fullTextSearchFunction,
+ },
+ ],
+};
+
+export const Group3 = {
+ label: 'Language Structure',
+ options: [
+ {
+ label: 'Identifiers',
+ value: pplIdentifiers,
+ },
+ {
+ label: 'Data Types',
+ value: pplDatatypes,
+ },
+ ],
+};
diff --git a/public/components/common/helpers/ppl_docs/language_structure/datatypes.ts b/public/components/common/helpers/ppl_docs/language_structure/datatypes.ts
new file mode 100644
index 0000000000..b01149143b
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/language_structure/datatypes.ts
@@ -0,0 +1,412 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const pplDatatypes = `## Data Types
+---
+### **Overview**
+
+### PPL Data Types
+
+The PPL support the following data types.
+
+| PPL Data Type |
+|---------------|
+| boolean |
+| byte |
+| short |
+| integer |
+| long |
+| float |
+| double |
+| string |
+| text |
+| timestamp |
+| datetime |
+| date |
+| time |
+| interval |
+| ip |
+| geo\_point |
+| binary |
+| struct |
+| array |
+
+### Data Types Mapping
+
+The table below list the mapping between OpenSearch Data Type, PPL Data
+Type and SQL Type.
+
+| OpenSearch Type | PPL Type | SQL Type |
+|-----------------|-----------|-----------|
+| boolean | boolean | BOOLEAN |
+| byte | byte | TINYINT |
+| short | byte | SMALLINT |
+| integer | integer | INTEGER |
+| long | long | BIGINT |
+| float | float | REAL |
+| half\_float | float | FLOAT |
+| scaled\_float | float | DOUBLE |
+| double | double | DOUBLE |
+| keyword | string | VARCHAR |
+| text | text | VARCHAR |
+| date | timestamp | TIMESTAMP |
+| ip | ip | VARCHAR |
+| date | timestamp | TIMESTAMP |
+| binary | binary | VARBINARY |
+| object | struct | STRUCT |
+| nested | array | STRUCT |
+
+Notes: Not all the PPL Type has correspond OpenSearch Type. e.g. data
+and time. To use function which required such data type, user should
+explict convert the data type.
+
+### **Numeric Data Types**
+
+Numeric values ranged from -2147483648 to +2147483647 are recognized as
+integer with type name \`INTEGER\`. For others outside the range, \`LONG\`
+integer will be the data type after parsed.
+
+### **Date and Time Data Types**
+
+The date and time data types are the types that represent temporal
+values and PPL plugin supports types including DATE, TIME, DATETIME,
+TIMESTAMP and INTERVAL. By default, the OpenSearch DSL uses date type as
+the only date and time related type, which has contained all information
+about an absolute time point. To integrate with PPL language, each of
+the types other than timestamp is holding part of temporal or timezone
+information, and the usage to explicitly clarify the date and time types
+is reflected in the datetime functions (see [Functions](functions.rst)
+for details), where some functions might have restrictions in the input
+argument type.
+
+#### **Date**
+
+Date represents the calendar date regardless of the time zone. A given
+date value represents a 24-hour period, or say a day, but this period
+varies in different timezones and might have flexible hours during
+Daylight Savings Time programs. Besides, the date type does not contain
+time information as well. The supported range is '1000-01-01' to
+'9999-12-31'.
+
+| Type | Syntax | Range |
+|------|--------------|------------------------------|
+| Date | 'yyyy-MM-dd' | '0001-01-01' to '9999-12-31' |
+
+#### **Time**
+
+Time represents the time on the clock or watch with no regard for which
+timezone it might be related with. Time type data does not have date
+information.
+
+| Type | Syntax | Range |
+|------|-------------------------|----------------------------------------|
+| Time | 'hh:mm:ss\[.fraction\]' | '00:00:00.000000' to '23:59:59.999999' |
+
+#### **Datetime**
+
+Datetime type is the combination of date and time. The conversion rule
+of date or time to datetime is described in [Conversion between date and
+time types](#conversion-between-date-and-time-types). Datetime type does
+not contain timezone information. For an absolute time point that
+contains both date time and timezone information, see
+[Timestamp](#timestamp).
+
+| Type | Syntax | Range |
+|----------|------------------------------------|--------------------------------------------------------------|
+| Datetime | 'yyyy-MM-dd hh:mm:ss\[.fraction\]' | '0001-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999' |
+
+#### **Timestamp**
+
+A timestamp instance is an absolute instant independent of timezone or
+convention. For example, for a given point of time, if we set the
+timestamp of this time point into another timezone, the value should
+also be different accordingly. Besides, the storage of timestamp type is
+also different from the other types. The timestamp is converted from the
+current timezone to UTC for storage, and is converted back to the set
+timezone from UTC when retrieving.
+
+| Type | Syntax | Range |
+|-----------|------------------------------------|------------------------------------------------------------------|
+| Timestamp | 'yyyy-MM-dd hh:mm:ss\[.fraction\]' | '0001-01-01 00:00:01.000000' UTC to '9999-12-31 23:59:59.999999' |
+
+#### **Interval**
+
+Interval data type represents a temporal duration or a period. The
+syntax is as follows:
+
+| Type | Syntax |
+|----------|--------------------|
+| Interval | INTERVAL expr unit |
+
+The expr is any expression that can be iterated to a quantity value
+eventually, see [Expressions](expressions.rst) for details. The unit
+represents the unit for interpreting the quantity, including
+MICROSECOND, SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER and
+YEAR.The INTERVAL keyword and the unit specifier are not case sensitive.
+Note that there are two classes of intervals. Year-week intervals can
+store years, quarters, months and weeks. Day-time intervals can store
+days, hours, minutes, seconds and microseconds. Year-week intervals are
+comparable only with another year-week intervals. These two types of
+intervals can only comparable with the same type of themselves.
+
+### **Conversion between date and time types**
+
+Basically the date and time types except interval can be converted to
+each other, but might suffer some alteration of the value or some
+information loss, for example extracting the time value from a datetime
+value, or convert a date value to a datetime value and so forth. Here
+lists the summary of the conversion rules that PPL plugin supports for
+each of the types:
+
+#### **Conversion from DATE**
+
+- Since the date value does not have any time information, conversion
+ to [Time](#time) type is not useful, and will always return a zero
+ time value '00:00:00'.
+- Conversion from date to datetime has a data fill-up due to the lack
+ of time information, and it attaches the time '00:00:00' to the
+ original date by default and forms a datetime instance. For example,
+ the result to covert date '2020-08-17' to datetime type is datetime
+ '2020-08-17 00:00:00'.
+- Conversion to timestamp is to alternate both the time value and the
+ timezone information, and it attaches the zero time value '00:00:00'
+ and the session timezone (UTC by default) to the date. For example,
+ the result to covert date '2020-08-17' to datetime type with session
+ timezone UTC is datetime '2020-08-17 00:00:00' UTC.
+
+#### **Conversion from TIME**
+
+- Time value cannot be converted to any other date and time types
+ since it does not contain any date information, so it is not
+ meaningful to give no date info to a date/datetime/timestamp
+ instance.
+
+#### **Conversion from DATETIME**
+
+- Conversion from datetime to date is to extract the date part from
+ the datetime value. For example, the result to convert datetime
+ '2020-08-17 14:09:00' to date is date '2020-08-08'.
+- Conversion to time is to extract the time part from the datetime
+ value. For example, the result to convert datetime '2020-08-17
+ 14:09:00' to time is time '14:09:00'.
+- Since the datetime type does not contain timezone information, the
+ conversion to timestamp needs to fill up the timezone part with the
+ session timezone. For example, the result to convert datetime
+ '2020-08-17 14:09:00' with system timezone of UTC, to timestamp is
+ timestamp '2020-08-17 14:09:00' UTC.
+
+#### **Conversion from TIMESTAMP**
+
+- Conversion from timestamp is much more straightforward. To convert
+ it to date is to extract the date value, and conversion to time is
+ to extract the time value. Conversion to datetime, it will extracts
+ the datetime value and leave the timezone information over. For
+ example, the result to convert datetime '2020-08-17 14:09:00' UTC to
+ date is date '2020-08-17', to time is '14:09:00' and to datetime is
+ datetime '2020-08-17 14:09:00'.
+
+### **String Data Types**
+
+A string is a sequence of characters enclosed in either single or double
+quotes. For example, both 'text' and "text" will be treated as string
+literal.
+
+### **Query Struct Data Types**
+
+In PPL, the Struct Data Types corresponding to the [Object field type in
+OpenSearch](https://www.elastic.co/guide/en/elasticsearch/reference/current/object.html).
+The "." is used as the path selector when access the inner attribute of
+the struct data.
+
+#### **Example: People**
+
+There are three fields in test index \`people\`: 1) deep nested object
+field \`city\`; 2) object field of array value \`account\`; 3) nested field
+\`projects\`:
+
+ {
+ "mappings": {
+ "properties": {
+ "city": {
+ "properties": {
+ "name": {
+ "type": "keyword"
+ },
+ "location": {
+ "properties": {
+ "latitude": {
+ "type": "double"
+ }
+ }
+ }
+ }
+ },
+ "account": {
+ "properties": {
+ "id": {
+ "type": "keyword"
+ }
+ }
+ },
+ "projects": {
+ "type": "nested",
+ "properties": {
+ "name": {
+ "type": "keyword"
+ }
+ }
+ }
+ }
+ }
+ }
+
+#### **Example: Employees**
+
+Here is the mapping for test index \`employees_nested\`. Note that field
+\`projects\` is a nested field:
+
+ {
+ "mappings": {
+ "properties": {
+ "id": {
+ "type": "long"
+ },
+ "name": {
+ "type": "text",
+ "fields": {
+ "keyword": {
+ "type": "keyword",
+ "ignore_above": 256
+ }
+ }
+ },
+ "projects": {
+ "type": "nested",
+ "properties": {
+ "name": {
+ "type": "text",
+ "fields": {
+ "keyword": {
+ "type": "keyword"
+ }
+ },
+ "fielddata": true
+ },
+ "started_year": {
+ "type": "long"
+ }
+ }
+ },
+ "title": {
+ "type": "text",
+ "fields": {
+ "keyword": {
+ "type": "keyword",
+ "ignore_above": 256
+ }
+ }
+ }
+ }
+ }
+ }
+
+Result set:
+
+ {
+ "employees_nested" : [
+ {
+ "id" : 3,
+ "name" : "Bob Smith",
+ "title" : null,
+ "projects" : [
+ {
+ "name" : "AWS Redshift Spectrum querying",
+ "started_year" : 1990
+ },
+ {
+ "name" : "AWS Redshift security",
+ "started_year" : 1999
+ },
+ {
+ "name" : "AWS Aurora security",
+ "started_year" : 2015
+ }
+ ]
+ },
+ {
+ "id" : 4,
+ "name" : "Susan Smith",
+ "title" : "Dev Mgr",
+ "projects" : [ ]
+ },
+ {
+ "id" : 6,
+ "name" : "Jane Smith",
+ "title" : "Software Eng 2",
+ "projects" : [
+ {
+ "name" : "AWS Redshift security",
+ "started_year" : 1998
+ },
+ {
+ "name" : "AWS Hello security",
+ "started_year" : 2015,
+ "address" : [
+ {
+ "city" : "Dallas",
+ "state" : "TX"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+
+#### **Example 1: Select struct inner attribute**
+
+The example show fetch city (top level), city.name (second level),
+city.location.latitude (deeper level) struct type data from people
+results.
+
+PPL query:
+
+ os> source=people | fields city, city.name, city.location.latitude;
+ fetched rows / total rows = 1/1
+ +-----------------------------------------------------+-------------+--------------------------+
+ | city | city.name | city.location.latitude |
+ |-----------------------------------------------------+-------------+--------------------------|
+ | {'name': 'Seattle', 'location': {'latitude': 10.5}} | Seattle | 10.5 |
+ +-----------------------------------------------------+-------------+--------------------------+
+
+#### **Example 2: Group by struct inner attribute**
+
+The example show group by object field inner attribute.
+
+PPL query:
+
+ os> source=people | stats count() by city.name;
+ fetched rows / total rows = 1/1
+ +-----------+-------------+
+ | count() | city.name |
+ |-----------+-------------|
+ | 1 | Seattle |
+ +-----------+-------------+
+
+#### **Example 3: Selecting Field of Array Value**
+
+Select deeper level for object fields of array value which returns the
+first element in the array. For example, because inner field
+\`accounts.id\` has three values instead of a tuple in this document, the
+first entry is returned.:
+
+ os> source = people | fields accounts, accounts.id;
+ fetched rows / total rows = 1/1
+ +------------+---------------+
+ | accounts | accounts.id |
+ |------------+---------------|
+ | {'id': 1} | 1 |
+ +------------+---------------+
+`;
diff --git a/public/components/common/helpers/ppl_docs/language_structure/identifiers.ts b/public/components/common/helpers/ppl_docs/language_structure/identifiers.ts
new file mode 100644
index 0000000000..e520379135
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/language_structure/identifiers.ts
@@ -0,0 +1,107 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const pplIdentifiers = `## Indentifiers
+---
+
+### **Introduction**
+
+Identifiers are used for naming your database objects, such as index
+name, field name, alias etc. Basically there are two types of
+identifiers: regular identifiers and delimited identifiers.
+
+### **Regular Identifiers**
+
+**Description**
+
+A regular identifier is a string of characters that must start with
+ASCII letter (lower or upper case). The subsequent character can be a
+combination of letter, digit, underscore (\`_\`). It cannot be a reversed
+key word. And whitespace and other special characters are not allowed.
+
+For OpenSearch, the following identifiers are supported extensionally:
+
+1. Identifiers prefixed by dot \`.\`: this is called hidden index in
+ OpenSearch, for example \`.opensearch_dashboards\`.
+2. Identifiers prefixed by at sign \`@\`: this is common for meta fields
+ generated in Logstash ingestion.
+3. Identifiers with \`-\` in the middle: this is mostly the case for
+ index name with date information.
+4. Identifiers with star \`*\` present: this is mostly an index pattern
+ for wildcard match.
+
+Index name with date suffix separated by dash or dots, such as
+\`cwl-2020.01.11\` or \`logs-7.0-2020.01.11\`, is common for those created
+by Logstash or FileBeat ingestion. So, this kind of identifier used as
+index name is also supported without the need of being quoted for user
+convenience. In this case, wildcard within date pattern is also allowed
+to search for data across indices of different date range. For example,
+you can use \`logs-2020.1*\` to search in indices for October, November
+and December 2020.
+
+#### **Examples**
+
+Here are examples for using index pattern directly without quotes:
+
+ os> source=accounts | fields account_number, firstname, lastname;
+ fetched rows / total rows = 4/4
+ +------------------+-------------+------------+
+ | account_number | firstname | lastname |
+ |------------------+-------------+------------|
+ | 1 | Amber | Duke |
+ | 6 | Hattie | Bond |
+ | 13 | Nanette | Bates |
+ | 18 | Dale | Adams |
+ +------------------+-------------+------------+
+
+### **Delimited Identifiers**
+
+**Description**
+
+A delimited identifier is an identifier enclosed in back ticks \`\`. In
+this case, the identifier enclosed is not necessarily a regular
+identifier. In other words, it can contain any special character not
+allowed by regular identifier.
+
+#### **Use Cases**
+
+Here are typical examples of the use of delimited identifiers:
+
+1. Identifiers of reserved key word name
+2. Identifiers with dot \`.\` present: similarly as \`-\` in index name to
+ include date information, it is required to be quoted so parser can
+ differentiate it from identifier with qualifiers.
+3. Identifiers with other special character: OpenSearch has its own
+ rule which allows more special character, for example Unicode
+ character is supported in index name.
+
+#### **Examples**
+
+Here are examples for quoting an index name by back ticks:
+
+ os> source=\`accounts\` | fields \`account_number\`;
+ fetched rows / total rows = 4/4
+ +------------------+
+ | account_number |
+ |------------------|
+ | 1 |
+ | 6 |
+ | 13 |
+ | 18 |
+ +------------------+
+
+### **Case Sensitivity**
+
+**Description**
+
+Identifiers are treated in case sensitive manner. So it must be exactly
+same as what is stored in OpenSearch.
+
+### **Examples**
+
+For example, if you run \`source=Accounts\`, it will end up with an index
+not found exception from our plugin because the actual index name is
+under lower case.
+`
\ No newline at end of file
diff --git a/public/components/common/helpers/ppl_docs/language_structure/index.ts b/public/components/common/helpers/ppl_docs/language_structure/index.ts
new file mode 100644
index 0000000000..34ab26c26e
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/language_structure/index.ts
@@ -0,0 +1,7 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export {pplDatatypes} from './datatypes';
+export {pplIdentifiers} from './identifiers';
\ No newline at end of file
diff --git a/public/components/common/helpers/ppl_docs/overview.tsx b/public/components/common/helpers/ppl_docs/overview.tsx
new file mode 100644
index 0000000000..0bb3bd71ff
--- /dev/null
+++ b/public/components/common/helpers/ppl_docs/overview.tsx
@@ -0,0 +1,41 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const overview = `## Overview
+---
+Piped Processing Language (PPL), powered by OpenSearch, enables
+OpenSearch users with exploration and discovery of, and finding search
+patterns in data stored in OpenSearch, using a set of commands delimited
+by pipes (\|). These are essentially read-only requests to process data
+and return results.
+
+Currently, OpenSearch users can query data using either Query DSL or
+SQL. Query DSL is powerful and fast. However, it has a steep learning
+curve, and was not designed as a human interface to easily create ad hoc
+queries and explore user data. SQL allows users to extract and analyze
+data in OpenSearch in a declarative manner. OpenSearch now makes its
+search and query engine robust by introducing Piped Processing Language
+(PPL). It enables users to extract insights from OpenSearch with a
+sequence of commands delimited by pipes () syntax. It enables
+developers, DevOps engineers, support engineers, site reliability
+engineers (SREs), and IT managers to effectively discover and explore
+log, monitoring and observability data stored in OpenSearch.
+
+We expand the capabilities of our Workbench, a comprehensive and
+integrated visual query tool currently supporting only SQL, to run
+on-demand PPL commands, and view and save results as text and JSON. We
+also add a new interactive standalone command line tool, the PPL CLI, to
+run on-demand PPL commands, and view and save results as text and JSON.
+
+The query start with search command and then flowing a set of command
+delimited by pipe ( for example, the following query retrieve firstname
+and lastname from accounts if age large than 18.
+
+\`\`\`
+source=accounts
+| where age > 18
+| fields firstname, lastname
+\`\`\`
+`;
diff --git a/public/components/common/helpers/ppl_reference_flyout.tsx b/public/components/common/helpers/ppl_reference_flyout.tsx
new file mode 100644
index 0000000000..bf5e522612
--- /dev/null
+++ b/public/components/common/helpers/ppl_reference_flyout.tsx
@@ -0,0 +1,102 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ EuiButton,
+ EuiComboBox,
+ EuiComboBoxOptionOption,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiFlyoutBody,
+ EuiFlyoutFooter,
+ EuiFlyoutHeader,
+ EuiLink,
+ EuiMarkdownFormat,
+ EuiSpacer,
+ EuiText,
+ EuiTitle,
+} from '@elastic/eui';
+import { PPL_DOCUMENTATION_URL } from '../../../../common/constants/shared';
+import _ from 'lodash';
+import React, { useState } from 'react';
+import { FlyoutContainers } from '../flyout_containers';
+import { Group1, Group2, Group3 } from './ppl_docs/groups';
+import { overview } from './ppl_docs/overview';
+
+type Props = {
+ module: string;
+ closeFlyout: () => void;
+};
+
+export const PPLReferenceFlyout = ({ module, closeFlyout }: Props) => {
+ const allOptionsStatic = [{ label: 'Overview', value: overview }, Group1, Group2, Group3];
+ const defaultOption =
+ module === 'explorer' ? [allOptionsStatic[0]] : [_.find(Group1.options, ['label', 'where'])];
+ const [selectedOptions, setSelected] = useState(defaultOption);
+ const [flyoutContent, setFlyoutContent] = useState(
+ {defaultOption[0].value}
+ );
+
+ const onChange = (selectedOptions: any) => {
+ setSelected(selectedOptions);
+
+ const newContent = selectedOptions.map((option: EuiComboBoxOptionOption) => (
+ {option.value}
+ ));
+ setFlyoutContent(newContent);
+ };
+
+ const flyoutHeader = (
+
+
+ OpenSearch PPL Reference Manual
+
+
+ );
+
+ const flyoutBody = (
+
+
+
+
+
+
+
+
+ Learn More
+
+
+
+
+
+ {flyoutContent}
+
+ );
+
+ const flyoutFooter = (
+
+
+
+ Close
+
+
+
+ );
+
+ return (
+
+ );
+};
diff --git a/public/components/common/live_tail/__tests__/__snapshots__/live_tail_button.test.tsx.snap b/public/components/common/live_tail/__tests__/__snapshots__/live_tail_button.test.tsx.snap
new file mode 100644
index 0000000000..8eda93631a
--- /dev/null
+++ b/public/components/common/live_tail/__tests__/__snapshots__/live_tail_button.test.tsx.snap
@@ -0,0 +1,254 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Live tail button change live tail to 10s interval 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 10s
+
+
+
+
+
+
+
+`;
+
+exports[`Live tail button starts live tail with 5s interval 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+ 5s
+
+
+
+
+
+
+
+`;
+
+exports[`Live tail off button stop live tail 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Stop
+
+
+
+
+
+
+
+`;
diff --git a/public/components/common/live_tail/__tests__/live_tail_button.test.tsx b/public/components/common/live_tail/__tests__/live_tail_button.test.tsx
new file mode 100644
index 0000000000..4cb2a478fb
--- /dev/null
+++ b/public/components/common/live_tail/__tests__/live_tail_button.test.tsx
@@ -0,0 +1,75 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount, shallow } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { LiveTailButton, StopLiveButton } from '../live_tail_button';
+import { waitFor } from '@testing-library/dom';
+
+ describe('Live tail button', () => {
+ configure({ adapter: new Adapter() });
+
+ it('starts live tail with 5s interval', async () => {
+ const setIsLiveTailPopoverOpen = jest.fn();
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+
+ it('change live tail to 10s interval', async () => {
+ const setIsLiveTailPopoverOpen = jest.fn();
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+ });
+
+ describe('Live tail off button', () => {
+ configure({ adapter: new Adapter() });
+
+ it('stop live tail', async () => {
+ const StopLive = jest.fn();
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+ });
\ No newline at end of file
diff --git a/public/components/common/live_tail/live_tail_button.tsx b/public/components/common/live_tail/live_tail_button.tsx
new file mode 100644
index 0000000000..0e53152fa3
--- /dev/null
+++ b/public/components/common/live_tail/live_tail_button.tsx
@@ -0,0 +1,55 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+//Define pop over interval options for live tail button in your plugin
+
+import { EuiButton } from "@elastic/eui";
+import React, { useMemo } from "react";
+import { LiveTailProps } from "common/types/explorer";
+
+//Live Tail Button
+export const LiveTailButton = ({
+ isLiveTailOn,
+ isLiveTailPopoverOpen,
+ setIsLiveTailPopoverOpen,
+ liveTailName,
+ dataTestSubj,
+}: LiveTailProps) => {
+ const liveButton = useMemo(() => {
+ return (
+ setIsLiveTailPopoverOpen(!isLiveTailPopoverOpen)}
+ data-test-subj={dataTestSubj}
+ >
+ {liveTailName}
+
+ );
+ }, [isLiveTailPopoverOpen, isLiveTailOn]);
+ return liveButton;
+};
+
+export const StopLiveButton = (props: any) => {
+ const { StopLive, dataTestSubj } = props;
+
+ const stopButton = () => {
+ return (
+ StopLive()}
+ color="danger"
+ data-test-subj={dataTestSubj}
+ >
+ Stop
+
+ );
+ };
+ return stopButton();
+};
+
+export const sleep = (milliseconds: number | undefined) => {
+ return new Promise((resolve) => setTimeout(resolve, milliseconds));
+};
diff --git a/public/components/common/search/autocomplete.test.tsx b/public/components/common/search/autocomplete.test.tsx
new file mode 100644
index 0000000000..fd50171010
--- /dev/null
+++ b/public/components/common/search/autocomplete.test.tsx
@@ -0,0 +1,733 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { fireEvent, render } from '@testing-library/react';
+import { configure } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import DSLService from 'public/services/requests/dsl';
+import React from 'react';
+import { Autocomplete } from './autocomplete';
+import { parseGetSuggestions } from './autocomplete_logic';
+import {
+ AutocompleteItem,
+ pipeCommands,
+ statsCommands,
+} from '../../../../common/constants/autocomplete';
+import { act } from 'react-dom/test-utils';
+
+configure({ adapter: new Adapter() });
+
+describe('renders autocomplete', function () {
+ const query = '';
+ const tempQuery = '';
+ const handleQueryChange = jest.fn();
+ const handleQuerySearch = jest.fn();
+ const dslService = ({
+ http: jest.fn(),
+ fetch: jest.fn(),
+ fetchIndices: jest.fn(),
+ fetchFields: jest.fn(),
+ } as unknown) as DSLService;
+ const getSuggestions = jest.fn();
+ const onItemSelect = jest.fn();
+ const utils = render(
+
+ );
+
+ const searchBar = utils.getByPlaceholderText('Enter PPL query');
+
+ it('handles query change', () => {
+ act(() => {
+ fireEvent.change(searchBar, { target: { value: 'new query' } });
+ });
+ expect(handleQueryChange).toBeCalledWith('new query');
+ });
+
+ it('handles query search on shift enter', () => {
+ act(() => {
+ fireEvent.keyDown(searchBar, { keyCode: 13, shiftKey: true });
+ });
+ expect(handleQuerySearch).toBeCalled();
+ });
+});
+
+describe('autocomplete logic', function () {
+ const dslService = ({
+ http: jest.fn(),
+ fetch: jest
+ .fn()
+ .mockReturnValueOnce({
+ aggregations: { top_tags: { buckets: [{ key: 'data', doc_count: 1 }] } },
+ })
+ .mockReturnValueOnce({
+ aggregations: {
+ top_tags: {
+ buckets: [
+ { key: 1, doc_count: 1 },
+ { key: 0, doc_count: 1 },
+ ],
+ },
+ },
+ })
+ .mockReturnValue({ aggregations: { top_tags: { buckets: [{ key: 24, doc_count: 1 }] } } }),
+ fetchIndices: jest.fn().mockReturnValue([{ index: 'test_index' }]),
+ fetchFields: jest.fn().mockReturnValue({
+ test_index: {
+ mappings: {
+ properties: {
+ str_field: { type: 'string' },
+ bool_field: { type: 'boolean' },
+ num_field: { type: 'integer' },
+ },
+ },
+ },
+ }),
+ } as unknown) as DSLService;
+
+ it('suggests source if empty', async () => {
+ const input = '';
+ const expected = [
+ {
+ label: 'source',
+ input,
+ suggestion: 'source',
+ itemName: 'source',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(dslService.fetchIndices).toBeCalled();
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('continues to suggest source after S', async () => {
+ const input = 'S';
+ const expected = [
+ {
+ label: 'source',
+ input,
+ suggestion: 'ource',
+ itemName: 'source',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+ it('suggests = after source', async () => {
+ const input = 'source ';
+ const expected = [
+ {
+ label: 'source =',
+ input,
+ suggestion: '=',
+ itemName: '=',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests index after source =', async () => {
+ const input = 'source = ';
+ const expected = [
+ {
+ label: 'source = test_index',
+ input,
+ suggestion: 'test_index',
+ itemName: 'test_index',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('continues to suggest index after source = TeSt', async () => {
+ const input = 'source = TeSt';
+ const expected = [
+ {
+ label: 'source = test_index',
+ input,
+ suggestion: '_index',
+ itemName: 'test_index',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests | after source = test_index', async () => {
+ const input = 'source = test_index ';
+ const expected = [
+ {
+ label: 'source = test_index |',
+ input,
+ suggestion: '|',
+ itemName: '|',
+ },
+ {
+ label: 'source = test_index,',
+ input,
+ suggestion: ',',
+ itemName: ',',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests pipeCommands after |', async () => {
+ const input = 'source = test_index | ';
+ const expected = pipeCommands.map((c) => {
+ return {
+ label: `source = test_index | ${c.label}`,
+ input,
+ suggestion: c.label,
+ itemName: c.label,
+ };
+ }) as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(dslService.fetchFields).toBeCalled();
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('continues to suggest field after where StR_F', async () => {
+ const input = 'source = test_index | where StR_F';
+ const expected = [
+ {
+ label: 'source = test_index | where str_field',
+ input,
+ suggestion: 'ield',
+ itemName: 'str_field',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests = after where str_field', async () => {
+ const input = 'source = test_index | where str_field ';
+ const expected = [
+ {
+ label: 'source = test_index | where str_field =',
+ input,
+ suggestion: '=',
+ itemName: '=',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(dslService.fetch).toBeCalled();
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests data after where str_field = ', async () => {
+ const input = 'source = test_index | where str_field = ';
+ const expected = [
+ {
+ label: 'source = test_index | where str_field = "data"',
+ input,
+ suggestion: '"data"',
+ itemName: '"data"',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('continues to suggest data after where str_field = "D', async () => {
+ const input = 'source = test_index | where str_field = "D';
+ const expected = [
+ {
+ label: 'source = test_index | where str_field = "data"',
+ input,
+ suggestion: 'ata"',
+ itemName: '"data"',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests | after where str_field = "data"', async () => {
+ const input = 'source = test_index | where str_field = "data" ';
+ const expected = [
+ {
+ label: 'source = test_index | where str_field = "data" |',
+ input,
+ suggestion: '|',
+ itemName: '|',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('continues to suggest field after where BoOl_F', async () => {
+ const input = 'source = test_index | where BoOl_F';
+ const expected = [
+ {
+ label: 'source = test_index | where bool_field',
+ input,
+ suggestion: 'ield',
+ itemName: 'bool_field',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests = after where bool_field', async () => {
+ const input = 'source = test_index | where bool_field ';
+ const expected = [
+ {
+ label: 'source = test_index | where bool_field =',
+ input,
+ suggestion: '=',
+ itemName: '=',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(dslService.fetch).toBeCalled();
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests data after where bool_field = ', async () => {
+ const input = 'source = test_index | where bool_field = ';
+ const expected = [
+ {
+ label: 'source = test_index | where bool_field = True',
+ input,
+ suggestion: 'True',
+ itemName: 'True',
+ },
+ {
+ label: 'source = test_index | where bool_field = False',
+ input,
+ suggestion: 'False',
+ itemName: 'False',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('continues to suggest data after where bool_field = fA', async () => {
+ const input = 'source = test_index | where bool_field = fA';
+ const expected = [
+ {
+ label: 'source = test_index | where bool_field = False',
+ input,
+ suggestion: 'lse',
+ itemName: 'False',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests | after where bool_field = True', async () => {
+ const input = 'source = test_index | where bool_field = True ';
+ const expected = [
+ {
+ label: 'source = test_index | where bool_field = True |',
+ input,
+ suggestion: '|',
+ itemName: '|',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('continues to suggest match( after where Ma', async () => {
+ const input = 'source = test_index | where Ma';
+ const expected = [
+ {
+ label: 'source = test_index | where match(',
+ input,
+ suggestion: 'tch(',
+ itemName: 'match(',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests fields after where match(', async () => {
+ const input = 'source = test_index | where match( ';
+ const expected = [
+ {
+ label: 'source = test_index | where match( str_field',
+ input,
+ suggestion: 'str_field',
+ itemName: 'str_field',
+ },
+ {
+ label: 'source = test_index | where match( bool_field',
+ input,
+ suggestion: 'bool_field',
+ itemName: 'bool_field',
+ },
+ {
+ label: 'source = test_index | where match( num_field',
+ input,
+ suggestion: 'num_field',
+ itemName: 'num_field',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests , after where match( num_field', async () => {
+ const input = 'source = test_index | where match( num_field ';
+ const expected = [
+ {
+ label: 'source = test_index | where match( num_field ,',
+ input,
+ suggestion: ',',
+ itemName: ',',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(dslService.fetch).toBeCalled();
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests data after where match( num_field ,', async () => {
+ const input = 'source = test_index | where match( num_field , ';
+ const expected = [
+ {
+ label: 'source = test_index | where match( num_field , 24',
+ input,
+ suggestion: '24',
+ itemName: '24',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests ) after where match( num_field , 24', async () => {
+ const input = 'source = test_index | where match( num_field , 24 ';
+ const expected = [
+ {
+ label: 'source = test_index | where match( num_field , 24 )',
+ input,
+ suggestion: ')',
+ itemName: ')',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests | after where match( num_field , 24 )', async () => {
+ const input = 'source = test_index | where match( num_field , 24 ) ';
+ const expected = [
+ {
+ label: 'source = test_index | where match( num_field , 24 ) |',
+ input,
+ suggestion: '|',
+ itemName: '|',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests statsCommands after stats', async () => {
+ const input = 'source = test_index | stats ';
+ const expected = statsCommands.map((c) => {
+ return {
+ label: `source = test_index | stats ${c.label}`,
+ input,
+ suggestion: c.label,
+ itemName: c.label,
+ };
+ }) as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests by, comma, pipe after stats count()', async () => {
+ const input = 'source = test_index | stats count() ';
+ const expected = [',', '|', 'by'].map((suggestion) => {
+ return {
+ label: `source = test_index | stats count() ${suggestion}`,
+ input,
+ suggestion,
+ itemName: suggestion,
+ };
+ }) as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests fields after stats count() by', async () => {
+ const input = 'source = test_index | stats count() by ';
+ const expected = [
+ {
+ label: 'source = test_index | stats count() by span(',
+ input,
+ suggestion: 'span(',
+ itemName: 'span(',
+ },
+ {
+ label: 'source = test_index | stats count() by str_field',
+ input,
+ suggestion: 'str_field',
+ itemName: 'str_field',
+ },
+ {
+ label: 'source = test_index | stats count() by bool_field',
+ input,
+ suggestion: 'bool_field',
+ itemName: 'bool_field',
+ },
+ {
+ label: 'source = test_index | stats count() by num_field',
+ input,
+ suggestion: 'num_field',
+ itemName: 'num_field',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests | after stats count() by str_field', async () => {
+ const input = 'source = test_index | stats count() by str_field ';
+ const expected = [
+ {
+ label: 'source = test_index | stats count() by str_field |',
+ input,
+ suggestion: '|',
+ itemName: '|',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests num_field after stats sum(', async () => {
+ const input = 'source = test_index | stats sum( ';
+ const expected = [
+ {
+ label: 'source = test_index | stats sum( num_field',
+ input,
+ suggestion: 'num_field',
+ itemName: 'num_field',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests by after stats sum( num_field )', async () => {
+ const input = 'source = test_index | stats sum( num_field ) ';
+ const expected = [
+ {
+ label: 'source = test_index | stats sum( num_field ) ,',
+ input,
+ suggestion: ',',
+ itemName: ',',
+ },
+ {
+ label: 'source = test_index | stats sum( num_field ) |',
+ input,
+ suggestion: '|',
+ itemName: '|',
+ },
+ {
+ label: 'source = test_index | stats sum( num_field ) by',
+ input,
+ suggestion: 'by',
+ itemName: 'by',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests fields after stats sum( num_field ) by', async () => {
+ const input = 'source = test_index | stats sum( num_field ) by ';
+ const expected = [
+ {
+ label: 'source = test_index | stats sum( num_field ) by span(',
+ input,
+ suggestion: 'span(',
+ itemName: 'span(',
+ },
+ {
+ label: 'source = test_index | stats sum( num_field ) by str_field',
+ input,
+ suggestion: 'str_field',
+ itemName: 'str_field',
+ },
+ {
+ label: 'source = test_index | stats sum( num_field ) by bool_field',
+ input,
+ suggestion: 'bool_field',
+ itemName: 'bool_field',
+ },
+ {
+ label: 'source = test_index | stats sum( num_field ) by num_field',
+ input,
+ suggestion: 'num_field',
+ itemName: 'num_field',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('continues to suggest fields after FiE', async () => {
+ const input = 'source = test_index | FiE';
+ const expected = [
+ {
+ label: 'source = test_index | fields',
+ input,
+ suggestion: 'lds',
+ itemName: 'fields',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests fields after fields', async () => {
+ const input = 'source = test_index | fields ';
+ const expected = [
+ {
+ label: 'source = test_index | fields +',
+ input,
+ suggestion: '+',
+ itemName: '+',
+ },
+ {
+ label: 'source = test_index | fields -',
+ input,
+ suggestion: '-',
+ itemName: '-',
+ },
+ {
+ label: 'source = test_index | fields str_field',
+ input,
+ suggestion: 'str_field',
+ itemName: 'str_field',
+ },
+ {
+ label: 'source = test_index | fields bool_field',
+ input,
+ suggestion: 'bool_field',
+ itemName: 'bool_field',
+ },
+ {
+ label: 'source = test_index | fields num_field',
+ input,
+ suggestion: 'num_field',
+ itemName: 'num_field',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests , after fields str_field', async () => {
+ const input = 'source = test_index | fields str_field ';
+ const expected = [
+ {
+ label: 'source = test_index | fields str_field ,',
+ input,
+ suggestion: ',',
+ itemName: ',',
+ },
+ {
+ label: 'source = test_index | fields str_field |',
+ input,
+ suggestion: '|',
+ itemName: '|',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests fields after fields str_field, ', async () => {
+ const input = 'source = test_index | fields str_field , ';
+ const expected = [
+ {
+ label: 'source = test_index | fields str_field , str_field',
+ input,
+ suggestion: 'str_field',
+ itemName: 'str_field',
+ },
+ {
+ label: 'source = test_index | fields str_field , bool_field',
+ input,
+ suggestion: 'bool_field',
+ itemName: 'bool_field',
+ },
+ {
+ label: 'source = test_index | fields str_field , num_field',
+ input,
+ suggestion: 'num_field',
+ itemName: 'num_field',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('continues to suggest dedup after DE', async () => {
+ const input = 'source = test_index | DE';
+ const expected = [
+ {
+ label: 'source = test_index | dedup',
+ input,
+ suggestion: 'dup',
+ itemName: 'dedup',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+
+ it('suggests fields after dedup', async () => {
+ const input = 'source = test_index | dedup ';
+ const expected = [
+ {
+ label: 'source = test_index | dedup str_field',
+ input,
+ suggestion: 'str_field',
+ itemName: 'str_field',
+ },
+ {
+ label: 'source = test_index | dedup bool_field',
+ input,
+ suggestion: 'bool_field',
+ itemName: 'bool_field',
+ },
+ {
+ label: 'source = test_index | dedup num_field',
+ input,
+ suggestion: 'num_field',
+ itemName: 'num_field',
+ },
+ ] as AutocompleteItem[];
+ const suggestion = await parseGetSuggestions('', input, dslService);
+ expect(suggestion).toStrictEqual(expected);
+ });
+});
diff --git a/public/components/common/search/autocomplete.tsx b/public/components/common/search/autocomplete.tsx
new file mode 100644
index 0000000000..3d3fdac26c
--- /dev/null
+++ b/public/components/common/search/autocomplete.tsx
@@ -0,0 +1,215 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable react-hooks/exhaustive-deps */
+
+import './search.scss';
+import $ from 'jquery';
+import React, { useEffect, useMemo, useState } from 'react';
+import { AutocompleteState, createAutocomplete } from '@algolia/autocomplete-core';
+import { EuiFieldText, EuiTextArea } from '@elastic/eui';
+import DSLService from 'public/services/requests/dsl';
+import { IQueryBarProps } from './search';
+import { uiSettingsService } from '../../../../common/utils';
+import { AutocompleteItem } from '../../../../common/constants/autocomplete';
+
+interface AutocompleteProps extends IQueryBarProps {
+ getSuggestions: (
+ base: string,
+ query: string,
+ dslService: DSLService,
+ possibleCommands: Array<{ label: string }>
+ ) => Promise;
+ onItemSelect: any;
+ isDisabled?: boolean;
+ baseQuery: string;
+ tabId: string;
+ placeholder?: string;
+ possibleCommands?: Array<{ label: string }>;
+ append?: any;
+}
+
+export const Autocomplete = (props: AutocompleteProps) => {
+ const {
+ query,
+ tempQuery,
+ handleQueryChange,
+ handleQuerySearch,
+ dslService,
+ getSuggestions,
+ onItemSelect,
+ isDisabled,
+ baseQuery,
+ tabId = '',
+ placeholder = 'Enter PPL query',
+ possibleCommands,
+ append,
+ } = props;
+
+ const [autocompleteState, setAutocompleteState] = useState>({
+ collections: [],
+ completion: null,
+ context: {},
+ isOpen: false,
+ query: tempQuery,
+ activeItemId: null,
+ status: 'idle',
+ });
+
+ const appLogEvents = tabId.startsWith('application-analytics-tab');
+ const panelsFilter = tabId === 'panels-filter';
+
+ useEffect(() => {
+ const searchBar = document.getElementById('autocomplete-textarea');
+
+ searchBar?.addEventListener('keydown', (e) => {
+ const keyCode = e.which || e.keyCode;
+ if (keyCode === 13 && e.shiftKey) {
+ handleQuerySearch();
+ }
+ return () => {
+ $('#autocomplete-textarea').unbind('keydown');
+ };
+ });
+ }, []);
+
+ const depArray =
+ appLogEvents || panelsFilter
+ ? [baseQuery, query, dslService, autocompleteState]
+ : [baseQuery, query, dslService];
+
+ const autocomplete = useMemo(() => {
+ return createAutocomplete<
+ AutocompleteItem,
+ React.BaseSyntheticEvent,
+ React.MouseEvent,
+ React.KeyboardEvent
+ >({
+ openOnFocus: true,
+ defaultActiveItemId: 0,
+ onStateChange: ({ state }) => {
+ setAutocompleteState({
+ ...state,
+ });
+ handleQueryChange(state.query);
+ },
+ initialState: {
+ ...autocompleteState,
+ query: query || '',
+ },
+ getSources() {
+ return [
+ {
+ sourceId: 'querySuggestions',
+ // eslint-disable-next-line no-shadow
+ async getItems({ query }) {
+ const suggestions = await getSuggestions(
+ baseQuery,
+ query,
+ dslService,
+ possibleCommands
+ );
+ return suggestions;
+ },
+ onSelect: ({ setQuery, item }) => {
+ onItemSelect(
+ {
+ setQuery,
+ item,
+ },
+ dslService
+ );
+ $('#autocomplete-textarea').blur();
+ $('#autocomplete-textarea').focus();
+ },
+ },
+ ];
+ },
+ });
+ }, depArray);
+
+ const TextArea = panelsFilter ? EuiFieldText : EuiTextArea;
+
+ return (
+
+
+ {autocompleteState.isOpen && (
+
+ {autocompleteState.collections.map((collection, index) => {
+ const { source, items } = collection;
+ const filteredItems = items.filter((item, itemIndex) => {
+ return items.findIndex((i) => i.itemName === item.itemName) === itemIndex;
+ });
+ return (
+
+
+ {items.length > 0 && (
+
+ {filteredItems.map((item) => {
+ const fullWord = item.itemName;
+ return (
+
+
+
+
+
+ ${fullWord.slice(0, -item.suggestion.length)} ${
+ item.suggestion
+ }
+
`,
+ }}
+ />
+
+
+
+
+ );
+ })}
+
+ )}
+
+
+ );
+ })}
+
+ )}
+
+ );
+};
diff --git a/public/components/common/search/autocomplete_logic.ts b/public/components/common/search/autocomplete_logic.ts
new file mode 100644
index 0000000000..347d0e3b37
--- /dev/null
+++ b/public/components/common/search/autocomplete_logic.ts
@@ -0,0 +1,378 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import DSLService from 'public/services/requests/dsl';
+import { isEmpty } from 'lodash';
+import { getDataValueQuery } from './queries/data_queries';
+import {
+ statsCommands,
+ numberTypes,
+ pipeCommands,
+ DataItem,
+ FieldItem,
+ IndexItem,
+ AutocompleteItem,
+ regexForIndex,
+ regexForSuggestion,
+ PIPE_AFTER_WHERE,
+ DATA_AFTER_WHERE_EQUAL,
+ EMPTY_REGEX,
+ EQUAL_AFTER_WHERE_FIELD,
+ MATCH_FIELD_AFTER_WHERE,
+ COMMA_AFTER_FIELD,
+ DATA_AFTER_COMMA,
+ CLOSE_AFTER_DATA,
+ PIPE_AFTER_MATCH,
+ FIELD_IN_FIELD_LOOP,
+ COMMA_PIPE_AFTER_FIELD,
+ PIPE_AFTER_KEEP_EMPTY,
+ PIPE_AFTER_CONSECUTIVE,
+ EQUAL_AFTER_EVAL_FIELD,
+ FIELD_AFTER_EVAL_EQUAL,
+ MATH_AFTER_FIELD,
+ PIPE_MATH_AFTER_EXPRESSIONS,
+ PLUS_MINUS_FIELD_AFTER_FIELDS,
+ FIELD_AFTER_PLUS_MINUS,
+ COMMA_PIPE_AFTER_FIELDS,
+ FIELD_IN_FIELDS_LOOP,
+ RARE_TOP_FIELD_LOOP,
+ COMMA_PIPE_BY_AFTER_FIELD,
+ FIELD_AFTER_BY,
+ PIPE_AFTER_GROUP_BY,
+ AS_AFTER_FIELD,
+ COMMA_PIPE_AFTER_RENAME_FIELD,
+ FIELD_AFTER_COMMA,
+ PIPE_AFTER_HEAD,
+ PLUS_MINUS_FIELD_AFTER_SORT,
+ FIELD_AFTER_PLUS_MINUS_SORT,
+ COMMA_PIPE_AFTER_SORT_FIELD,
+ PLUS_MINUS_FIELD_IN_FIELDS_LOOP,
+ FIELD_AFTER_COMMAND,
+ FIELD_SPAN_AFTER_GROUP_BY,
+ NUM_FIELD_AFTER_AGGREGATION,
+ CLOSE_AFTER_FIELD,
+ COMMA_PIPE_BY_AFTER_AGGREGATION,
+ PIPE_AFTER_STATS_GROUP_BY,
+ AGGREGATION_FOR_STATS,
+ FIELD_AFTER_SPAN,
+ CLOSE_AFTER_SPAN,
+ PIPE_AFTER_SPAN,
+ STRING_FIELD_AFTER_PARSE,
+ PIPE_AFTER_PARSE,
+ EQUAL_AFTER_SOURCE,
+ INDEX_AFTER_EQUAL,
+ PIPE_COMMA_AFTER_INDEX,
+ MORE_INDEX_AFTER_COMMA,
+} from '../../../../common/constants/autocomplete';
+
+let currIndices: string[] = [];
+let currField: string = '';
+let currFieldType: string = '';
+
+const indexList: string[] = [];
+const fieldList: string[] = [];
+const fieldsFromBackend: FieldItem[] = [];
+const indicesFromBackend: IndexItem[] = [];
+const dataValuesFromBackend: DataItem[] = [];
+
+const getIndices = async (dslService: DSLService): Promise => {
+ if (indicesFromBackend.length === 0) {
+ const indices = (await dslService.fetchIndices()).filter(
+ ({ index }: { index: any }) => !index.startsWith('.')
+ );
+ for (let i = 0; i < indices.length; i++) {
+ indicesFromBackend.push({
+ label: indices[i].index,
+ });
+ indexList.push(indices[i].index);
+ }
+ }
+};
+
+const getFields = async (dslService: DSLService): Promise => {
+ if (!isEmpty(currIndices)) {
+ fieldsFromBackend.length = 0;
+ for (let i = 0; i < currIndices.length; i++) {
+ const index = currIndices[i];
+ const res = await dslService.fetchFields(index);
+ if (!res) {
+ return;
+ }
+ const resFieldList = Object.keys(res?.[index].mappings.properties);
+ for (let j = 0; j < resFieldList.length; j++) {
+ const element = resFieldList[j];
+ if (
+ res?.[index].mappings.properties[element].properties ||
+ res?.[index].mappings.properties[element].fields
+ ) {
+ fieldsFromBackend.push({ label: element, type: 'string' });
+ } else if (res?.[index].mappings.properties[element].type === 'keyword') {
+ fieldsFromBackend.push({ label: element, type: 'string' });
+ } else {
+ fieldsFromBackend.push({
+ label: element,
+ type: res?.[index].mappings.properties[element].type,
+ });
+ }
+ fieldList.push(element);
+ }
+ }
+ }
+};
+
+const getDataValues = async (
+ indices: string[],
+ field: string,
+ fieldType: string,
+ dslService: DSLService
+): Promise => {
+ for (let i = 0; i < indices.length; i++) {
+ const index = indices[i];
+ const res = (await dslService.fetch(getDataValueQuery(index, field)))?.aggregations?.top_tags
+ ?.buckets;
+ if (isEmpty(res)) {
+ continue;
+ }
+ dataValuesFromBackend.length = 0;
+ res.forEach((e: any) => {
+ if (fieldType === 'string') {
+ dataValuesFromBackend.push({ label: '"' + e.key + '"', doc_count: e.doc_count });
+ } else if (fieldType === 'boolean') {
+ if (e.key === 1) {
+ dataValuesFromBackend.push({ label: 'True', doc_count: e.doc_count });
+ } else {
+ dataValuesFromBackend.push({ label: 'False', doc_count: e.doc_count });
+ }
+ } else if (fieldType !== 'geo_point') {
+ dataValuesFromBackend.push({ label: String(e.key), doc_count: e.doc_count });
+ }
+ });
+ return dataValuesFromBackend;
+ }
+ return [];
+};
+
+export const onItemSelect = async (
+ { setQuery, item }: { setQuery: any; item: any },
+ dslService: DSLService
+) => {
+ if (fieldsFromBackend.length === 0 && indexList.includes(item.itemName)) {
+ currIndices = [item.itemName];
+ getFields(dslService);
+ }
+ setQuery(item.label + ' ');
+};
+
+// Function to create the array of objects to be suggested
+const fillSuggestions = (str: string, word: string, items: any): AutocompleteItem[] => {
+ const lowerWord = word.toLowerCase();
+ const suggestionList = [];
+ for (let i = 0; i < items.length; i++) {
+ suggestionList.push({
+ label: str.substring(0, str.lastIndexOf(word)) + items[i].label,
+ input: str,
+ suggestion: items[i].label.substring(word.length),
+ itemName: items[i].label,
+ });
+ }
+ return filterSuggestions(suggestionList, lowerWord);
+};
+
+// Function to filter out currently inputed suggestions
+const filterSuggestions = (suggestions: AutocompleteItem[], prefix: string) => {
+ return suggestions.filter(
+ ({ itemName }) =>
+ itemName.toLowerCase().startsWith(prefix) && prefix.localeCompare(itemName.toLowerCase())
+ );
+};
+
+export const parseForIndices = (query: string) => {
+ for (let i = 0; i < regexForIndex.length; i++) {
+ const groupArray = regexForIndex[i].exec(query);
+ if (groupArray) {
+ const afterEqual = query.substring(query.indexOf('=') + 1);
+ const noSpaces = afterEqual.replace(/\s/g, '');
+ return noSpaces.split(',');
+ }
+ }
+ return [];
+};
+
+const parseForNextSuggestion = (command: string) => {
+ for (let i = 0; i < regexForSuggestion.length; i++) {
+ const groupArray = regexForSuggestion[i].exec(command);
+ if (groupArray) {
+ return regexForSuggestion[i];
+ }
+ }
+};
+
+export const parseGetSuggestions = async (
+ base: string,
+ currQuery: string,
+ dslService: DSLService,
+ possibleCommands: Array<{ label: string }> = pipeCommands
+) => {
+ const fullQuery = base ? base + '| ' + currQuery : currQuery;
+ const splitSpaceQuery = fullQuery.split(' ');
+ const splitPipeQuery = fullQuery.split('|');
+
+ const lastWord = splitSpaceQuery[splitSpaceQuery.length - 1];
+ const lastCommand = splitPipeQuery[splitPipeQuery.length - 1];
+ const firstCommand = splitPipeQuery[0];
+
+ if (!base && isEmpty(indicesFromBackend)) {
+ await getIndices(dslService);
+ }
+
+ if (fullQuery.match(EMPTY_REGEX)) {
+ return fillSuggestions(currQuery, lastWord, [{ label: 'source' }]);
+ }
+
+ const next = parseForNextSuggestion(lastCommand);
+ if (next) {
+ switch (next) {
+ case AGGREGATION_FOR_STATS:
+ return fillSuggestions(currQuery, lastWord, statsCommands);
+ case AS_AFTER_FIELD:
+ return fillSuggestions(currQuery, lastWord, [{ label: 'as' }]);
+ case COMMA_PIPE_BY_AFTER_FIELD:
+ case COMMA_PIPE_BY_AFTER_AGGREGATION:
+ return fillSuggestions(currQuery, lastWord, [
+ { label: ',' },
+ { label: '|' },
+ { label: 'by' },
+ ]);
+ case COMMA_PIPE_AFTER_FIELDS:
+ case COMMA_PIPE_AFTER_RENAME_FIELD:
+ case COMMA_PIPE_AFTER_SORT_FIELD:
+ return fillSuggestions(currQuery, lastWord, [{ label: ',' }, { label: '|' }]);
+ case PIPE_COMMA_AFTER_INDEX:
+ return filterSuggestions(
+ [
+ { label: currQuery + '|', input: currQuery, suggestion: '|', itemName: '|' },
+ { label: currQuery.trim() + ',', input: currQuery, suggestion: ',', itemName: ',' },
+ ],
+ lastWord
+ );
+ case PLUS_MINUS_FIELD_AFTER_FIELDS:
+ case PLUS_MINUS_FIELD_AFTER_SORT:
+ case PLUS_MINUS_FIELD_IN_FIELDS_LOOP:
+ return fillSuggestions(currQuery, lastWord, [
+ { label: '+' },
+ { label: '-' },
+ ...fieldsFromBackend,
+ ]);
+ case PIPE_MATH_AFTER_EXPRESSIONS:
+ return fillSuggestions(currQuery, lastWord, [
+ { label: '|' },
+ { label: '+' },
+ { label: '-' },
+ { label: '*' },
+ { label: '/' },
+ ]);
+ case MATH_AFTER_FIELD:
+ return fillSuggestions(currQuery, lastWord, [
+ { label: '+' },
+ { label: '-' },
+ { label: '*' },
+ { label: '/' },
+ ]);
+ case COMMA_PIPE_AFTER_FIELD:
+ return fillSuggestions(currQuery, lastWord, [
+ { label: ',' },
+ { label: '|' },
+ { label: 'keepempty=true' },
+ { label: 'consecutive=true' },
+ ]);
+ case CLOSE_AFTER_DATA:
+ case CLOSE_AFTER_FIELD:
+ case CLOSE_AFTER_SPAN:
+ return fillSuggestions(currQuery, lastWord, [{ label: ')' }]);
+ case COMMA_AFTER_FIELD:
+ currField = COMMA_AFTER_FIELD.exec(lastCommand)![1];
+ currFieldType = fieldsFromBackend.find((field) => field.label === currField)?.type || '';
+ await getDataValues(currIndices, currField, currFieldType, dslService);
+ return fillSuggestions(currQuery, lastWord, [{ label: ',' }]);
+ case FIELD_AFTER_SPAN:
+ const matchArray = FIELD_AFTER_SPAN.exec(lastCommand);
+ const tempField = matchArray![matchArray!.length - 1];
+ if (fieldList.includes(tempField)) {
+ currField = tempField;
+ currFieldType = fieldsFromBackend.find((field) => field.label === currField)?.type || '';
+ await getDataValues(currIndices, currField, currFieldType, dslService);
+ return fillSuggestions(currQuery, lastWord, [{ label: ',' }]);
+ } else {
+ return fillSuggestions(currQuery, lastWord, fieldsFromBackend);
+ }
+ case FIELD_AFTER_COMMAND:
+ case FIELD_IN_FIELD_LOOP:
+ case FIELD_AFTER_EVAL_EQUAL:
+ case FIELD_AFTER_PLUS_MINUS:
+ case FIELD_IN_FIELDS_LOOP:
+ case RARE_TOP_FIELD_LOOP:
+ case FIELD_AFTER_BY:
+ case FIELD_AFTER_COMMA:
+ case FIELD_AFTER_PLUS_MINUS_SORT:
+ return fillSuggestions(currQuery, lastWord, fieldsFromBackend);
+ case FIELD_SPAN_AFTER_GROUP_BY:
+ return fillSuggestions(currQuery, lastWord, [{ label: 'span(' }, ...fieldsFromBackend]);
+ case NUM_FIELD_AFTER_AGGREGATION:
+ const numberFields = fieldsFromBackend.filter((field: { type: string }) =>
+ numberTypes.includes(field.type)
+ );
+ return fillSuggestions(currQuery, lastWord, numberFields);
+ case STRING_FIELD_AFTER_PARSE:
+ return fillSuggestions(
+ currQuery,
+ lastWord,
+ fieldsFromBackend.filter((field) => field.type === 'string')
+ );
+ case PIPE_AFTER_WHERE:
+ case PIPE_AFTER_MATCH:
+ case PIPE_AFTER_KEEP_EMPTY:
+ case PIPE_AFTER_CONSECUTIVE:
+ case PIPE_AFTER_GROUP_BY:
+ case PIPE_AFTER_HEAD:
+ case PIPE_AFTER_STATS_GROUP_BY:
+ case PIPE_AFTER_SPAN:
+ case PIPE_AFTER_PARSE:
+ return fillSuggestions(currQuery, lastWord, [{ label: '|' }]);
+ case DATA_AFTER_WHERE_EQUAL:
+ case DATA_AFTER_COMMA:
+ return fillSuggestions(currQuery, lastWord, dataValuesFromBackend);
+ case EQUAL_AFTER_WHERE_FIELD:
+ case EQUAL_AFTER_EVAL_FIELD:
+ currField = next.exec(lastCommand)![1];
+ currFieldType = fieldsFromBackend.find((field) => field.label === currField)?.type || '';
+ await getDataValues(currIndices, currField, currFieldType, dslService);
+ return fillSuggestions(currQuery, lastWord, [{ label: '=' }]);
+ case MATCH_FIELD_AFTER_WHERE:
+ return fillSuggestions(currQuery, lastWord, [{ label: 'match(' }, ...fieldsFromBackend]);
+ case EQUAL_AFTER_SOURCE:
+ return fillSuggestions(currQuery, lastWord, [{ label: '=' }]);
+ case INDEX_AFTER_EQUAL:
+ return fillSuggestions(currQuery, lastWord, indicesFromBackend);
+ case MORE_INDEX_AFTER_COMMA:
+ const trimmedIndices = indicesFromBackend.map((index) => {
+ return {
+ label: currQuery.substring(0, currQuery.lastIndexOf(lastWord)).trim() + index.label,
+ input: currQuery,
+ suggestion: index.label.substring(lastWord.length),
+ itemName: index.label,
+ };
+ });
+ return filterSuggestions(trimmedIndices, lastWord);
+ case EMPTY_REGEX:
+ currIndices = parseForIndices(firstCommand);
+ await getFields(dslService);
+ currField = '';
+ currFieldType = '';
+ return fillSuggestions(currQuery, lastWord, possibleCommands);
+ }
+ }
+
+ return [];
+};
diff --git a/public/components/common/search/date_picker.tsx b/public/components/common/search/date_picker.tsx
new file mode 100644
index 0000000000..75087c9f13
--- /dev/null
+++ b/public/components/common/search/date_picker.tsx
@@ -0,0 +1,27 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { EuiSuperDatePicker } from '@elastic/eui';
+import { IDatePickerProps } from './search';
+import { uiSettingsService } from '../../../../common/utils';
+
+export function DatePicker(props: IDatePickerProps) {
+ const { startTime, endTime, handleTimePickerChange, handleTimeRangePickerRefresh } = props;
+
+ const handleTimeChange = (e: any) => handleTimePickerChange([e.start, e.end]);
+
+ return (
+
+ );
+}
diff --git a/public/components/common/search/queries/data_queries.ts b/public/components/common/search/queries/data_queries.ts
new file mode 100644
index 0000000000..69ee9dcf21
--- /dev/null
+++ b/public/components/common/search/queries/data_queries.ts
@@ -0,0 +1,19 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const getDataValueQuery = (index: string, field: string) => {
+ const query = {
+ index: index,
+ 'size': 0,
+ 'aggs': {
+ 'top_tags': {
+ 'terms': {
+ 'field': field,
+ }
+ }
+ }
+ }
+ return query;
+}
diff --git a/public/components/common/search/request_handler.tsx b/public/components/common/search/request_handler.tsx
new file mode 100644
index 0000000000..e263f39dcf
--- /dev/null
+++ b/public/components/common/search/request_handler.tsx
@@ -0,0 +1,17 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import _ from 'lodash';
+import { CoreStart } from '../../../../../../src/core/public';
+
+const DSL_ROUTE = '/api/dsl/search';
+
+export function handleDslRequest(http: CoreStart['http'], query) {
+ return http
+ .post(DSL_ROUTE, {
+ body: JSON.stringify(query),
+ })
+ .catch((error) => console.error(error));
+}
diff --git a/public/components/common/search/search.scss b/public/components/common/search/search.scss
new file mode 100644
index 0000000000..1b0666a6d1
--- /dev/null
+++ b/public/components/common/search/search.scss
@@ -0,0 +1,79 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+.globalQueryBar {
+ margin: .5rem 0;
+ padding: .5rem;
+}
+.aa-Autocomplete {
+ width: 100%;
+ position: relative;
+ margin: 4px;
+ margin-left: 8px;
+ --aa-search-input-height: 38px;
+ --aa-panel-border-color-rgb: rgba(227,230,238,255);
+ --aa-input-background-color-rbg: rgba(250,251,253,255);
+}
+.styling {
+ font-weight: bold;
+}
+
+#servicesEntities {
+ position: relative;
+ z-index: 0;
+}
+
+#autocomplete-textarea {
+ width: 100%;
+ outline: none;
+ min-height: 48px;
+ max-width: unset;
+ height: 45px;
+ resize: vertical;
+ font-size: 16px;
+ padding-right: 40px;
+}
+
+.aa-Panel {
+ width: 100%;
+ z-index: 2500;
+}
+
+.aa-Panel--scrollable-dark {
+ background-color: #1D1E24;
+ border: 2px groove #383444;
+}
+
+.aa-Item-dark {
+ color: #DFE5EF;
+}
+
+.event-date-picker {
+ max-width: 35vw;
+}
+
+.ppl-link {
+ border: unset;
+ position: absolute;
+ top: 14px;
+ right: 15px;
+ background-color: transparent;
+}
+.ppl-link-light {
+ color: #006BB4;
+}
+
+.ppl-link-dark {
+ color: #1BA9F5;
+}
+
+.base-query-popover {
+ border: unset;
+ font-size: 17px;
+ position: absolute;
+ top: 20px;
+ left: 8px;
+ background-color: transparent;
+}
diff --git a/public/components/common/search/search.test.tsx b/public/components/common/search/search.test.tsx
new file mode 100644
index 0000000000..6a7543fec0
--- /dev/null
+++ b/public/components/common/search/search.test.tsx
@@ -0,0 +1,71 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { fireEvent, render } from '@testing-library/react';
+import React from 'react';
+import { Search } from './search';
+
+describe('Search bar', () => {
+ it('handles query change', () => {
+ const query = 'rawQuery';
+ const tempQuery = 'rawQuery';
+ const handleQueryChange = jest.fn();
+ const handleQuerySearch = jest.fn();
+ const dslService = jest.fn();
+ const handleTimePickerChange = jest.fn();
+ const selectedPanelName = jest.fn();
+ const selectedCustomPanelOptions = jest.fn();
+ const setSelectedPanelName = jest.fn();
+ const setSelectedCustomPanelOptions = jest.fn();
+ const handleSavingObject = jest.fn();
+ const isPanelTextFieldInvalid = jest.fn();
+ const showSavePanelOptionsList = jest.fn();
+ const handleTimeRangePickerRefresh = jest.fn();
+ const savedObjects = jest.fn();
+ const getFullSuggestions = jest.fn();
+ const onItemSelect = jest.fn();
+ const dateRange = ['now-15m', 'now'];
+ const liveTailButton = jest.fn();
+ const isLiveTailPopoverOpen = jest.fn();
+ const closeLiveTailPopover = jest.fn();
+ const popoverItems = jest.fn();
+ const isLiveTailOn = jest.fn();
+ const countDistribution = jest.fn();
+ const utils = render(
+
+ );
+
+ const searchBar = utils.getByPlaceholderText('Enter PPL query');
+ fireEvent.change(searchBar, { target: { value: 'new query' } });
+ expect(handleQueryChange).toBeCalledWith('new query');
+ });
+});
diff --git a/public/components/common/search/search.tsx b/public/components/common/search/search.tsx
new file mode 100644
index 0000000000..af9a21f89f
--- /dev/null
+++ b/public/components/common/search/search.tsx
@@ -0,0 +1,253 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import './search.scss';
+
+import React, { useState } from 'react';
+import {
+ EuiFlexGroup,
+ EuiButton,
+ EuiFlexItem,
+ EuiPopover,
+ EuiButtonEmpty,
+ EuiPopoverFooter,
+ EuiBadge,
+ EuiContextMenuPanel,
+ EuiToolTip,
+} from '@elastic/eui';
+import _ from 'lodash';
+import { DatePicker } from './date_picker';
+import '@algolia/autocomplete-theme-classic';
+import { Autocomplete } from './autocomplete';
+import { SavePanel } from '../../explorer/save_panel';
+import { PPLReferenceFlyout } from '../helpers';
+import { uiSettingsService } from '../../../../common/utils';
+import { APP_ANALYTICS_TAB_ID_REGEX } from '../../../../common/constants/explorer';
+import { LiveTailButton, StopLiveButton } from '../live_tail/live_tail_button';
+export interface IQueryBarProps {
+ query: string;
+ tempQuery: string;
+ handleQueryChange: (query: string) => void;
+ handleQuerySearch: () => void;
+ dslService: any;
+}
+
+export interface IDatePickerProps {
+ startTime: string;
+ endTime: string;
+ setStartTime: () => void;
+ setEndTime: () => void;
+ setTimeRange: () => void;
+ setIsOutputStale: () => void;
+ handleTimePickerChange: (timeRange: string[]) => any;
+ handleTimeRangePickerRefresh: () => any;
+}
+
+export const Search = (props: any) => {
+ const {
+ query,
+ tempQuery,
+ handleQueryChange,
+ handleQuerySearch,
+ handleTimePickerChange,
+ dslService,
+ startTime,
+ endTime,
+ setStartTime,
+ setEndTime,
+ setIsOutputStale,
+ selectedPanelName,
+ selectedCustomPanelOptions,
+ setSelectedPanelName,
+ setSelectedCustomPanelOptions,
+ handleSavingObject,
+ isPanelTextFieldInvalid,
+ savedObjects,
+ showSavePanelOptionsList,
+ showSaveButton = true,
+ handleTimeRangePickerRefresh,
+ liveTailButton,
+ isLiveTailPopoverOpen,
+ closeLiveTailPopover,
+ popoverItems,
+ isLiveTailOn,
+ selectedSubTabId,
+ searchBarConfigs = {},
+ getSuggestions,
+ onItemSelect,
+ tabId = '',
+ baseQuery = '',
+ stopLive,
+ setIsLiveTailPopoverOpen,
+ liveTailName,
+ } = props;
+
+ const appLogEvents = tabId.match(APP_ANALYTICS_TAB_ID_REGEX);
+
+ const [isSavePanelOpen, setIsSavePanelOpen] = useState(false);
+ const [isFlyoutVisible, setIsFlyoutVisible] = useState(false);
+
+ const closeFlyout = () => {
+ setIsFlyoutVisible(false);
+ };
+
+ const showFlyout = () => {
+ setIsFlyoutVisible(true);
+ };
+
+ let flyout;
+ if (isFlyoutVisible) {
+ flyout = ;
+ }
+
+ const Savebutton = (
+ {
+ setIsSavePanelOpen((staleState) => {
+ return !staleState;
+ });
+ }}
+ data-test-subj="eventExplorer__saveManagementPopover"
+ iconType="arrowDown"
+ >
+ Save
+
+ );
+
+ const liveButton = (
+
+ );
+
+ return (
+
+
+ {appLogEvents && (
+
+
+
+ Base Query
+
+
+
+ )}
+
+
+ showFlyout()}
+ onClickAriaLabel={'pplLinkShowFlyout'}
+ >
+ PPL
+
+
+
+
+ {!isLiveTailOn && (
+ handleTimePickerChange(timeRange)}
+ handleTimeRangePickerRefresh={handleTimeRangePickerRefresh}
+ />
+ )}
+
+ {showSaveButton && !showSavePanelOptionsList && (
+
+
+
+
+
+ )}
+ {isLiveTailOn && (
+
+
+
+ )}
+ {showSaveButton && searchBarConfigs[selectedSubTabId]?.showSaveButton && (
+ <>
+
+ setIsSavePanelOpen(false)}
+ >
+
+
+
+
+ setIsSavePanelOpen(false)}
+ data-test-subj="eventExplorer__querySaveCancel"
+ >
+ Cancel
+
+
+
+ {
+ handleSavingObject();
+ setIsSavePanelOpen(false);
+ }}
+ data-test-subj="eventExplorer__querySaveConfirm"
+ >
+ Save
+
+
+
+
+
+
+ >
+ )}
+
+ {flyout}
+
+ );
+};
diff --git a/public/components/common/search/searchindex.tsx b/public/components/common/search/searchindex.tsx
new file mode 100644
index 0000000000..0a7fe44606
--- /dev/null
+++ b/public/components/common/search/searchindex.tsx
@@ -0,0 +1,60 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { EuiComboBox } from '@elastic/eui';
+import React, { useState, useEffect, memo } from 'react';
+
+
+export const IndexPicker = memo(function indexDropdown(props: any) {
+ return ;
+});
+
+interface Fetch {
+ dslService: any;
+ query: any;
+ handleQueryChange: (query: string, index: string) => void;
+}
+
+export function SearchIndex(options: Fetch) {
+
+ const [indicesFromBackend, setindicesFromBackend] = useState([]);
+
+ // fetch indices from backend
+ const getIndices = async (dslService: any) => {
+ if (indicesFromBackend.length === 0) {
+ const indices = (await dslService.fetchIndices()).filter(
+ ({ index }) => !index.startsWith('.')
+ );
+ for (let i = 0; i < indices.length; i++) {
+ indicesFromBackend.push({
+ label: indices[i].index,
+ });
+ }
+ }
+ };
+
+ useEffect(() => {
+ getIndices(options.dslService);
+ }, []);
+
+ const [selectedOptions, setSelected] = useState(
+ []
+ );
+
+ // handle Index Change
+ const onChange = (selectedOptions) => {
+ options.handleQueryChange(options.query, selectedOptions);
+ setSelected(selectedOptions);
+ };
+
+ return (
+ onChange(e)}
+ />
+ );
+}
diff --git a/public/components/common/side_nav.tsx b/public/components/common/side_nav.tsx
new file mode 100644
index 0000000000..0f63ed243f
--- /dev/null
+++ b/public/components/common/side_nav.tsx
@@ -0,0 +1,140 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ EuiButton,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiPage,
+ EuiPageBody,
+ EuiPageSideBar,
+ EuiSideNav,
+ EuiSideNavItemType,
+ EuiSwitch,
+} from '@elastic/eui';
+import React from 'react';
+import { useState } from 'react';
+import { toMountPoint } from '../../../../../src/plugins/opensearch_dashboards_react/public';
+import { uiSettingsService } from '../../../common/utils';
+
+export function ObservabilitySideBar(props: { children: React.ReactNode }) {
+ // set items.isSelected based on location.hash passed in
+ // tries to find an item where href is a prefix of the hash
+ // if none will try to find an item where the hash is a prefix of href
+ function setIsSelected(
+ items: EuiSideNavItemType[],
+ hash: string,
+ initial = true,
+ reverse = false
+ ): boolean {
+ // Default page is Events Analytics
+ // But it is kept as second option in side nav
+ if (hash === '#/') {
+ items[0].items[2].isSelected = true;
+ return true;
+ }
+ for (let i = 0; i < items.length; i++) {
+ const item = items[i];
+ if (item.href && ((reverse && item.href.startsWith(hash)) || hash.startsWith(item.href))) {
+ item.isSelected = true;
+ return true;
+ }
+ if (item.items?.length && setIsSelected(item.items, hash, false, reverse)) return true;
+ }
+ return initial && setIsSelected(items, hash, false, !reverse);
+ }
+
+ const items = [
+ {
+ name: 'Observability',
+ id: 0,
+ items: [
+ {
+ name: 'Application analytics',
+ id: 1,
+ href: '#/application_analytics',
+ },
+ {
+ name: 'Trace analytics',
+ id: 2,
+ href: '#/trace_analytics/home',
+ items: [
+ {
+ name: 'Traces',
+ id: 2.1,
+ href: '#/trace_analytics/traces',
+ },
+ {
+ name: 'Services',
+ id: 2.2,
+ href: '#/trace_analytics/services',
+ },
+ ],
+ },
+ {
+ name: 'Event analytics',
+ id: 3,
+ href: '#/event_analytics',
+ },
+ {
+ name: 'Operational panels',
+ id: 4,
+ href: '#/operational_panels/',
+ },
+ {
+ name: 'Notebooks',
+ id: 5,
+ href: '#/notebooks',
+ },
+ ],
+ },
+ ];
+ setIsSelected(items, location.hash);
+ const [isDarkMode, setIsDarkMode] = useState(uiSettingsService.get('theme:darkMode'));
+
+ return (
+
+
+
+
+
+
+
+ {
+ uiSettingsService.set('theme:darkMode', !isDarkMode).then((resp) => {
+ setIsDarkMode(!isDarkMode);
+ uiSettingsService.addToast({
+ title: 'Theme setting changes require you to reload the page to take effect.',
+ text: toMountPoint(
+ <>
+
+
+ window.location.reload()}>
+ Reload page
+
+
+
+ >
+ ),
+ color: 'success',
+ });
+ });
+ }}
+ />
+
+
+
+ {props.children}
+
+ );
+}
diff --git a/public/components/custom_panels/__tests__/__snapshots__/custom_panel_table.test.tsx.snap b/public/components/custom_panels/__tests__/__snapshots__/custom_panel_table.test.tsx.snap
new file mode 100644
index 0000000000..29687e5095
--- /dev/null
+++ b/public/components/custom_panels/__tests__/__snapshots__/custom_panel_table.test.tsx.snap
@@ -0,0 +1,2894 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Panels Table Component renders empty panel table container 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+ Operational panels
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Panels
+
+ (
+ 0
+ )
+
+
+
+
+
+
+
+
+
+
+ Use Operational panels to create and view different visualizations on ingested observability data, using PPL (Piped Processing Language) queries.
+
+
+
+ Learn more
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Actions
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Actions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create panel
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No Operational Panels
+
+
+
+
+
+
+
+
+ Use operational panels to dive deeper into observability
+
+ using PPL queries and insightful visualizations
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create panel
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Add samples
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Panels Table Component renders panel table container 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+ Operational panels
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Panels
+
+ (
+ 4
+ )
+
+
+
+
+
+
+
+
+
+
+ Use Operational panels to create and view different visualizations on ingested observability data, using PPL (Piped Processing Language) queries.
+
+
+
+ Learn more
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Actions
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Actions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create panel
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Select all rows
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelPaddingSize="none"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sorting
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name
+
+
+
+
+
+
+ Click to sort in ascending order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Last updated
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Click to sort in ascending order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Created
+
+
+
+
+
+
+ Click to sort in ascending order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name
+
+
+
+
+
+
+
+ Last updated
+
+
+ 11/04/2021 06:10 PM
+
+
+
+
+
+
+ Created
+
+
+ 11/02/2021 07:26 PM
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name
+
+
+
+
+
+
+
+ Last updated
+
+
+ 11/03/2021 10:51 PM
+
+
+
+
+
+
+ Created
+
+
+ 11/02/2021 09:44 PM
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name
+
+
+
+
+
+
+
+ Last updated
+
+
+ 11/03/2021 10:37 PM
+
+
+
+
+
+
+ Created
+
+
+ 10/29/2021 10:15 PM
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name
+
+
+
+
+
+
+
+ Last updated
+
+
+ 11/03/2021 09:26 PM
+
+
+
+
+
+
+ Created
+
+
+ 11/03/2021 09:26 PM
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ :
+ 10
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Rows per page
+
+ :
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/custom_panels/__tests__/__snapshots__/custom_panel_view.test.tsx.snap b/public/components/custom_panels/__tests__/__snapshots__/custom_panel_view.test.tsx.snap
new file mode 100644
index 0000000000..2c020c56b8
--- /dev/null
+++ b/public/components/custom_panels/__tests__/__snapshots__/custom_panel_view.test.tsx.snap
@@ -0,0 +1,5052 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Panels View Component renders panel view container with visualizations 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Created on
+ Invalid date
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Edit
+
+
+
+
+
+
+
+
+
+
+
+ Panel actions
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Panel actions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Add visualization
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="addVisualizationContextMenu"
+ isOpen={false}
+ ownFocus={true}
+ panelPaddingSize="none"
+ >
+
+
+
+
+
+
+
+
+ Add Visualization
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="addVisualizationContextMenu"
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PPL
+
+ }
+ disabled={true}
+ fullWidth={true}
+ onChange={[Function]}
+ onKeyPress={[Function]}
+ placeholder="Use PPL 'where' clauses to add filters on all visualizations [where Carrier = 'OpenSearch-Air']"
+ value=""
+ >
+
+ PPL
+
+ }
+ fullWidth={true}
+ >
+
+
+
+
+
+
+
+
+
+ PPL
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ >
+
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="QuickSelectPopover"
+ isOpen={false}
+ ownFocus={true}
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
}
+ iconType={false}
+ isCustom={true}
+ startDateControl={
}
+ >
+
+
+ Last 30 minutes
+
+
+ Show dates
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Refresh
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Start by adding
+ your first visualization
+
+
+
+
+
+
+
+
+ Use PPL Queries to fetch & filter observability data and create
+ visualizations
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Add Visualization
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="addVisualizationContextMenu"
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ >
+<<<<<<< HEAD
+
+ Add visualization
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="addVisualizationContextMenu"
+ isOpen={false}
+ ownFocus={true}
+ panelPaddingSize="none"
+>>>>>>> 6b15239 (Add data test subj to app analytics (#704))
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Panels View Component renders panel view container with visualizations 2`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Created on
+ Invalid date
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Edit
+
+
+
+
+
+
+
+
+
+
+
+ Panel actions
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Panel actions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Add Visualization
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="addVisualizationContextMenu"
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PPL
+
+ }
+ disabled={true}
+ fullWidth={true}
+ onChange={[Function]}
+ onKeyPress={[Function]}
+ placeholder="Use PPL 'where' clauses to add filters on all visualizations [where Carrier = 'OpenSearch-Air']"
+ value=""
+ >
+
+ PPL
+
+ }
+ fullWidth={true}
+ >
+
+
+
+
+
+
+
+
+
+ PPL
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ >
+
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="QuickSelectPopover"
+ isOpen={false}
+ ownFocus={true}
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
}
+ iconType={false}
+ isCustom={true}
+ startDateControl={
}
+ >
+
+
+ Last 30 minutes
+
+
+ Show dates
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Refresh
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Start by adding
+ your first visualization
+
+
+
+
+
+
+
+
+ Use PPL Queries to fetch & filter observability data and create
+ visualizations
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Add Visualization
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="addVisualizationContextMenu"
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Panels View Component renders panel view container without visualizations 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Created on
+ Invalid date
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Edit
+
+
+
+
+
+
+
+
+
+
+
+ Panel actions
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Panel actions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Add visualization
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="addVisualizationContextMenu"
+ isOpen={false}
+ ownFocus={true}
+ panelPaddingSize="none"
+ >
+
+
+
+
+
+
+
+
+ Add Visualization
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="addVisualizationContextMenu"
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PPL
+
+ }
+ disabled={true}
+ fullWidth={true}
+ onChange={[Function]}
+ onKeyPress={[Function]}
+ placeholder="Use PPL 'where' clauses to add filters on all visualizations [where Carrier = 'OpenSearch-Air']"
+ value=""
+ >
+
+ PPL
+
+ }
+ fullWidth={true}
+ >
+
+
+
+
+
+
+
+
+
+ PPL
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ >
+
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="QuickSelectPopover"
+ isOpen={false}
+ ownFocus={true}
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
}
+ iconType={false}
+ isCustom={true}
+ startDateControl={
}
+ >
+
+
+ Last 30 minutes
+
+
+ Show dates
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Refresh
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Start by adding
+ your first visualization
+
+
+
+
+
+
+
+
+ Use PPL Queries to fetch & filter observability data and create
+ visualizations
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Add Visualization
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="addVisualizationContextMenu"
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ >
+<<<<<<< HEAD
+
+ Add visualization
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="addVisualizationContextMenu"
+ isOpen={false}
+ ownFocus={true}
+ panelPaddingSize="none"
+>>>>>>> 6b15239 (Add data test subj to app analytics (#704))
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/custom_panels/__tests__/custom_panel_table.test.tsx b/public/components/custom_panels/__tests__/custom_panel_table.test.tsx
new file mode 100644
index 0000000000..fb754bba30
--- /dev/null
+++ b/public/components/custom_panels/__tests__/custom_panel_table.test.tsx
@@ -0,0 +1,82 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { CustomPanelTable } from '../custom_panel_table';
+import { waitFor } from '@testing-library/react';
+import { panelBreadCrumbs, panelsData } from '../../../../test/panels_constants';
+import { CustomPanelListType } from '../../../../common/types/custom_panels';
+
+describe('Panels Table Component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders empty panel table container', async () => {
+ const loading = false;
+ const fetchCustomPanels = jest.fn();
+ const customPanelData: CustomPanelListType[] = [];
+ const createCustomPanel = jest.fn();
+ const setBreadcrumbs = jest.fn();
+ const parentBreadcrumb = panelBreadCrumbs;
+ const renameCustomPanel = jest.fn();
+ const cloneCustomPanel = jest.fn();
+ const deleteCustomPanelList = jest.fn();
+ const addSamplePanels = jest.fn();
+
+ const wrapper = mount(
+
+ );
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+
+ it('renders panel table container', async () => {
+ const loading = false;
+ const fetchCustomPanels = jest.fn();
+ const customPanelData: CustomPanelListType[] = panelsData.panels;
+ const createCustomPanel = jest.fn();
+ const setBreadcrumbs = jest.fn();
+ const parentBreadcrumb = panelBreadCrumbs;
+ const renameCustomPanel = jest.fn();
+ const cloneCustomPanel = jest.fn();
+ const deleteCustomPanelList = jest.fn();
+ const addSamplePanels = jest.fn();
+
+ const wrapper = mount(
+
+ );
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
diff --git a/public/components/custom_panels/__tests__/custom_panel_view.test.tsx b/public/components/custom_panels/__tests__/custom_panel_view.test.tsx
new file mode 100644
index 0000000000..3ad38f26d0
--- /dev/null
+++ b/public/components/custom_panels/__tests__/custom_panel_view.test.tsx
@@ -0,0 +1,134 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { CustomPanelView } from '../custom_panel_view';
+import { waitFor } from '@testing-library/react';
+import {
+ panelBreadCrumbs,
+ sampleEmptyPanel,
+ samplePanel,
+ samplePPLResponse,
+ sampleSavedVisualization,
+} from '../../../../test/panels_constants';
+import httpClientMock from '../../../../test/__mocks__/httpClientMock';
+import PPLService from '../../../../public/services/requests/ppl';
+import DSLService from '../../../../public/services/requests/dsl';
+import { coreStartMock } from '../../../../test/__mocks__/coreMocks';
+import { HttpResponse } from '../../../../../../src/core/public';
+
+describe.skip('Panels View Component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders panel view container without visualizations', async () => {
+ httpClientMock.get = jest.fn(() =>
+ Promise.resolve((sampleEmptyPanel as unknown) as HttpResponse)
+ );
+ const panelId = 'L8Sx53wBDp0rvEg3yoLb';
+ const http = httpClientMock;
+ const pplService = new PPLService(httpClientMock);
+ const dslService = new DSLService(httpClientMock);
+ const core = coreStartMock;
+ const parentBreadcrumbs = panelBreadCrumbs;
+ const start = 'now-30m';
+ const end = 'now';
+ const setStart = jest.fn();
+ const setEnd = jest.fn();
+ const renameCustomPanel = jest.fn();
+ const cloneCustomPanel = jest.fn();
+ const deleteCustomPanel = jest.fn();
+ const setToast = jest.fn();
+ const onEditClick = (savedVisId: string) => {
+ window.location.assign(`#/event_analytics/explorer/${savedVisId}`);
+ };
+
+ const wrapper = mount(
+
+ );
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+
+ it('renders panel view container with visualizations', async () => {
+ let counter = 0;
+ // Mocks two http get requests first for fetch panel
+ // Others for fetching visualizations in panel
+ httpClientMock.get = jest.fn(() => {
+ if (counter === 0) {
+ counter += 1;
+ return Promise.resolve((samplePanel as unknown) as HttpResponse);
+ } else return Promise.resolve((sampleSavedVisualization as unknown) as HttpResponse);
+ });
+
+ httpClientMock.post = jest.fn(() =>
+ Promise.resolve((samplePPLResponse as unknown) as HttpResponse)
+ );
+ const panelId = 'L8Sx53wBDp0rvEg3yoLb';
+ const http = httpClientMock;
+ const pplService = new PPLService(httpClientMock);
+ const dslService = new DSLService(httpClientMock);
+ const core = coreStartMock;
+ const parentBreadcrumbs = panelBreadCrumbs;
+ const start = 'now-30m';
+ const end = 'now';
+ const setStart = jest.fn();
+ const setEnd = jest.fn();
+ const renameCustomPanel = jest.fn();
+ const cloneCustomPanel = jest.fn();
+ const deleteCustomPanel = jest.fn();
+ const setToast = jest.fn();
+ const onEditClick = (savedVisId: string) => {
+ window.location.assign(`#/event_analytics/explorer/${savedVisId}`);
+ };
+
+ const wrapper = mount(
+
+ );
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
diff --git a/public/components/custom_panels/custom_panel_table.tsx b/public/components/custom_panels/custom_panel_table.tsx
new file mode 100644
index 0000000000..a2c7ce8d67
--- /dev/null
+++ b/public/components/custom_panels/custom_panel_table.tsx
@@ -0,0 +1,413 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable react-hooks/exhaustive-deps */
+
+import {
+ EuiBreadcrumb,
+ EuiButton,
+ EuiContextMenuItem,
+ EuiContextMenuPanel,
+ EuiFieldSearch,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiHorizontalRule,
+ EuiInMemoryTable,
+ EuiLink,
+ EuiOverlayMask,
+ EuiPage,
+ EuiPageBody,
+ EuiPageContent,
+ EuiPageContentHeader,
+ EuiPageContentHeaderSection,
+ EuiPageHeader,
+ EuiPageHeaderSection,
+ EuiPopover,
+ EuiSpacer,
+ EuiTableFieldDataColumnType,
+ EuiText,
+ EuiTitle,
+} from '@elastic/eui';
+import React, { ReactElement, useEffect, useState } from 'react';
+import moment from 'moment';
+import _ from 'lodash';
+import { ChromeBreadcrumb } from '../../../../../src/core/public';
+import {
+ CREATE_PANEL_MESSAGE,
+ CUSTOM_PANELS_DOCUMENTATION_URL,
+} from '../../../common/constants/custom_panels';
+import { UI_DATE_FORMAT } from '../../../common/constants/shared';
+import { getCustomModal } from './helpers/modal_containers';
+import { CustomPanelListType } from '../../../common/types/custom_panels';
+import { getSampleDataModal } from '../common/helpers/add_sample_modal';
+import { pageStyles } from '../../../common/constants/shared';
+import { DeleteModal } from '../common/helpers/delete_modal';
+
+/*
+ * "CustomPanelTable" module, used to view all the saved panels
+ *
+ * Props taken in as params are:
+ * loading: loader bool for the table
+ * fetchCustomPanels: fetch panels function
+ * customPanels: List of panels available
+ * createCustomPanel: create panel function
+ * setBreadcrumbs: setter for breadcrumbs on top panel
+ * parentBreadcrumb: parent breadcrumb
+ * renameCustomPanel: rename function for the panel
+ * cloneCustomPanel: clone function for the panel
+ * deleteCustomPanelList: delete function for the panels
+ */
+
+interface Props {
+ loading: boolean;
+ fetchCustomPanels: () => void;
+ customPanels: CustomPanelListType[];
+ createCustomPanel: (newCustomPanelName: string) => void;
+ setBreadcrumbs: (newBreadcrumbs: ChromeBreadcrumb[]) => void;
+ parentBreadcrumbs: EuiBreadcrumb[];
+ renameCustomPanel: (newCustomPanelName: string, customPanelId: string) => void;
+ cloneCustomPanel: (newCustomPanelName: string, customPanelId: string) => void;
+ deleteCustomPanelList: (customPanelIdList: string[], toastMessage: string) => any;
+ addSamplePanels: () => void;
+}
+
+export const CustomPanelTable = ({
+ loading,
+ fetchCustomPanels,
+ customPanels,
+ createCustomPanel,
+ setBreadcrumbs,
+ parentBreadcrumbs,
+ renameCustomPanel,
+ cloneCustomPanel,
+ deleteCustomPanelList,
+ addSamplePanels,
+}: Props) => {
+ const [isModalVisible, setIsModalVisible] = useState(false); // Modal Toggle
+ const [modalLayout, setModalLayout] = useState( ); // Modal Layout
+ const [isActionsPopoverOpen, setIsActionsPopoverOpen] = useState(false);
+ const [selectedCustomPanels, setselectedCustomPanels] = useState([]);
+ const [searchQuery, setSearchQuery] = useState('');
+
+ useEffect(() => {
+ setBreadcrumbs(parentBreadcrumbs);
+ fetchCustomPanels();
+ }, []);
+
+ const closeModal = () => {
+ setIsModalVisible(false);
+ };
+
+ const showModal = () => {
+ setIsModalVisible(true);
+ };
+
+ const onCreate = async (newCustomPanelName: string) => {
+ createCustomPanel(newCustomPanelName);
+ closeModal();
+ };
+
+ const onRename = async (newCustomPanelName: string) => {
+ renameCustomPanel(newCustomPanelName, selectedCustomPanels[0].id);
+ closeModal();
+ };
+
+ const onClone = async (newName: string) => {
+ cloneCustomPanel(newName, selectedCustomPanels[0].id);
+ closeModal();
+ };
+
+ const onDelete = async () => {
+ const toastMessage = `Custom Panels ${
+ selectedCustomPanels.length > 1 ? 's' : ' ' + selectedCustomPanels[0].name
+ } successfully deleted!`;
+ const PanelList = selectedCustomPanels.map((panel) => panel.id);
+ deleteCustomPanelList(PanelList, toastMessage);
+ closeModal();
+ };
+
+ const createPanel = () => {
+ setModalLayout(
+ getCustomModal(
+ onCreate,
+ closeModal,
+ 'Name',
+ 'Create operational panel',
+ 'Cancel',
+ 'Create',
+ undefined,
+ CREATE_PANEL_MESSAGE
+ )
+ );
+ showModal();
+ };
+
+ const renamePanel = () => {
+ setModalLayout(
+ getCustomModal(
+ onRename,
+ closeModal,
+ 'Name',
+ 'Rename Panel',
+ 'Cancel',
+ 'Rename',
+ selectedCustomPanels[0].name,
+ CREATE_PANEL_MESSAGE
+ )
+ );
+ showModal();
+ };
+
+ const clonePanel = () => {
+ setModalLayout(
+ getCustomModal(
+ onClone,
+ closeModal,
+ 'Name',
+ 'Duplicate Panel',
+ 'Cancel',
+ 'Duplicate',
+ selectedCustomPanels[0].name + ' (copy)',
+ CREATE_PANEL_MESSAGE
+ )
+ );
+ showModal();
+ };
+
+ const deletePanel = () => {
+ const customPanelString = `operational panel${selectedCustomPanels.length > 1 ? 's' : ''}`;
+ setModalLayout(
+
+ );
+ showModal();
+ };
+
+ const addSampledata = async () => {
+ setModalLayout(
+ getSampleDataModal(closeModal, async () => {
+ closeModal();
+ await addSamplePanels();
+ })
+ );
+ showModal();
+ };
+
+ const popoverButton = (
+ setIsActionsPopoverOpen(!isActionsPopoverOpen)}
+ >
+ Actions
+
+ );
+
+ const popoverItems: ReactElement[] = [
+ {
+ setIsActionsPopoverOpen(false);
+ renamePanel();
+ }}
+ >
+ Rename
+ ,
+ {
+ setIsActionsPopoverOpen(false);
+ clonePanel();
+ }}
+ >
+ Duplicate
+ ,
+ {
+ setIsActionsPopoverOpen(false);
+ deletePanel();
+ }}
+ >
+ Delete
+ ,
+ {
+ setIsActionsPopoverOpen(false);
+ addSampledata();
+ }}
+ >
+ Add samples
+ ,
+ ];
+
+ const tableColumns = [
+ {
+ field: 'name',
+ name: 'Name',
+ sortable: true,
+ truncateText: true,
+ render: (value, record) => (
+
+ {_.truncate(value, { length: 100 })}
+
+ ),
+ },
+ {
+ field: 'dateModified',
+ name: 'Last updated',
+ sortable: true,
+ render: (value) => moment(new Date(value)).format(UI_DATE_FORMAT),
+ },
+ {
+ field: 'dateCreated',
+ name: 'Created',
+ sortable: true,
+ render: (value) => moment(new Date(value)).format(UI_DATE_FORMAT),
+ },
+ ] as Array>;
+
+ return (
+
+
+
+
+
+
+ Operational panels
+
+
+
+
+
+
+
+
+ Panels
+ ({customPanels.length})
+
+
+
+
+ Use Operational panels to create and view different visualizations on ingested
+ observability data, using PPL (Piped Processing Language) queries.{' '}
+
+ Learn more
+
+
+
+
+
+
+ setIsActionsPopoverOpen(false)}
+ >
+
+
+
+
+ createPanel()}
+ data-test-subj="customPanels__createNewPanels"
+ >
+ Create panel
+
+
+
+
+
+
+ {customPanels.length > 0 ? (
+ <>
+ setSearchQuery(e.target.value)}
+ />
+
+
+ customPanel.name.toLowerCase().includes(searchQuery.toLowerCase())
+ )
+ : customPanels
+ }
+ itemId="id"
+ columns={tableColumns}
+ tableLayout="auto"
+ pagination={{
+ initialPageSize: 10,
+ pageSizeOptions: [8, 10, 13],
+ }}
+ sorting={{
+ sort: {
+ field: 'dateModified',
+ direction: 'desc',
+ },
+ }}
+ allowNeutralSort={false}
+ isSelectable={true}
+ selection={{
+ onSelectionChange: (items) => setselectedCustomPanels(items),
+ }}
+ />
+ >
+ ) : (
+ <>
+
+
+ No Operational Panels
+
+
+ Use operational panels to dive deeper into observability
+
+ using PPL queries and insightful visualizations
+
+
+
+
+
+ createPanel()}
+ >
+ Create panel
+
+
+
+ addSampledata()}>
+ Add samples
+
+
+
+
+ >
+ )}
+
+
+
+ {isModalVisible && modalLayout}
+
+ );
+};
diff --git a/public/components/custom_panels/custom_panel_view.tsx b/public/components/custom_panels/custom_panel_view.tsx
new file mode 100644
index 0000000000..be6ab6ae90
--- /dev/null
+++ b/public/components/custom_panels/custom_panel_view.tsx
@@ -0,0 +1,672 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable no-console */
+/* eslint-disable react-hooks/exhaustive-deps */
+
+import {
+ EuiBreadcrumb,
+ EuiButton,
+ EuiContextMenu,
+ EuiContextMenuPanelDescriptor,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiLink,
+ EuiOverlayMask,
+ EuiPage,
+ EuiPageBody,
+ EuiPageContentBody,
+ EuiPageHeader,
+ EuiPageHeaderSection,
+ EuiPopover,
+ EuiSpacer,
+ EuiSuperDatePicker,
+ EuiTitle,
+ OnTimeChangeProps,
+ ShortDate,
+} from '@elastic/eui';
+import { last } from 'lodash';
+import React, { useEffect, useState } from 'react';
+import { DurationRange } from '@elastic/eui/src/components/date_picker/types';
+import moment from 'moment';
+import DSLService from '../../services/requests/dsl';
+import { CoreStart } from '../../../../../src/core/public';
+import { EmptyPanelView } from './panel_modules/empty_panel';
+import {
+ CREATE_PANEL_MESSAGE,
+ CUSTOM_PANELS_API_PREFIX,
+} from '../../../common/constants/custom_panels';
+import { SavedVisualizationType, VisualizationType } from '../../../common/types/custom_panels';
+import { PanelGrid } from './panel_modules/panel_grid';
+import { getCustomModal } from './helpers/modal_containers';
+import PPLService from '../../services/requests/ppl';
+import {
+ isDateValid,
+ convertDateTime,
+ onTimeChange,
+ isPPLFilterValid,
+ fetchVisualizationById,
+} from './helpers/utils';
+import { UI_DATE_FORMAT } from '../../../common/constants/shared';
+import { VisaulizationFlyout } from './panel_modules/visualization_flyout';
+import { uiSettingsService } from '../../../common/utils';
+import { PPLReferenceFlyout } from '../common/helpers';
+import { Autocomplete } from '../common/search/autocomplete';
+import {
+ parseGetSuggestions,
+ onItemSelect,
+ parseForIndices,
+} from '../common/search/autocomplete_logic';
+import { AddVisualizationPopover } from './helpers/add_visualization_popover';
+import { DeleteModal } from '../common/helpers/delete_modal';
+
+/*
+ * "CustomPanelsView" module used to render an Operational Panel
+ *
+ * Props taken in as params are:
+ * panelId: Name of the panel opened
+ * page: Page where component is called
+ * http: http core service
+ * pplService: ppl requestor service
+ * dslService: dsl requestor service
+ * chrome: chrome core service
+ * parentBreadcrumb: parent breadcrumb
+ * renameCustomPanel: Rename function for the panel
+ * deleteCustomPanel: Delete function for the panel
+ * cloneCustomPanel: Clone function for the panel
+ * setToast: create Toast function
+ * onEditClick: Edit function for visualization
+ * startTime: Starting time
+ * endTime: Ending time
+ * setStartTime: Function to change start time
+ * setEndTime: Function to change end time
+ * childBreadcrumbs: Breadcrumbs to extend
+ * appId: id of application that panel belongs to
+ * onAddClick: Function for add button instead of add visualization popover
+ */
+
+interface CustomPanelViewProps {
+ panelId: string;
+ page: 'app' | 'operationalPanels';
+ http: CoreStart['http'];
+ pplService: PPLService;
+ dslService: DSLService;
+ chrome: CoreStart['chrome'];
+ parentBreadcrumbs: EuiBreadcrumb[];
+ renameCustomPanel: (editedCustomPanelName: string, editedCustomPanelId: string) => Promise;
+ deleteCustomPanel: (customPanelId: string, customPanelName: string) => Promise;
+ cloneCustomPanel: (clonedCustomPanelName: string, clonedCustomPanelId: string) => Promise;
+ setToast: (
+ title: string,
+ color?: string,
+ text?: React.ReactChild | undefined,
+ side?: string | undefined
+ ) => void;
+ onEditClick: (savedVisualizationId: string) => any;
+ startTime: string;
+ endTime: string;
+ setStartTime: any;
+ setEndTime: any;
+ childBreadcrumbs?: EuiBreadcrumb[];
+ appId?: string;
+ updateAvailabilityVizId?: any;
+ onAddClick?: any;
+}
+
+export const CustomPanelView = (props: CustomPanelViewProps) => {
+ const {
+ panelId,
+ page,
+ appId,
+ http,
+ pplService,
+ dslService,
+ chrome,
+ parentBreadcrumbs,
+ childBreadcrumbs,
+ startTime,
+ endTime,
+ setStartTime,
+ setEndTime,
+ updateAvailabilityVizId,
+ renameCustomPanel,
+ deleteCustomPanel,
+ cloneCustomPanel,
+ setToast,
+ onEditClick,
+ onAddClick,
+ } = props;
+ const [openPanelName, setOpenPanelName] = useState('');
+ const [panelCreatedTime, setPanelCreatedTime] = useState('');
+ const [pplFilterValue, setPPLFilterValue] = useState('');
+ const [baseQuery, setBaseQuery] = useState('');
+ const [onRefresh, setOnRefresh] = useState(false);
+
+ const [inputDisabled, setInputDisabled] = useState(true);
+ const [addVizDisabled, setAddVizDisabled] = useState(false);
+ const [editDisabled, setEditDisabled] = useState(false);
+ const [dateDisabled, setDateDisabled] = useState(false);
+ const [panelVisualizations, setPanelVisualizations] = useState([]);
+ const [editMode, setEditMode] = useState(false);
+ const [isModalVisible, setIsModalVisible] = useState(false); // Modal Toggle
+ const [modalLayout, setModalLayout] = useState( ); // Modal Layout
+ const [isFlyoutVisible, setIsFlyoutVisible] = useState(false); // Add Visualization Flyout
+ const [isFlyoutReplacement, setisFlyoutReplacement] = useState(false);
+ const [replaceVisualizationId, setReplaceVisualizationId] = useState('');
+ const [panelsMenuPopover, setPanelsMenuPopover] = useState(false);
+ const [editActionType, setEditActionType] = useState('');
+ const [isHelpFlyoutVisible, setHelpIsFlyoutVisible] = useState(false);
+
+ const appPanel = page === 'app';
+
+ const closeHelpFlyout = () => {
+ setAddVizDisabled(false);
+ setHelpIsFlyoutVisible(false);
+ };
+
+ const showHelpFlyout = () => {
+ setAddVizDisabled(true);
+ setHelpIsFlyoutVisible(true);
+ };
+
+ // DateTimePicker States
+ const [recentlyUsedRanges, setRecentlyUsedRanges] = useState([]);
+
+ // Fetch Panel by id
+ const fetchCustomPanel = async () => {
+ return http
+ .get(`${CUSTOM_PANELS_API_PREFIX}/panels/${panelId}`)
+ .then((res) => {
+ setOpenPanelName(res.operationalPanel.name);
+ setPanelCreatedTime(res.createdTimeMs);
+ setPPLFilterValue(res.operationalPanel.queryFilter.query);
+ setStartTime(startTime ? startTime : res.operationalPanel.timeRange.from);
+ setEndTime(endTime ? endTime : res.operationalPanel.timeRange.to);
+ setPanelVisualizations(res.operationalPanel.visualizations);
+ })
+ .catch((err) => {
+ console.error('Issue in fetching the operational panels', err);
+ });
+ };
+
+ const handleQueryChange = (newQuery: string) => {
+ setPPLFilterValue(newQuery);
+ };
+
+ const closeModal = () => {
+ setIsModalVisible(false);
+ };
+
+ const showModal = () => {
+ setIsModalVisible(true);
+ };
+
+ const onDatePickerChange = (timeProps: OnTimeChangeProps) => {
+ onTimeChange(
+ timeProps.start,
+ timeProps.end,
+ recentlyUsedRanges,
+ setRecentlyUsedRanges,
+ setStartTime,
+ setEndTime
+ );
+ onRefreshFilters(timeProps.start, timeProps.end);
+ };
+
+ const onDelete = async () => {
+ deleteCustomPanel(panelId, openPanelName).then((res) => {
+ setTimeout(() => {
+ window.location.assign(`${last(parentBreadcrumbs)!.href}`);
+ }, 1000);
+ });
+ closeModal();
+ };
+
+ const deletePanel = () => {
+ setModalLayout(
+
+ );
+ showModal();
+ };
+
+ const onRename = async (newCustomPanelName: string) => {
+ renameCustomPanel(newCustomPanelName, panelId).then(() => {
+ setOpenPanelName(newCustomPanelName);
+ });
+ closeModal();
+ };
+
+ const renamePanel = () => {
+ setModalLayout(
+ getCustomModal(
+ onRename,
+ closeModal,
+ 'Name',
+ 'Rename Panel',
+ 'Cancel',
+ 'Rename',
+ openPanelName,
+ CREATE_PANEL_MESSAGE
+ )
+ );
+ showModal();
+ };
+
+ const onClone = async (newCustomPanelName: string) => {
+ cloneCustomPanel(newCustomPanelName, panelId).then((id: string) => {
+ window.location.assign(`${last(parentBreadcrumbs)!.href}${id}`);
+ });
+ closeModal();
+ };
+
+ const clonePanel = () => {
+ setModalLayout(
+ getCustomModal(
+ onClone,
+ closeModal,
+ 'Name',
+ 'Duplicate Panel',
+ 'Cancel',
+ 'Duplicate',
+ openPanelName + ' (copy)',
+ CREATE_PANEL_MESSAGE
+ )
+ );
+ showModal();
+ };
+
+ // toggle between panel edit mode
+ const editPanel = (editType: string) => {
+ setEditMode(!editMode);
+ if (editType === 'cancel') fetchCustomPanel();
+ setEditActionType(editType);
+ };
+
+ const closeFlyout = () => {
+ setIsFlyoutVisible(false);
+ setAddVizDisabled(false);
+ checkDisabledInputs();
+ };
+
+ const showFlyout = (isReplacement?: boolean, replaceVizId?: string) => {
+ setisFlyoutReplacement(isReplacement);
+ setReplaceVisualizationId(replaceVizId);
+ setIsFlyoutVisible(true);
+ setAddVizDisabled(true);
+ setInputDisabled(true);
+ };
+
+ const checkDisabledInputs = () => {
+ // When not in edit mode and panel has no visualizations
+ if (panelVisualizations.length === 0 && !editMode) {
+ setEditDisabled(true);
+ setInputDisabled(true);
+ setAddVizDisabled(false);
+ setDateDisabled(false);
+ }
+
+ // When panel has visualizations
+ if (panelVisualizations.length > 0) {
+ setEditDisabled(false);
+ setInputDisabled(false);
+ setAddVizDisabled(false);
+ setDateDisabled(false);
+ }
+
+ // When in edit mode
+ if (editMode) {
+ setEditDisabled(false);
+ setInputDisabled(true);
+ setAddVizDisabled(true);
+ setDateDisabled(true);
+ }
+ };
+
+ const buildBaseQuery = async () => {
+ const indices: string[] = [];
+ for (let i = 0; i < panelVisualizations.length; i++) {
+ const visualizationId = panelVisualizations[i].savedVisualizationId;
+ // TODO: create route to get list of visualizations in one call
+ const visData: SavedVisualizationType = await fetchVisualizationById(
+ http,
+ visualizationId,
+ (value: string) => setToast(value, 'danger')
+ );
+ const moreIndices = parseForIndices(visData.query);
+ for (let j = 0; j < moreIndices.length; j++) {
+ if (!indices.includes(moreIndices[j])) {
+ indices.push(moreIndices[j]);
+ }
+ }
+ }
+ setBaseQuery('source = ' + indices.join(', '));
+ return;
+ };
+
+ const onRefreshFilters = (start: ShortDate, end: ShortDate) => {
+ if (!isDateValid(convertDateTime(start), convertDateTime(end, false), setToast)) {
+ return;
+ }
+
+ if (!isPPLFilterValid(pplFilterValue, setToast)) {
+ return;
+ }
+
+ const panelFilterBody = {
+ panelId,
+ query: pplFilterValue,
+ language: 'ppl',
+ to: end,
+ from: start,
+ };
+
+ http
+ .post(`${CUSTOM_PANELS_API_PREFIX}/panels/filter`, {
+ body: JSON.stringify(panelFilterBody),
+ })
+ .then((res) => {
+ setOnRefresh(!onRefresh);
+ })
+ .catch((err) => {
+ setToast('Error is adding filters to the operational panel', 'danger');
+ console.error(err.body.message);
+ });
+ };
+
+ const cloneVisualization = (visualzationTitle: string, savedVisualizationId: string) => {
+ http
+ .post(`${CUSTOM_PANELS_API_PREFIX}/visualizations`, {
+ body: JSON.stringify({
+ panelId,
+ savedVisualizationId,
+ }),
+ })
+ .then(async (res) => {
+ setPanelVisualizations(res.visualizations);
+ setToast(`Visualization ${visualzationTitle} successfully added!`, 'success');
+ })
+ .catch((err) => {
+ setToast(`Error in adding ${visualzationTitle} visualization to the panel`, 'danger');
+ console.error(err);
+ });
+ };
+
+ const cancelButton = (
+ editPanel('cancel')}>
+ Cancel
+
+ );
+
+ const saveButton = (
+ editPanel('save')}>
+ Save
+
+ );
+
+ const editButton = (
+ editPanel('edit')} disabled={editDisabled}>
+ Edit
+
+ );
+
+ const addButton = (
+
+ Add
+
+ );
+
+ // Panel Actions Button
+ const panelActionsButton = (
+ setPanelsMenuPopover(true)}
+ disabled={addVizDisabled}
+ >
+ Panel actions
+
+ );
+
+ let flyout;
+ if (isFlyoutVisible) {
+ flyout = (
+
+ );
+ }
+
+ let helpFlyout;
+ if (isHelpFlyoutVisible) {
+ helpFlyout = ;
+ }
+
+ const panelActionsMenu: EuiContextMenuPanelDescriptor[] = [
+ {
+ id: 0,
+ title: 'Panel actions',
+ items: [
+ {
+ name: 'Reload panel',
+ onClick: () => {
+ setPanelsMenuPopover(false);
+ fetchCustomPanel();
+ },
+ },
+ {
+ name: 'Rename panel',
+ onClick: () => {
+ setPanelsMenuPopover(false);
+ renamePanel();
+ },
+ },
+ {
+ name: 'Duplicate panel',
+ onClick: () => {
+ setPanelsMenuPopover(false);
+ clonePanel();
+ },
+ },
+ {
+ name: 'Delete panel',
+ onClick: () => {
+ setPanelsMenuPopover(false);
+ deletePanel();
+ },
+ },
+ ],
+ },
+ ];
+
+ // Fetch the custom panel on Initial Mount
+ useEffect(() => {
+ fetchCustomPanel();
+ }, [panelId]);
+
+ // Toggle input type (disabled or not disabled)
+ // Disabled when there no visualizations in panels or when the panel is in edit mode
+ useEffect(() => {
+ checkDisabledInputs();
+ }, [editMode]);
+
+ // Build base query with all of the indices included in the current visualizations
+ useEffect(() => {
+ checkDisabledInputs();
+ buildBaseQuery();
+ }, [panelVisualizations]);
+
+ // Edit the breadcrumb when panel name changes
+ useEffect(() => {
+ let newBreadcrumb;
+ if (childBreadcrumbs) {
+ newBreadcrumb = childBreadcrumbs;
+ } else {
+ newBreadcrumb = [
+ {
+ text: openPanelName,
+ href: `${last(parentBreadcrumbs)!.href}${panelId}`,
+ },
+ ];
+ }
+ chrome.setBreadcrumbs([...parentBreadcrumbs, ...newBreadcrumb]);
+ }, [panelId, openPanelName]);
+
+ return (
+
+
+
+
+ {appPanel || (
+ <>
+
+
+ {openPanelName}
+
+
+
+
+ Created on {moment(panelCreatedTime).format(UI_DATE_FORMAT)}
+
+
+
+ {editMode ? (
+ <>
+ {cancelButton}
+ {saveButton}
+ >
+ ) : (
+ {editButton}
+ )}
+
+ setPanelsMenuPopover(false)}
+ >
+
+
+
+
+
+
+
+
+ >
+ )}
+
+
+
+
+ onRefreshFilters(startTime, endTime)}
+ dslService={dslService}
+ getSuggestions={parseGetSuggestions}
+ onItemSelect={onItemSelect}
+ isDisabled={inputDisabled}
+ tabId={'panels-filter'}
+ placeholder={
+ "Use PPL 'where' clauses to add filters on all visualizations [where Carrier = 'OpenSearch-Air']"
+ }
+ possibleCommands={[{ label: 'where' }]}
+ append={
+
+ PPL
+
+ }
+ />
+
+
+
+
+ {appPanel && (
+ <>
+ {editMode ? (
+ <>
+ {cancelButton}
+ {saveButton}
+ >
+ ) : (
+ {editButton}
+ )}
+ {addButton}
+ >
+ )}
+
+
+ {panelVisualizations.length === 0 && (
+
+ )}
+
+
+
+
+ {isModalVisible && modalLayout}
+ {flyout}
+ {helpFlyout}
+
+ );
+};
diff --git a/public/components/custom_panels/helpers/__tests__/__snapshots__/custom_input_model.test.tsx.snap b/public/components/custom_panels/helpers/__tests__/__snapshots__/custom_input_model.test.tsx.snap
new file mode 100644
index 0000000000..bbc895db33
--- /dev/null
+++ b/public/components/custom_panels/helpers/__tests__/__snapshots__/custom_input_model.test.tsx.snap
@@ -0,0 +1,100 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Custom Input Model component renders custom input modal with multiple arguments 1`] = `
+
+
+
+
+ Input test
+
+
+
+
+
+
+
+
+
+
+
+ btn test
+
+
+ btn test 2
+
+
+
+
+`;
+
+exports[`Custom Input Model component renders custom input modal with single argument 1`] = `
+
+
+
+
+ Input test
+
+
+
+
+
+
+
+
+
+
+
+ btn test
+
+
+ btn test 2
+
+
+
+
+`;
diff --git a/public/components/custom_panels/helpers/__tests__/__snapshots__/modal_container.test.tsx.snap b/public/components/custom_panels/helpers/__tests__/__snapshots__/modal_container.test.tsx.snap
new file mode 100644
index 0000000000..3d92156d3c
--- /dev/null
+++ b/public/components/custom_panels/helpers/__tests__/__snapshots__/modal_container.test.tsx.snap
@@ -0,0 +1,64 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Modal Container component renders DeleteModal component 1`] = `
+
+
+
+
+ Test Title
+
+
+
+
+ Test Message
+
+
+ The action cannot be undone.
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+ Delete
+
+
+
+
+`;
+
+exports[`Modal Container component renders getCloneModal function 1`] = `""`;
+
+exports[`Modal Container component renders getDeleteModal function 1`] = `""`;
diff --git a/public/components/custom_panels/helpers/__tests__/__snapshots__/utils.test.tsx.snap b/public/components/custom_panels/helpers/__tests__/__snapshots__/utils.test.tsx.snap
new file mode 100644
index 0000000000..039fcd1b73
--- /dev/null
+++ b/public/components/custom_panels/helpers/__tests__/__snapshots__/utils.test.tsx.snap
@@ -0,0 +1,3152 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Utils helper functions renders displayVisualization function 1`] = `
+
+
+
+
+
+
+
+`;
+
+exports[`Utils helper functions renders displayVisualization function 2`] = `
+
+`;
+
+exports[`Utils helper functions renders displayVisualization function 3`] = `
+
+`;
+
+exports[`Utils helper functions renders displayVisualization function 3`] = `
+
+`;
+
+exports[`Utils helper functions renders displayVisualization function 4`] = `
+
+`;
diff --git a/public/components/custom_panels/helpers/__tests__/custom_input_model.test.tsx b/public/components/custom_panels/helpers/__tests__/custom_input_model.test.tsx
new file mode 100644
index 0000000000..11659128cc
--- /dev/null
+++ b/public/components/custom_panels/helpers/__tests__/custom_input_model.test.tsx
@@ -0,0 +1,61 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, shallow } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { CustomInputModal } from '../custom_input_modal';
+
+describe('Custom Input Model component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders custom input modal with single argument', () => {
+ const runModal = jest.fn;
+ const closeModal = jest.fn();
+ const labelTxt = 'test label';
+ const titletxt = 'Input test';
+ const btn1txt = 'btn test';
+ const btn2txt = 'btn test 2';
+ const wrapper = shallow(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it('renders custom input modal with multiple arguments', () => {
+ const runModal = jest.fn;
+ const closeModal = jest.fn();
+ const labelTxt = 'test label';
+ const titletxt = 'Input test';
+ const btn1txt = 'btn test';
+ const btn2txt = 'btn test 2';
+ const openPanelName = 'Test Panel';
+ const helpText = 'Help Text';
+ const optionalArgs = ['option1', 'option2', 'option3'];
+ const wrapper = shallow(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+});
diff --git a/public/components/custom_panels/helpers/__tests__/modal_container.test.tsx b/public/components/custom_panels/helpers/__tests__/modal_container.test.tsx
new file mode 100644
index 0000000000..0fb8c3bb0e
--- /dev/null
+++ b/public/components/custom_panels/helpers/__tests__/modal_container.test.tsx
@@ -0,0 +1,42 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, shallow } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import { DeleteModal } from '../../../common/helpers/delete_modal';
+import React from 'react';
+import { getCloneModal, getDeleteModal } from '../modal_containers';
+
+describe('Modal Container component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders getCloneModal function', () => {
+ const onCancel = jest.fn();
+ const onConfirm = jest.fn();
+ const wrapper = shallow(getCloneModal(onCancel, onConfirm));
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it('renders getDeleteModal function', () => {
+ const onCancel = jest.fn();
+ const onConfirm = jest.fn();
+ const title = 'Test Title';
+ const message = 'Test Message';
+ const confirmMessage = 'Confirm Message';
+ const wrapper = shallow(getDeleteModal(onCancel, onConfirm, title, message, confirmMessage));
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it('renders DeleteModal component', () => {
+ const onCancel = jest.fn();
+ const onConfirm = jest.fn();
+ const title = 'Test Title';
+ const message = 'Test Message';
+ const wrapper = shallow(
+
+ );
+ expect(wrapper).toMatchSnapshot();
+ });
+});
diff --git a/public/components/custom_panels/helpers/__tests__/utils.test.tsx b/public/components/custom_panels/helpers/__tests__/utils.test.tsx
new file mode 100644
index 0000000000..0e92e37e78
--- /dev/null
+++ b/public/components/custom_panels/helpers/__tests__/utils.test.tsx
@@ -0,0 +1,122 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import moment from 'moment';
+import { DurationRange } from '@elastic/eui/src/components/date_picker/types';
+
+import {
+ isNameValid,
+ convertDateTime,
+ mergeLayoutAndVisualizations,
+ onTimeChange,
+ isDateValid,
+ isPPLFilterValid,
+ displayVisualization,
+} from '../utils';
+import {
+ sampleLayout,
+ sampleMergedVisualizations,
+ samplePanelVisualizations,
+ samplePPLEmptyResponse,
+ samplePPLResponse,
+ sampleSavedVisualization,
+} from '../../../../../test/panels_constants';
+import { PPL_DATE_FORMAT } from '../../../../../common/constants/shared';
+import React from 'react';
+
+describe.skip('Utils helper functions', () => {
+ configure({ adapter: new Adapter() });
+
+ it('validates isNameValid function', () => {
+ expect(isNameValid('Lorem ipsum dolor sit amet, consectetur adipiscing elit,')).toBe(false);
+ expect(isNameValid('Lorem ipsum dolor sit amet, consectetur adipiscin')).toBe(true);
+ });
+
+ it('validates convertDateTime function', () => {
+ expect(convertDateTime('2022-01-30T18:44:40.577Z')).toBe(
+ moment('2022-01-30T18:44:40.577Z').format(PPL_DATE_FORMAT)
+ );
+ expect(convertDateTime('2022-02-25T19:18:33.075Z', true)).toBe(
+ moment('2022-02-25T19:18:33.075Z').format(PPL_DATE_FORMAT)
+ );
+ });
+
+ it('validates mergeLayoutAndVisualizations function', () => {
+ const setState = jest.fn();
+ mergeLayoutAndVisualizations(sampleLayout, samplePanelVisualizations, setState);
+ expect(setState).toHaveBeenCalledWith(sampleMergedVisualizations);
+ });
+
+ it('validates onTimeChange function', () => {
+ const setRecentlyUsedRanges = jest.fn((x) => x);
+ const setStart = jest.fn();
+ const setEnd = jest.fn();
+ const recentlyUsedRanges: DurationRange[] = [];
+ onTimeChange(
+ '2022-01-30T18:44:40.577Z',
+ '2022-02-25T19:18:33.075Z',
+ recentlyUsedRanges,
+ setRecentlyUsedRanges,
+ setStart,
+ setEnd
+ );
+ expect(setRecentlyUsedRanges).toHaveBeenCalledWith([
+ { start: '2022-01-30T18:44:40.577Z', end: '2022-02-25T19:18:33.075Z' },
+ ]);
+ expect(setStart).toHaveBeenCalledWith('2022-01-30T18:44:40.577Z');
+ expect(setEnd).toHaveBeenCalledWith('2022-02-25T19:18:33.075Z');
+ });
+
+ it('validates isDateValid function', () => {
+ const setToast = jest.fn();
+ expect(
+ isDateValid(
+ convertDateTime('2022-01-30T18:44:40.577Z'),
+ convertDateTime('2022-02-25T19:18:33.075Z', false),
+ setToast
+ )
+ ).toBe(true);
+ expect(
+ isDateValid(
+ convertDateTime('2022-01-30T18:44:40.577Z'),
+ convertDateTime('2022-01-30T18:44:40.577Z', false),
+ setToast
+ )
+ ).toBe(true);
+ expect(
+ isDateValid(
+ convertDateTime('2022-02-25T19:18:33.075Z'),
+ convertDateTime('2022-01-30T18:44:40.577Z', false),
+ setToast
+ )
+ ).toBe(false);
+ });
+
+ it('validates isPPLFilterValid function', () => {
+ const setToast = jest.fn();
+ expect(isPPLFilterValid(sampleSavedVisualization.visualization.query, setToast)).toBe(false);
+ expect(isPPLFilterValid("where Carrier = 'OpenSearch-Air'", setToast)).toBe(true);
+ });
+
+ it('renders displayVisualization function', () => {
+ const wrapper1 = mount({displayVisualization(samplePPLResponse, 'bar', false)}
);
+ expect(wrapper1).toMatchSnapshot();
+
+ const wrapper2 = mount({displayVisualization(samplePPLResponse, 'line', true)}
);
+ expect(wrapper2).toMatchSnapshot();
+
+ const wrapper3 = mount(
+ {displayVisualization(samplePPLResponse, 'horizontal_bar', false)}
+ );
+ expect(wrapper3).toMatchSnapshot();
+
+ const wrapper4 = mount(
+ {displayVisualization(samplePPLEmptyResponse, 'horizontal_bar', true)}
+ );
+ expect(wrapper4).toMatchSnapshot();
+ });
+});
diff --git a/public/components/custom_panels/helpers/add_visualization_popover.tsx b/public/components/custom_panels/helpers/add_visualization_popover.tsx
new file mode 100644
index 0000000000..b59b1c43d7
--- /dev/null
+++ b/public/components/custom_panels/helpers/add_visualization_popover.tsx
@@ -0,0 +1,82 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { EuiButton, EuiContextMenu, EuiPopover } from '@elastic/eui';
+import React, { useState } from 'react';
+
+interface AddVisualizationPopoverProps {
+ showFlyout: (isReplacement?: boolean, replaceVizId?: string) => void;
+ addVizDisabled: boolean;
+}
+
+export const AddVisualizationPopover = ({
+ addVizDisabled,
+ showFlyout,
+}: AddVisualizationPopoverProps) => {
+ const [isVizPopoverOpen, setVizPopoverOpen] = useState(false); // Add Visualization Popover
+
+ const onPopoverClick = () => {
+ setVizPopoverOpen(!isVizPopoverOpen);
+ };
+
+ const closeVizPopover = () => {
+ setVizPopoverOpen(false);
+ };
+
+ const advancedVisualization = () => {
+ closeVizPopover();
+ window.location.assign('#/event_analytics/explorer');
+ };
+
+ const getVizContextPanels = () => {
+ return [
+ {
+ id: 0,
+ title: 'Add visualization',
+ items: [
+ {
+ name: 'Select existing visualization',
+ onClick: () => {
+ if (closeVizPopover != null) {
+ closeVizPopover();
+ }
+ showFlyout();
+ },
+ },
+ {
+ name: 'Create new visualization',
+ onClick: () => {
+ advancedVisualization();
+ },
+ },
+ ],
+ },
+ ];
+ };
+
+ const addVisualizationButton = (
+
+ Add visualization
+
+ );
+ return (
+
+ );
+};
diff --git a/public/components/custom_panels/helpers/custom_input_modal.tsx b/public/components/custom_panels/helpers/custom_input_modal.tsx
new file mode 100644
index 0000000000..15042e6791
--- /dev/null
+++ b/public/components/custom_panels/helpers/custom_input_modal.tsx
@@ -0,0 +1,109 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useState } from 'react';
+import {
+ EuiButtonEmpty,
+ EuiForm,
+ EuiModal,
+ EuiModalBody,
+ EuiModalFooter,
+ EuiModalHeader,
+ EuiModalHeaderTitle,
+ EuiOverlayMask,
+ EuiFormRow,
+ EuiFieldText,
+ EuiButton,
+} from '@elastic/eui';
+
+/*
+ * "CustomInputModalProps" component is used to create a modal with an input filed
+ *
+ * Props taken in as params are:
+ * runModal - function to fetch input field value and trigger closing modal
+ * closeModal - function to trigger closing modal
+ * titletxt - string as header for title of modal
+ * labelTxt - string as header for input field
+ * btn1txt - string as content to fill "close button"
+ * btn2txt - string as content to fill "confirm button"
+ * openPanelName - Default input value for the field
+ * helpText - string help for the input field
+ * optionalArgs - Arguments needed to pass them to runModal function
+ */
+
+type CustomInputModalProps = {
+ runModal:
+ | ((value: string, value2: string, value3: string, value4: string) => void)
+ | ((value: string) => void);
+ closeModal: (
+ event?: React.KeyboardEvent | React.MouseEvent
+ ) => void;
+ labelTxt: string;
+ titletxt: string;
+ btn1txt: string;
+ btn2txt: string;
+ openPanelName?: string;
+ helpText?: string;
+ optionalArgs?: string[];
+};
+
+export const CustomInputModal = (props: CustomInputModalProps) => {
+ const {
+ runModal,
+ closeModal,
+ labelTxt,
+ titletxt,
+ btn1txt,
+ btn2txt,
+ openPanelName,
+ helpText,
+ optionalArgs,
+ } = props;
+ const [value, setValue] = useState(openPanelName || ''); // sets input value
+
+ const onChange = (e: React.ChangeEvent) => {
+ setValue(e.target.value);
+ };
+
+ return (
+
+
+
+ {titletxt}
+
+
+
+
+
+ onChange(e)}
+ />
+
+
+
+
+
+ {btn1txt}
+ {optionalArgs === undefined ? (
+ runModal(value)} fill>
+ {btn2txt}
+
+ ) : (
+ runModal(value, ...optionalArgs)}
+ fill
+ >
+ {btn2txt}
+
+ )}
+
+
+
+ );
+};
diff --git a/public/components/custom_panels/helpers/modal_containers.tsx b/public/components/custom_panels/helpers/modal_containers.tsx
new file mode 100644
index 0000000000..0fb80a5979
--- /dev/null
+++ b/public/components/custom_panels/helpers/modal_containers.tsx
@@ -0,0 +1,107 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useState } from 'react';
+import {
+ EuiOverlayMask,
+ EuiConfirmModal,
+ EuiButton,
+ EuiButtonEmpty,
+ EuiFieldText,
+ EuiForm,
+ EuiFormRow,
+ EuiModal,
+ EuiModalBody,
+ EuiModalFooter,
+ EuiModalHeader,
+ EuiModalHeaderTitle,
+ EuiText,
+ EuiSpacer,
+} from '@elastic/eui';
+import { CustomInputModal } from './custom_input_modal';
+
+/* The file contains helper functions for modal layouts
+ * getCustomModal - returns modal with input field
+ * getCloneModal - returns a confirm-modal with clone option
+ * getDeleteModal - returns a confirm-modal with delete option
+ */
+
+export const getCustomModal = (
+ runModal:
+ | ((value: string, value2: string, value3: string, value4: string) => void)
+ | ((value: string) => void),
+ closeModal: (
+ event?: React.KeyboardEvent | React.MouseEvent
+ ) => void,
+ labelTxt: string,
+ titletxt: string,
+ btn1txt: string,
+ btn2txt: string,
+ openPanelName?: string,
+ helpText?: string,
+ optionalArgs?: string[]
+) => {
+ return (
+
+ );
+};
+
+export const getCloneModal = (
+ onCancel: (
+ event?: React.KeyboardEvent | React.MouseEvent
+ ) => void,
+ onConfirm: (event?: React.MouseEvent) => void
+) => {
+ return (
+
+
+ Do you want to clone this operational panel?
+
+
+ );
+};
+
+export const getDeleteModal = (
+ onCancel: (
+ event?: React.KeyboardEvent | React.MouseEvent
+ ) => void,
+ onConfirm: (event?: React.MouseEvent) => void,
+ title: string,
+ message: string,
+ confirmMessage?: string
+) => {
+ return (
+
+
+ {message}
+
+
+ );
+};
diff --git a/public/components/custom_panels/helpers/utils.tsx b/public/components/custom_panels/helpers/utils.tsx
new file mode 100644
index 0000000000..3121ddeeeb
--- /dev/null
+++ b/public/components/custom_panels/helpers/utils.tsx
@@ -0,0 +1,306 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable no-console */
+
+import dateMath from '@elastic/datemath';
+import { ShortDate } from '@elastic/eui';
+import { DurationRange } from '@elastic/eui/src/components/date_picker/types';
+import _ from 'lodash';
+import { Moment } from 'moment-timezone';
+import React from 'react';
+import { Layout } from 'react-grid-layout';
+import { PPL_DATE_FORMAT, PPL_INDEX_REGEX } from '../../../../common/constants/shared';
+import PPLService from '../../../services/requests/ppl';
+import { CoreStart } from '../../../../../../src/core/public';
+import { CUSTOM_PANELS_API_PREFIX } from '../../../../common/constants/custom_panels';
+import { VisualizationType, SavedVisualizationType } from '../../../../common/types/custom_panels';
+import { Visualization } from '../../visualizations/visualization';
+import { getVizContainerProps } from '../../../components/visualizations/charts/helpers';
+
+/*
+ * "Utils" This file contains different reused functions in operational panels
+ *
+ * isNameValid - Validates string to length > 0 and < 50
+ * convertDateTime - Converts input datetime string to required format
+ * mergeLayoutAndVisualizations - Function to merge current panel layout into the visualizations list
+ * getQueryResponse - Get response of PPL query to load visualizations
+ * renderSavedVisualization - Fetches savedVisualization by Id and runs getQueryResponse
+ * onTimeChange - Function to store recently used time filters and set start and end time.
+ * isDateValid - Function to check date validity
+ * isPPLFilterValid - Validate if the panel PPL query doesn't contain any Index/Time/Field filters
+ * displayVisualization - Function to render the visualzation based of its type
+ */
+
+// Name validation 0>Name<=50
+export const isNameValid = (name: string) => {
+ return name.length >= 50 || name.length === 0 ? false : true;
+};
+
+// DateTime convertor to required format
+export const convertDateTime = (datetime: string, isStart = true, formatted = true) => {
+ let returnTime: undefined | Moment;
+ if (isStart) {
+ returnTime = dateMath.parse(datetime);
+ } else {
+ returnTime = dateMath.parse(datetime, { roundUp: true });
+ }
+
+ if (formatted) return returnTime!.utc().format(PPL_DATE_FORMAT);
+ return returnTime;
+};
+
+// Merges new layout into visualizations
+export const mergeLayoutAndVisualizations = (
+ layout: Layout[],
+ newVisualizationList: VisualizationType[],
+ setPanelVisualizations: (value: React.SetStateAction) => void
+) => {
+ const newPanelVisualizations: VisualizationType[] = [];
+
+ for (let i = 0; i < newVisualizationList.length; i++) {
+ for (let j = 0; j < layout.length; j++) {
+ if (newVisualizationList[i].id == layout[j].i) {
+ newPanelVisualizations.push({
+ ...newVisualizationList[i],
+ x: layout[j].x,
+ y: layout[j].y,
+ w: layout[j].w,
+ h: layout[j].h,
+ });
+ }
+ }
+ }
+ setPanelVisualizations(newPanelVisualizations);
+};
+
+/* Builds Final Query by adding time and query filters(From panel UI) to the original visualization query
+ * -> Final Query is as follows:
+ * -> finalQuery = indexPartOfQuery + timeQueryFilter + panelFilterQuery + filterPartOfQuery
+ * -> finalQuery = source=opensearch_dashboards_sample_data_flights
+ * + | where utc_time > ‘2021-07-01 00:00:00’ and utc_time < ‘2021-07-02 00:00:00’
+ * + | where Carrier='OpenSearch-Air'
+ * + | stats sum(FlightDelayMin) as delays by Carrier
+ */
+const queryAccumulator = (
+ originalQuery: string,
+ timestampField: string,
+ startTime: string,
+ endTime: string,
+ panelFilterQuery: string
+) => {
+ const indexMatchArray = originalQuery.match(PPL_INDEX_REGEX);
+ if (indexMatchArray == null) {
+ throw Error('index not found in Query');
+ }
+ const indexPartOfQuery = indexMatchArray[0];
+ const filterPartOfQuery = originalQuery.replace(PPL_INDEX_REGEX, '');
+ const timeQueryFilter = ` | where ${timestampField} >= '${convertDateTime(
+ startTime
+ )}' and ${timestampField} <= '${convertDateTime(endTime, false)}'`;
+ const pplFilterQuery = panelFilterQuery === '' ? '' : ` | ${panelFilterQuery}`;
+ return indexPartOfQuery + timeQueryFilter + pplFilterQuery + filterPartOfQuery;
+};
+
+// PPL Service requestor
+const pplServiceRequestor = async (
+ pplService: PPLService,
+ finalQuery: string,
+ type: string,
+ setVisualizationData: React.Dispatch>,
+ setIsLoading: React.Dispatch>,
+ setIsError: React.Dispatch>
+) => {
+ await pplService
+ .fetch({ query: finalQuery, format: 'viz' })
+ .then((res) => {
+ if (res === undefined) setIsError('Please check the validity of PPL Filter');
+ setVisualizationData(res);
+ })
+ .catch((error: Error) => {
+ setIsError(error.stack || 'Issue in fetching visualization');
+ console.error(error);
+ })
+ .finally(() => {
+ setIsLoading(false);
+ });
+};
+
+// Fetched Saved Visualization By Id
+export const fetchVisualizationById = async (
+ http: CoreStart['http'],
+ savedVisualizationId: string,
+ setIsError: (value: string) => void
+) => {
+ let savedVisualization = {} as SavedVisualizationType;
+ await http
+ .get(`${CUSTOM_PANELS_API_PREFIX}/visualizations/${savedVisualizationId}`)
+ .then((res) => {
+ savedVisualization = res.visualization;
+ })
+ .catch((err) => {
+ setIsError(`Could not locate saved visualization id:${savedVisualizationId}`);
+ console.error('Issue in fetching the saved Visualization by Id', err);
+ });
+
+ return savedVisualization;
+};
+
+// Get PPL Query Response
+export const getQueryResponse = (
+ pplService: PPLService,
+ query: string,
+ type: string,
+ startTime: string,
+ endTime: string,
+ setVisualizationData: React.Dispatch>,
+ setIsLoading: React.Dispatch>,
+ setIsError: React.Dispatch>,
+ filterQuery = '',
+ timestampField = 'timestamp'
+) => {
+ setIsLoading(true);
+ setIsError('');
+
+ let finalQuery = '';
+ try {
+ finalQuery = queryAccumulator(query, timestampField, startTime, endTime, filterQuery);
+ } catch (error) {
+ const errorMessage = 'Issue in building final query';
+ setIsError(errorMessage);
+ console.error(errorMessage, error);
+ setIsLoading(false);
+ return;
+ }
+
+ pplServiceRequestor(pplService, finalQuery, type, setVisualizationData, setIsLoading, setIsError);
+};
+
+// Fetches savedVisualization by Id and runs getQueryResponse
+export const renderSavedVisualization = async (
+ http: CoreStart['http'],
+ pplService: PPLService,
+ savedVisualizationId: string,
+ startTime: string,
+ endTime: string,
+ filterQuery: string,
+ setVisualizationTitle: React.Dispatch>,
+ setVisualizationType: React.Dispatch>,
+ setVisualizationData: React.Dispatch>,
+ setVisualizationMetaData: React.Dispatch>,
+ setIsLoading: React.Dispatch>,
+ setIsError: React.Dispatch>
+) => {
+ setIsLoading(true);
+ setIsError('');
+
+ let visualization = {} as SavedVisualizationType;
+ visualization = await fetchVisualizationById(http, savedVisualizationId, setIsError);
+
+ if (_.isEmpty(visualization)) {
+ setIsLoading(false);
+ return;
+ }
+
+ if (visualization.name) {
+ setVisualizationTitle(visualization.name);
+ }
+
+ if (visualization.type) {
+ setVisualizationType(visualization.type);
+ }
+
+ setVisualizationMetaData(visualization);
+
+ getQueryResponse(
+ pplService,
+ visualization.query,
+ visualization.type,
+ startTime,
+ endTime,
+ setVisualizationData,
+ setIsLoading,
+ setIsError,
+ filterQuery,
+ visualization.timeField
+ );
+};
+
+// Function to store recently used time filters and set start and end time.
+export const onTimeChange = (
+ start: ShortDate,
+ end: ShortDate,
+ recentlyUsedRanges: DurationRange[],
+ setRecentlyUsedRanges: React.Dispatch>,
+ setStart: React.Dispatch>,
+ setEnd: React.Dispatch>
+) => {
+ const recentlyUsedRange = recentlyUsedRanges.filter((recentlyUsedRange) => {
+ const isDuplicate = recentlyUsedRange.start === start && recentlyUsedRange.end === end;
+ return !isDuplicate;
+ });
+ recentlyUsedRange.unshift({ start, end });
+ setStart(start);
+ setEnd(end);
+ setRecentlyUsedRanges(recentlyUsedRange.slice(0, 9));
+};
+
+// Function to check date validity
+export const isDateValid = (
+ start: string | Moment | undefined,
+ end: string | Moment | undefined,
+ setToast: (
+ title: string,
+ color?: string,
+ text?: React.ReactChild | undefined,
+ side?: string | undefined
+ ) => void,
+ side?: string | undefined
+) => {
+ if (end! < start!) {
+ setToast('Time range entered is invalid', 'danger', undefined, side);
+ return false;
+ } else return true;
+};
+
+// Check for time filter in query
+const checkIndexExists = (query: string) => {
+ return PPL_INDEX_REGEX.test(query);
+};
+
+// Check PPL Query in Panel UI
+// Validate if the query doesn't contain any Index
+export const isPPLFilterValid = (
+ query: string,
+ setToast: (
+ title: string,
+ color?: string,
+ text?: React.ReactChild | undefined,
+ side?: string | undefined
+ ) => void
+) => {
+ if (checkIndexExists(query)) {
+ setToast('Please remove index from PPL Filter', 'danger', undefined);
+ return false;
+ }
+ return true;
+};
+
+// Renders visualization in the vizualization container component
+export const displayVisualization = (metaData: any, data: any, type: string) => {
+ if (metaData === undefined || metaData === {}) {
+ return <>>;
+ }
+ return (
+
+ );
+};
diff --git a/public/components/custom_panels/home.tsx b/public/components/custom_panels/home.tsx
new file mode 100644
index 0000000000..4a5395fb0f
--- /dev/null
+++ b/public/components/custom_panels/home.tsx
@@ -0,0 +1,349 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable no-console */
+
+import { EuiBreadcrumb, EuiGlobalToastList, EuiLink, ShortDate } from '@elastic/eui';
+import { Toast } from '@elastic/eui/src/components/toast/global_toast_list';
+import _ from 'lodash';
+import React, { ReactChild, useState } from 'react';
+// eslint-disable-next-line @osd/eslint/module_migration
+import { StaticContext } from 'react-router';
+import { Route, RouteComponentProps } from 'react-router-dom';
+import PPLService from '../../services/requests/ppl';
+import DSLService from '../../services/requests/dsl';
+import { CoreStart } from '../../../../../src/core/public';
+import {
+ CUSTOM_PANELS_API_PREFIX,
+ CUSTOM_PANELS_DOCUMENTATION_URL,
+} from '../../../common/constants/custom_panels';
+import {
+ EVENT_ANALYTICS,
+ OBSERVABILITY_BASE,
+ SAVED_OBJECTS,
+} from '../../../common/constants/shared';
+import { CustomPanelListType } from '../../../common/types/custom_panels';
+import { ObservabilitySideBar } from '../common/side_nav';
+import { CustomPanelTable } from './custom_panel_table';
+import { CustomPanelView } from './custom_panel_view';
+import { isNameValid } from './helpers/utils';
+
+/*
+ * "Home" module is initial page for Operantional Panels
+ *
+ * Props taken in as params are:
+ * http: http core service;
+ * chrome: chrome core service;
+ * parentBreadcrumb: parent breadcrumb name and link
+ * pplService: ppl requestor service
+ * renderProps: Props from router
+ */
+
+interface PanelHomeProps {
+ http: CoreStart['http'];
+ chrome: CoreStart['chrome'];
+ parentBreadcrumbs: EuiBreadcrumb[];
+ pplService: PPLService;
+ dslService: DSLService;
+ renderProps: RouteComponentProps;
+}
+
+export const Home = ({
+ http,
+ chrome,
+ parentBreadcrumbs,
+ pplService,
+ dslService,
+ renderProps,
+}: PanelHomeProps) => {
+ const [customPanelData, setcustomPanelData] = useState([]);
+ const [toasts, setToasts] = useState([]);
+ const [loading, setLoading] = useState(false);
+ const [toastRightSide, setToastRightSide] = useState(true);
+ const [start, setStart] = useState('');
+ const [end, setEnd] = useState('');
+
+ const setToast = (title: string, color = 'success', text?: ReactChild, side?: string) => {
+ if (!text) text = '';
+ setToastRightSide(!side ? true : false);
+ setToasts([...toasts, { id: new Date().toISOString(), title, text, color } as Toast]);
+ };
+
+ const onEditClick = (savedVisualizationId: string) => {
+ window.location.assign(`#/event_analytics/explorer/${savedVisualizationId}`);
+ };
+
+ // Fetches all saved Custom Panels
+ const fetchCustomPanels = () => {
+ setLoading(true);
+ http
+ .get(`${CUSTOM_PANELS_API_PREFIX}/panels`)
+ .then((res) => {
+ setcustomPanelData(res.panels);
+ })
+ .catch((err) => {
+ console.error('Issue in fetching the operational panels', err.body.message);
+ });
+ setLoading(false);
+ };
+
+ // Creates a new CustomPanel
+ const createCustomPanel = (newCustomPanelName: string) => {
+ if (!isNameValid(newCustomPanelName)) {
+ setToast('Invalid Operational Panel name', 'danger');
+ return;
+ }
+
+ return http
+ .post(`${CUSTOM_PANELS_API_PREFIX}/panels`, {
+ body: JSON.stringify({
+ panelName: newCustomPanelName,
+ }),
+ })
+ .then(async (res) => {
+ setToast(`Operational Panel "${newCustomPanelName}" successfully created!`);
+ window.location.assign(`${_.last(parentBreadcrumbs)!.href}${res.newPanelId}`);
+ })
+ .catch((err) => {
+ setToast(
+ 'Please ask your administrator to enable Operational Panels for you.',
+ 'danger',
+
+ Documentation
+
+ );
+ console.error(err);
+ });
+ };
+
+ // Renames an existing CustomPanel
+ const renameCustomPanel = (editedCustomPanelName: string, editedCustomPanelId: string) => {
+ if (!isNameValid(editedCustomPanelName)) {
+ setToast('Invalid Custom Panel name', 'danger');
+ return Promise.reject();
+ }
+ const renamePanelObject = {
+ panelId: editedCustomPanelId,
+ panelName: editedCustomPanelName,
+ };
+
+ return http
+ .post(`${CUSTOM_PANELS_API_PREFIX}/panels/rename`, {
+ body: JSON.stringify(renamePanelObject),
+ })
+ .then((res) => {
+ setcustomPanelData((prevCustomPanelData) => {
+ const newCustomPanelData = [...prevCustomPanelData];
+ const renamedCustomPanel = newCustomPanelData.find(
+ (customPanel) => customPanel.id === editedCustomPanelId
+ );
+ if (renamedCustomPanel) renamedCustomPanel.name = editedCustomPanelName;
+ return newCustomPanelData;
+ });
+ setToast(`Operational Panel successfully renamed into "${editedCustomPanelName}"`);
+ })
+ .catch((err) => {
+ setToast(
+ 'Error renaming Operational Panel, please make sure you have the correct permission.',
+ 'danger'
+ );
+ console.error(err.body.message);
+ });
+ };
+
+ // Clones an existing Custom Panel, return new Custom Panel id
+ const cloneCustomPanel = (
+ clonedCustomPanelName: string,
+ clonedCustomPanelId: string
+ ): Promise => {
+ if (!isNameValid(clonedCustomPanelName)) {
+ setToast('Invalid Operational Panel name', 'danger');
+ return Promise.reject();
+ }
+ const clonePanelObject = {
+ panelId: clonedCustomPanelId,
+ panelName: clonedCustomPanelName,
+ };
+
+ return http
+ .post(`${CUSTOM_PANELS_API_PREFIX}/panels/clone`, {
+ body: JSON.stringify(clonePanelObject),
+ })
+ .then((res) => {
+ setcustomPanelData((prevCustomPanelData) => {
+ return [
+ ...prevCustomPanelData,
+ {
+ name: clonedCustomPanelName,
+ id: res.clonePanelId,
+ dateCreated: res.dateCreated,
+ dateModified: res.dateModified,
+ },
+ ];
+ });
+ setToast(`Operational Panel "${clonedCustomPanelName}" successfully created!`);
+ return res.clonePanelId;
+ })
+ .catch((err) => {
+ setToast(
+ 'Error cloning Operational Panel, please make sure you have the correct permission.',
+ 'danger'
+ );
+ console.error(err.body.message);
+ });
+ };
+
+ // Deletes multiple existing Operational Panels
+ const deleteCustomPanelList = (customPanelIdList: string[], toastMessage: string) => {
+ const concatList = customPanelIdList.toString();
+ return http
+ .delete(`${CUSTOM_PANELS_API_PREFIX}/panelList/` + concatList)
+ .then((res) => {
+ setcustomPanelData((prevCustomPanelData) => {
+ return prevCustomPanelData.filter(
+ (customPanel) => !customPanelIdList.includes(customPanel.id)
+ );
+ });
+ setToast(toastMessage);
+ return res;
+ })
+ .catch((err) => {
+ setToast(
+ 'Error deleting Operational Panels, please make sure you have the correct permission.',
+ 'danger'
+ );
+ console.error(err.body.message);
+ });
+ };
+
+ // Deletes an existing Operational Panel
+ const deleteCustomPanel = (customPanelId: string, customPanelName: string) => {
+ return http
+ .delete(`${CUSTOM_PANELS_API_PREFIX}/panels/` + customPanelId)
+ .then((res) => {
+ setcustomPanelData((prevCustomPanelData) => {
+ return prevCustomPanelData.filter((customPanel) => customPanel.id !== customPanelId);
+ });
+ setToast(`Operational Panel "${customPanelName}" successfully deleted!`);
+ return res;
+ })
+ .catch((err) => {
+ setToast(
+ 'Error deleting Operational Panel, please make sure you have the correct permission.',
+ 'danger'
+ );
+ console.error(err.body.message);
+ });
+ };
+
+ const addSamplePanels = async () => {
+ try {
+ setLoading(true);
+ const flights = await http
+ .get('../api/saved_objects/_find', {
+ query: {
+ type: 'index-pattern',
+ search_fields: 'title',
+ search: 'opensearch_dashboards_sample_data_flights',
+ },
+ })
+ .then((resp) => resp.total === 0);
+ const logs = await http
+ .get('../api/saved_objects/_find', {
+ query: {
+ type: 'index-pattern',
+ search_fields: 'title',
+ search: 'opensearch_dashboards_sample_data_logs',
+ },
+ })
+ .then((resp) => resp.total === 0);
+ if (flights || logs) setToast('Adding sample data. This can take some time.');
+ await Promise.all([
+ flights ? http.post('../api/sample_data/flights') : Promise.resolve(),
+ logs ? http.post('../api/sample_data/logs') : Promise.resolve(),
+ ]);
+
+ let savedVisualizationIds: string[] = [];
+ await http
+ .get(`${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}/addSampleSavedObjects/panels`)
+ .then((resp) => (savedVisualizationIds = [...resp.savedVizIds]));
+
+ await http
+ .post(`${CUSTOM_PANELS_API_PREFIX}/panels/addSamplePanels`, {
+ body: JSON.stringify({
+ savedVisualizationIds,
+ }),
+ })
+ .then((res) => {
+ setcustomPanelData([...customPanelData, ...res.demoPanelsData]);
+ });
+ setToast(`Sample panels successfully added.`);
+ } catch (err: any) {
+ setToast('Error adding sample panels.', 'danger');
+ console.error(err.body.message);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+ {
+ setToasts(toasts.filter((toast) => toast.id !== removedToast.id));
+ }}
+ side={toastRightSide ? 'right' : 'left'}
+ toastLifeTimeMs={6000}
+ />
+ {
+ return (
+
+
+
+ );
+ }}
+ />
+ {
+ return (
+
+ );
+ }}
+ />
+
+ );
+};
diff --git a/public/components/custom_panels/panel_modules/__tests__/__snapshots__/empty_panel.test.tsx.snap b/public/components/custom_panels/panel_modules/__tests__/__snapshots__/empty_panel.test.tsx.snap
new file mode 100644
index 0000000000..9a31cb5f06
--- /dev/null
+++ b/public/components/custom_panels/panel_modules/__tests__/__snapshots__/empty_panel.test.tsx.snap
@@ -0,0 +1,430 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Empty panel view component renders empty panel view with disabled popover 1`] = `
+
+
+
+
+
+
+
+
+
+
+ Start by adding your first visualization
+
+
+
+
+
+
+
+
+ Use PPL Queries to fetch & filter observability data and create visualizations
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Add visualization
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="addVisualizationContextMenu"
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Empty panel view component renders empty panel view with enabled popover 1`] = `
+
+
+
+
+
+
+
+
+
+
+ Start by adding your first visualization
+
+
+
+
+
+
+
+
+ Use PPL Queries to fetch & filter observability data and create visualizations
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Add visualization
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="addVisualizationContextMenu"
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/custom_panels/panel_modules/__tests__/empty_panel.test.tsx b/public/components/custom_panels/panel_modules/__tests__/empty_panel.test.tsx
new file mode 100644
index 0000000000..2c3c24dcd6
--- /dev/null
+++ b/public/components/custom_panels/panel_modules/__tests__/empty_panel.test.tsx
@@ -0,0 +1,36 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { EuiButton, EuiContextMenu, EuiPopover } from '@elastic/eui';
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { EmptyPanelView } from '../empty_panel';
+
+describe('Empty panel view component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders empty panel view with disabled popover', () => {
+ const addVizDisabled = true;
+ const showFlyout = jest.fn();
+ const wrapper = mount(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ expect(wrapper.find('EuiButton').prop('disabled')).toBe(true);
+ });
+
+ it('renders empty panel view with enabled popover', () => {
+ const addVizDisabled = false;
+ const showFlyout = jest.fn();
+ const wrapper = mount(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ expect(wrapper.find('EuiButton').prop('disabled')).toBe(false);
+ });
+});
diff --git a/public/components/custom_panels/panel_modules/empty_panel.tsx b/public/components/custom_panels/panel_modules/empty_panel.tsx
new file mode 100644
index 0000000000..32a1226b76
--- /dev/null
+++ b/public/components/custom_panels/panel_modules/empty_panel.tsx
@@ -0,0 +1,46 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { EuiSpacer, EuiText, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
+import React, { useState } from 'react';
+import { AddVisualizationPopover } from '../helpers/add_visualization_popover';
+
+/*
+ * EmptyPanelView - This Sub-component is shown to the user when a operational panel is empty
+ *
+ * Props taken in as params are:
+ * addVizDisabled -> Boolean to enable/disable the add visualization button
+ * getVizContextPanels -> Function to populate the add visualization popover
+ */
+
+interface EmptyPanelViewProps {
+ addButton?: any;
+ addVizDisabled: boolean;
+ showFlyout: (isReplacement?: boolean, replaceVizId?: string) => void;
+}
+
+export const EmptyPanelView = ({
+ addVizDisabled,
+ showFlyout,
+ addButton = ,
+}: EmptyPanelViewProps) => {
+ return (
+
+
+
+ Start by adding your first visualization
+
+
+ Use PPL Queries to fetch & filter observability data and create visualizations
+
+
+
+
+ {addButton}
+
+
+
+ );
+};
diff --git a/public/components/custom_panels/panel_modules/panel_grid/__tests__/__snapshots__/panel_grid.test.tsx.snap b/public/components/custom_panels/panel_modules/panel_grid/__tests__/__snapshots__/panel_grid.test.tsx.snap
new file mode 100644
index 0000000000..b192dff2d8
--- /dev/null
+++ b/public/components/custom_panels/panel_modules/panel_grid/__tests__/__snapshots__/panel_grid.test.tsx.snap
@@ -0,0 +1,174 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Panel Grid Component renders panel grid component with empty visualizations 1`] = `
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/custom_panels/panel_modules/panel_grid/__tests__/panel_grid.test.tsx b/public/components/custom_panels/panel_modules/panel_grid/__tests__/panel_grid.test.tsx
new file mode 100644
index 0000000000..1366eb4537
--- /dev/null
+++ b/public/components/custom_panels/panel_modules/panel_grid/__tests__/panel_grid.test.tsx
@@ -0,0 +1,63 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import httpClientMock from '../../../../../../test/__mocks__/httpClientMock';
+import { PanelGrid } from '../panel_grid';
+import PPLService from '../../../../../services/requests/ppl';
+import { VisualizationType } from '../../../../../../common/types/custom_panels';
+import { coreStartMock } from '../../../../../../test/__mocks__/coreMocks';
+import { waitFor } from '@testing-library/react';
+
+describe('Panel Grid Component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders panel grid component with empty visualizations', async () => {
+ const http = httpClientMock;
+ const core = coreStartMock;
+ const panelId = '';
+ const panelVisualizations: VisualizationType[] = [];
+ const setPanelVisualizations = jest.fn();
+ const editMode = false;
+ const pplService = new PPLService(httpClientMock);
+ const start = 'now-15m';
+ const end = 'now';
+ const onRefresh = false;
+ const cloneVisualization = jest.fn();
+ const pplFilterValue = '';
+ const showFlyout = jest.fn();
+ const editActionType = '';
+ const onEditClick = (savedVisId: string) => {
+ window.location.assign(`#/event_analytics/explorer/${savedVisId}`);
+ };
+
+ const wrapper = mount(
+
+ );
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
diff --git a/public/components/custom_panels/panel_modules/panel_grid/index.ts b/public/components/custom_panels/panel_modules/panel_grid/index.ts
new file mode 100644
index 0000000000..d67fc20547
--- /dev/null
+++ b/public/components/custom_panels/panel_modules/panel_grid/index.ts
@@ -0,0 +1,6 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { PanelGrid } from "./panel_grid";
diff --git a/public/components/custom_panels/panel_modules/panel_grid/panel_grid.scss b/public/components/custom_panels/panel_modules/panel_grid/panel_grid.scss
new file mode 100644
index 0000000000..0c00cee0bc
--- /dev/null
+++ b/public/components/custom_panels/panel_modules/panel_grid/panel_grid.scss
@@ -0,0 +1,15 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+.react-grid-layout {
+ & .react-grid-placeholder {
+ background: $euiColorWarning;
+ }
+}
+
+.full-width {
+ min-width: 100%;
+ max-width: 100%;
+}
diff --git a/public/components/custom_panels/panel_modules/panel_grid/panel_grid.tsx b/public/components/custom_panels/panel_modules/panel_grid/panel_grid.tsx
new file mode 100644
index 0000000000..dc70ba7fd9
--- /dev/null
+++ b/public/components/custom_panels/panel_modules/panel_grid/panel_grid.tsx
@@ -0,0 +1,212 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable react-hooks/exhaustive-deps */
+/* eslint-disable no-console */
+
+import _ from 'lodash';
+import React, { useEffect, useState } from 'react';
+import { Layout, Layouts, Responsive, WidthProvider } from 'react-grid-layout';
+import useObservable from 'react-use/lib/useObservable';
+import { CoreStart } from '../../../../../../../src/core/public';
+import PPLService from '../../../../services/requests/ppl';
+import { VisualizationContainer } from '../visualization_container';
+import { VisualizationType } from '../../../../../common/types/custom_panels';
+import { CUSTOM_PANELS_API_PREFIX } from '../../../../../common/constants/custom_panels';
+import './panel_grid.scss';
+import { mergeLayoutAndVisualizations } from '../../helpers/utils';
+
+// HOC container to provide dynamic width for Grid layout
+const ResponsiveGridLayout = WidthProvider(Responsive);
+
+/*
+ * PanelGrid - This module is places all visualizations in react-grid-layout
+ *
+ * Props taken in as params are:
+ * http: http core service;
+ * chrome: chrome core service;
+ * panelId: OpenPanel Id
+ * updateAvailabilityVizId: function to update application if availabilityViz is removed from panel
+ * panelVisualizations: list of panel visualizations
+ * setPanelVisualizations: function to set panel visualizations
+ * editMode: boolean to check if the panel is in edit mode
+ * pplService: ppl requestor service
+ * startTime: start time in date filter
+ * endTime: end time in date filter
+ * onRefresh: boolean value to trigger refresh of visualizations
+ * cloneVisualization: function to clone a visualization in panel
+ * pplFilterValue: string with panel PPL filter value
+ * showFlyout: function to show the flyout
+ * editActionType: Type of action done while clicking the edit button
+ */
+
+interface PanelGridProps {
+ http: CoreStart['http'];
+ chrome: CoreStart['chrome'];
+ panelId: string;
+ updateAvailabilityVizId?: any;
+ panelVisualizations: VisualizationType[];
+ setPanelVisualizations: React.Dispatch>;
+ editMode: boolean;
+ pplService: PPLService;
+ startTime: string;
+ endTime: string;
+ onEditClick: (savedVisualizationId: string) => any;
+ onRefresh: boolean;
+ cloneVisualization: (visualzationTitle: string, savedVisualizationId: string) => void;
+ pplFilterValue: string;
+ showFlyout: (isReplacement?: boolean | undefined, replaceVizId?: string | undefined) => void;
+ editActionType: string;
+ setEditVizId?: any;
+}
+
+export const PanelGrid = (props: PanelGridProps) => {
+ const {
+ http,
+ chrome,
+ panelId,
+ updateAvailabilityVizId,
+ panelVisualizations,
+ setPanelVisualizations,
+ editMode,
+ pplService,
+ startTime,
+ endTime,
+ onEditClick,
+ onRefresh,
+ cloneVisualization,
+ pplFilterValue,
+ showFlyout,
+ editActionType,
+ } = props;
+ const [currentLayout, setCurrentLayout] = useState([]);
+ const [postEditLayout, setPostEditLayout] = useState([]);
+ const [gridData, setGridData] = useState(panelVisualizations.map(() => <>>));
+ const isLocked = useObservable(chrome.getIsNavDrawerLocked$());
+
+ // Reset Size of Visualizations when layout is changed
+ const layoutChanged = (currLayouts: Layout[], allLayouts: Layouts) => {
+ window.dispatchEvent(new Event('resize'));
+ setPostEditLayout(currLayouts);
+ };
+
+ const loadVizComponents = () => {
+ const gridDataComps = panelVisualizations.map(
+ (panelVisualization: VisualizationType, index) => (
+
+ )
+ );
+ setGridData(gridDataComps);
+ };
+
+ // Reload the Layout
+ const reloadLayout = () => {
+ const tempLayout: Layout[] = panelVisualizations.map((panelVisualization) => {
+ return {
+ i: panelVisualization.id,
+ x: panelVisualization.x,
+ y: panelVisualization.y,
+ w: panelVisualization.w,
+ h: panelVisualization.h,
+ static: !editMode,
+ } as Layout;
+ });
+ setCurrentLayout(tempLayout);
+ };
+
+ // remove visualization from panel in edit mode
+ const removeVisualization = (visualizationId: string) => {
+ const newVisualizationList = _.reject(panelVisualizations, {
+ id: visualizationId,
+ });
+ mergeLayoutAndVisualizations(postEditLayout, newVisualizationList, setPanelVisualizations);
+ };
+
+ // Save Visualization Layouts when not in edit mode anymore (after users saves the panel)
+ const saveVisualizationLayouts = async (panelID: string, visualizationParams: any) => {
+ return http
+ .put(`${CUSTOM_PANELS_API_PREFIX}/visualizations/edit`, {
+ body: JSON.stringify({
+ panelId: panelID,
+ visualizationParams,
+ }),
+ })
+ .then(async (res) => {
+ setPanelVisualizations(res.visualizations);
+ })
+ .catch((err) => {
+ console.error(err);
+ });
+ };
+
+ // Update layout whenever user edit gets completed
+ useEffect(() => {
+ if (editMode) {
+ reloadLayout();
+ loadVizComponents();
+ }
+ }, [editMode]);
+
+ useEffect(() => {
+ if (editActionType === 'save') {
+ const visualizationParams = postEditLayout.map((layout) =>
+ _.omit(layout, ['static', 'moved'])
+ );
+ saveVisualizationLayouts(panelId, visualizationParams);
+ if (updateAvailabilityVizId) {
+ updateAvailabilityVizId(panelVisualizations);
+ }
+ }
+ }, [editActionType]);
+
+ // Update layout whenever visualizations are updated
+ useEffect(() => {
+ reloadLayout();
+ loadVizComponents();
+ }, [panelVisualizations]);
+
+ // Reset Size of Panel Grid when Nav Dock is Locked
+ useEffect(() => {
+ setTimeout(function () {
+ window.dispatchEvent(new Event('resize'));
+ }, 300);
+ }, [isLocked]);
+
+ useEffect(() => {
+ loadVizComponents();
+ }, [onRefresh]);
+
+ useEffect(() => {
+ loadVizComponents();
+ }, []);
+
+ return (
+
+ {panelVisualizations.map((panelVisualization: VisualizationType, index) => (
+ {gridData[index]}
+ ))}
+
+ );
+};
diff --git a/public/components/custom_panels/panel_modules/visualization_container/__tests__/__snapshots__/visualization_container.test.tsx.snap b/public/components/custom_panels/panel_modules/visualization_container/__tests__/__snapshots__/visualization_container.test.tsx.snap
new file mode 100644
index 0000000000..3065c1cb8a
--- /dev/null
+++ b/public/components/custom_panels/panel_modules/visualization_container/__tests__/__snapshots__/visualization_container.test.tsx.snap
@@ -0,0 +1,303 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Visualization Container Component renders add visualization container 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Visualization Container Component renders add visualization container 2`] = `
+
+
+ >>>>>> 6b15239 (Add data test subj to app analytics (#704))
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/custom_panels/panel_modules/visualization_container/__tests__/visualization_container.test.tsx b/public/components/custom_panels/panel_modules/visualization_container/__tests__/visualization_container.test.tsx
new file mode 100644
index 0000000000..20ab07fa9e
--- /dev/null
+++ b/public/components/custom_panels/panel_modules/visualization_container/__tests__/visualization_container.test.tsx
@@ -0,0 +1,69 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import PPLService from '../../../../../services/requests/ppl';
+import React from 'react';
+import { VisualizationContainer } from '../visualization_container';
+import httpClientMock from '../../../../../../test/__mocks__/httpClientMock';
+import { HttpResponse } from '../../../../../../../../src/core/public';
+import { waitFor } from '@testing-library/react';
+import {
+ sampleSavedVisualization,
+ samplePPLResponse,
+} from '../../../../../../test/panels_constants';
+
+describe.skip('Visualization Container Component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders add visualization container', async () => {
+ httpClientMock.get = jest.fn(() =>
+ Promise.resolve((sampleSavedVisualization as unknown) as HttpResponse)
+ );
+
+ httpClientMock.post = jest.fn(() =>
+ Promise.resolve((samplePPLResponse as unknown) as HttpResponse)
+ );
+
+ const editMode = true;
+ const visualizationId = 'panel_viz_9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d';
+ const savedVisualizationId = 'oiuccXwBYVazWqOO1e06';
+ const fromTime = 'now-15m';
+ const toTime = 'now';
+ const onRefresh = true;
+ const cloneVisualization = jest.fn();
+ const pplFilterValue = 'where Carrier = "OpenSearch-Air"';
+ const showFlyout = jest.fn();
+ const removeVisualization = jest.fn();
+ const pplService = new PPLService(httpClientMock);
+ const onEditClick = (savedVisId: string) => {
+ window.location.assign(`#/event_analytics/explorer/${savedVisId}`);
+ };
+
+ const wrapper = mount(
+
+ );
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
diff --git a/public/components/custom_panels/panel_modules/visualization_container/index.ts b/public/components/custom_panels/panel_modules/visualization_container/index.ts
new file mode 100644
index 0000000000..1503aa7ab8
--- /dev/null
+++ b/public/components/custom_panels/panel_modules/visualization_container/index.ts
@@ -0,0 +1,6 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { VisualizationContainer } from "./visualization_container";
diff --git a/public/components/custom_panels/panel_modules/visualization_container/visualization_container.scss b/public/components/custom_panels/panel_modules/visualization_container/visualization_container.scss
new file mode 100644
index 0000000000..6d14d72882
--- /dev/null
+++ b/public/components/custom_panels/panel_modules/visualization_container/visualization_container.scss
@@ -0,0 +1,60 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+.mouseGrabber {
+ & :hover {
+ cursor: -webkit-grab;
+ cursor: grab;
+ }
+ & :active {
+ cursor: -webkit-grabbing;
+ cursor: grabbing;
+ }
+}
+
+.visualization-action-button {
+ & :hover {
+ cursor: -webkit-pointer;
+ cursor: pointer;
+ }
+}
+
+.visualization-div {
+ width: 100%;
+ height: 90%;
+ overflow: auto;
+ text-align: center;
+}
+
+%center-div {
+ top: 50%;
+ left: 50%;
+ -ms-transform: translate(-50%, -50%);
+ -moz-transform: translate(-50%, -50%);
+ -webkit-transform: translate(-50%, -50%);
+ -o-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+}
+
+.visualization-loading-chart {
+ margin: 0;
+ position: absolute;
+ @extend %center-div;
+}
+
+.visualization-error-div {
+ overflow: auto;
+ position: relative;
+ @extend %center-div;
+}
+
+.panel-full-width {
+ width: 100%;
+ height: 100%;
+}
+
+.panels-title-text {
+ @include euiTextTruncate;
+}
diff --git a/public/components/custom_panels/panel_modules/visualization_container/visualization_container.tsx b/public/components/custom_panels/panel_modules/visualization_container/visualization_container.tsx
new file mode 100644
index 0000000000..bb1a25e041
--- /dev/null
+++ b/public/components/custom_panels/panel_modules/visualization_container/visualization_container.tsx
@@ -0,0 +1,222 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ EuiButtonIcon,
+ EuiContextMenuItem,
+ EuiContextMenuPanel,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiIcon,
+ EuiLoadingChart,
+ EuiPanel,
+ EuiPopover,
+ EuiSpacer,
+ EuiText,
+ EuiToolTip,
+} from '@elastic/eui';
+import React, { useEffect, useMemo, useState } from 'react';
+import { CoreStart } from '../../../../../../../src/core/public';
+import PPLService from '../../../../services/requests/ppl';
+import { displayVisualization, renderSavedVisualization } from '../../helpers/utils';
+import './visualization_container.scss';
+
+/*
+ * Visualization container - This module is a placeholder to add visualizations in react-grid-layout
+ *
+ * Props taken in as params are:
+ * editMode: boolean to check if the panel is in edit mode
+ * visualizationId: unique visualization id
+ * visualizationTitle: visualization name
+ * query: ppl query to load the visualization
+ * pplService: ppl requestor service
+ * type: type of visualization [bar, horizontal_bar, line]
+ * fromTime: start time in date filter
+ * toTime: end time in date filter
+ * onRefresh: boolean value to trigger refresh of visualizations
+ * cloneVisualization: function to clone a visualization in panel
+ * pplFilterValue: string with panel PPL filter value
+ * showFlyout: function to show the flyout
+ * removeVisualization: function to remove all the visualizations
+ */
+
+interface Props {
+ http: CoreStart['http'];
+ editMode: boolean;
+ visualizationId: string;
+ savedVisualizationId: string;
+ pplService: PPLService;
+ fromTime: string;
+ toTime: string;
+ onRefresh: boolean;
+ pplFilterValue: string;
+ usedInNotebooks?: boolean;
+ onEditClick: (savedVisualizationId: string) => any;
+ cloneVisualization?: (visualzationTitle: string, savedVisualizationId: string) => void;
+ showFlyout?: (isReplacement?: boolean | undefined, replaceVizId?: string | undefined) => void;
+ removeVisualization?: (visualizationId: string) => void;
+}
+
+export const VisualizationContainer = ({
+ http,
+ editMode,
+ visualizationId,
+ savedVisualizationId,
+ pplService,
+ fromTime,
+ toTime,
+ onRefresh,
+ pplFilterValue,
+ usedInNotebooks,
+ onEditClick,
+ cloneVisualization,
+ showFlyout,
+ removeVisualization,
+}: Props) => {
+ const [isPopoverOpen, setIsPopoverOpen] = useState(false);
+ const [disablePopover, setDisablePopover] = useState(false);
+ const [visualizationTitle, setVisualizationTitle] = useState('');
+ const [visualizationType, setVisualizationType] = useState('');
+ const [visualizationMetaData, setVisualizationMetaData] = useState();
+ const [visualizationData, setVisualizationData] = useState([]);
+ const [isLoading, setIsLoading] = useState(true);
+ const [isError, setIsError] = useState('');
+ const onActionsMenuClick = () => setIsPopoverOpen((currPopoverOpen) => !currPopoverOpen);
+ const closeActionsMenu = () => setIsPopoverOpen(false);
+
+ let popoverPanel = [
+ {
+ closeActionsMenu();
+ onEditClick(savedVisualizationId);
+ }}
+ >
+ Edit
+ ,
+ {
+ closeActionsMenu();
+ showFlyout(true, visualizationId);
+ }}
+ >
+ Replace
+ ,
+ {
+ closeActionsMenu();
+ cloneVisualization(visualizationTitle, savedVisualizationId);
+ }}
+ >
+ Duplicate
+ ,
+ ];
+
+ if (usedInNotebooks) {
+ popoverPanel = [popoverPanel[0]];
+ }
+
+ const loadVisaulization = async () => {
+ await renderSavedVisualization(
+ http,
+ pplService,
+ savedVisualizationId,
+ fromTime,
+ toTime,
+ pplFilterValue,
+ setVisualizationTitle,
+ setVisualizationType,
+ setVisualizationData,
+ setVisualizationMetaData,
+ setIsLoading,
+ setIsError
+ );
+ };
+
+ const memoisedVisualizationBox = useMemo(
+ () => (
+
+ {isLoading ? (
+
+ ) : isError !== '' ? (
+
+ ) : (
+ displayVisualization(visualizationMetaData, visualizationData, visualizationType)
+ )}
+
+ ),
+ [onRefresh, isLoading, isError, visualizationData, visualizationType, visualizationMetaData]
+ );
+
+ useEffect(() => {
+ loadVisaulization();
+ }, [onRefresh]);
+
+ useEffect(() => {
+ editMode ? setDisablePopover(true) : setDisablePopover(false);
+ }, [editMode]);
+
+ return (
+
+
+
+
+
+
+ {visualizationTitle}
+
+
+
+
+ {disablePopover ? (
+ {
+ removeVisualization(visualizationId);
+ }}
+ />
+ ) : (
+
+ }
+ isOpen={isPopoverOpen}
+ closePopover={closeActionsMenu}
+ anchorPosition="downLeft"
+ >
+
+
+ )}
+
+
+
+ {memoisedVisualizationBox}
+
+ );
+};
diff --git a/public/components/custom_panels/panel_modules/visualization_flyout/__tests__/__snapshots__/visualization_flyout.test.tsx.snap b/public/components/custom_panels/panel_modules/visualization_flyout/__tests__/__snapshots__/visualization_flyout.test.tsx.snap
new file mode 100644
index 0000000000..1d43d52288
--- /dev/null
+++ b/public/components/custom_panels/panel_modules/visualization_flyout/__tests__/__snapshots__/visualization_flyout.test.tsx.snap
@@ -0,0 +1,2140 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Visualization Flyout Component renders add visualization Flyout 1`] = `
+
+
+
+ No saved visualizations found!
+
+
+ }
+ >
+
+
+ Please use the "create new visualization" option in add visualization menu.
+
+
+
+ }
+ flyoutFooter={
+
+
+
+
+ Cancel
+
+
+
+
+ Add
+
+
+
+
+ }
+ flyoutHeader={
+
+
+
+ Select existing visualization
+
+
+
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No saved visualizations found!
+
+
+
+
+
+
+ Please use the "create new visualization" option in add visualization menu.
+
+
+
+
+
+
+
+ }
+ onActivation={[Function]}
+ onDeactivation={[Function]}
+ persistentFocus={false}
+ returnFocus={[Function]}
+ shards={Array []}
+ sideCar={
+ Object {
+ "assignMedium": [Function],
+ "assignSyncMedium": [Function],
+ "options": Object {
+ "async": true,
+ "ssr": false,
+ },
+ "read": [Function],
+ "useMedium": [Function],
+ }
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+ No saved visualizations found!
+
+
+
+
+
+
+ Please use the "create new visualization" option in add visualization menu.
+
+
+
+
+
+
+
+ }
+ onActivation={[Function]}
+ onDeactivation={[Function]}
+ persistentFocus={false}
+ returnFocus={[Function]}
+ shards={Array []}
+ sideCar={
+ Object {
+ "assignMedium": [Function],
+ "assignSyncMedium": [Function],
+ "options": Object {
+ "async": true,
+ "ssr": false,
+ },
+ "read": [Function],
+ "useMedium": [Function],
+ }
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+ No saved visualizations found!
+
+
+
+
+
+
+ Please use the "create new visualization" option in add visualization menu.
+
+
+
+
+
+
+
+ }
+ onActivation={[Function]}
+ onDeactivation={[Function]}
+ persistentFocus={false}
+ returnFocus={[Function]}
+ shards={Array []}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+ No saved visualizations found!
+
+
+
+
+
+
+ Please use the "create new visualization" option in add visualization menu.
+
+
+
+
+
+
+
+ }
+ onActivation={[Function]}
+ onDeactivation={[Function]}
+ persistentFocus={false}
+ returnFocus={[Function]}
+ shards={Array []}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Select existing visualization
+
+
+
+
+
+
+ No saved visualizations found!
+
+
+ }
+ >
+
+
+
+
+
+
+
+
+ No saved visualizations found!
+
+
+
+
+
+
+
+
+ Please use the "create new visualization" option in add visualization menu.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Add
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Visualization Flyout Component renders replace visualization Flyout 1`] = `
+
+
+
+ No saved visualizations found!
+
+
+ }
+ >
+
+
+ Please use the "create new visualization" option in add visualization menu.
+
+
+
+ }
+ flyoutFooter={
+
+
+
+
+ Cancel
+
+
+
+
+ Add
+
+
+
+
+ }
+ flyoutHeader={
+
+
+
+ Replace visualization
+
+
+
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No saved visualizations found!
+
+
+
+
+
+
+ Please use the "create new visualization" option in add visualization menu.
+
+
+
+
+
+
+
+ }
+ onActivation={[Function]}
+ onDeactivation={[Function]}
+ persistentFocus={false}
+ returnFocus={[Function]}
+ shards={Array []}
+ sideCar={
+ Object {
+ "assignMedium": [Function],
+ "assignSyncMedium": [Function],
+ "options": Object {
+ "async": true,
+ "ssr": false,
+ },
+ "read": [Function],
+ "useMedium": [Function],
+ }
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No saved visualizations found!
+
+
+
+
+
+
+ Please use the "create new visualization" option in add visualization menu.
+
+
+
+
+
+
+
+ }
+ onActivation={[Function]}
+ onDeactivation={[Function]}
+ persistentFocus={false}
+ returnFocus={[Function]}
+ shards={Array []}
+ sideCar={
+ Object {
+ "assignMedium": [Function],
+ "assignSyncMedium": [Function],
+ "options": Object {
+ "async": true,
+ "ssr": false,
+ },
+ "read": [Function],
+ "useMedium": [Function],
+ }
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No saved visualizations found!
+
+
+
+
+
+
+ Please use the "create new visualization" option in add visualization menu.
+
+
+
+
+
+
+
+ }
+ onActivation={[Function]}
+ onDeactivation={[Function]}
+ persistentFocus={false}
+ returnFocus={[Function]}
+ shards={Array []}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No saved visualizations found!
+
+
+
+
+
+
+ Please use the "create new visualization" option in add visualization menu.
+
+
+
+
+
+
+
+ }
+ onActivation={[Function]}
+ onDeactivation={[Function]}
+ persistentFocus={false}
+ returnFocus={[Function]}
+ shards={Array []}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Replace visualization
+
+
+
+
+
+
+ No saved visualizations found!
+
+
+ }
+ >
+
+
+
+
+
+
+
+
+ No saved visualizations found!
+
+
+
+
+
+
+
+
+ Please use the "create new visualization" option in add visualization menu.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Add
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/custom_panels/panel_modules/visualization_flyout/__tests__/visualization_flyout.test.tsx b/public/components/custom_panels/panel_modules/visualization_flyout/__tests__/visualization_flyout.test.tsx
new file mode 100644
index 0000000000..7aebf7b901
--- /dev/null
+++ b/public/components/custom_panels/panel_modules/visualization_flyout/__tests__/visualization_flyout.test.tsx
@@ -0,0 +1,76 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import PPLService from '../../../../../services/requests/ppl';
+import React from 'react';
+import { VisaulizationFlyout } from '../visualization_flyout';
+import httpClientMock from '../../../../../../test/__mocks__/httpClientMock';
+import { ShortDate } from '@elastic/eui';
+
+describe('Visualization Flyout Component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders add visualization Flyout', () => {
+ const panelId = '';
+ const pplFilterValue = '';
+ const start: ShortDate = 'now-15m';
+ const end: ShortDate = 'now';
+ const setToast = jest.fn();
+ const closeFlyout = jest.fn();
+ const setPanelVisualizations = jest.fn();
+ const pplService = new PPLService(httpClientMock);
+ const isFlyoutReplacement = false;
+
+ const wrapper = mount(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it('renders replace visualization Flyout', () => {
+ const panelId = 'oiuccXwBYVazWqOO1e06';
+ const pplFilterValue = "where Carrier='OpenSearch-Air'";
+ const start: ShortDate = '2011-08-11T01:23:45.678Z';
+ const end: ShortDate = '2011-08-12T01:23:45.678Z';
+ const setToast = jest.fn();
+ const closeFlyout = jest.fn();
+ const setPanelVisualizations = jest.fn();
+ const pplService = new PPLService(httpClientMock);
+ const isFlyoutReplacement = true;
+ const replaceVisualizationId = '';
+
+ const wrapper = mount(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+});
diff --git a/public/components/custom_panels/panel_modules/visualization_flyout/index.ts b/public/components/custom_panels/panel_modules/visualization_flyout/index.ts
new file mode 100644
index 0000000000..bab4d36c5c
--- /dev/null
+++ b/public/components/custom_panels/panel_modules/visualization_flyout/index.ts
@@ -0,0 +1,6 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { VisaulizationFlyout } from "./visualization_flyout";
diff --git a/public/components/custom_panels/panel_modules/visualization_flyout/visualization_flyout.scss b/public/components/custom_panels/panel_modules/visualization_flyout/visualization_flyout.scss
new file mode 100644
index 0000000000..bec49407b7
--- /dev/null
+++ b/public/components/custom_panels/panel_modules/visualization_flyout/visualization_flyout.scss
@@ -0,0 +1,29 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+.visualization-div-preview {
+ min-height: 50vh;
+}
+
+.visualization-loading-chart-preview {
+ margin: 0;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ -ms-transform: translate(-50%, -50%);
+ -moz-transform: translate(-50%, -50%);
+ -webkit-transform: translate(-50%, -50%);
+ -o-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+}
+
+.visualization-error-div-preview {
+ overflow: scroll;
+}
+
+.date-picker-preview {
+ height: 3vh;
+ max-width: 500px;
+}
diff --git a/public/components/custom_panels/panel_modules/visualization_flyout/visualization_flyout.tsx b/public/components/custom_panels/panel_modules/visualization_flyout/visualization_flyout.tsx
new file mode 100644
index 0000000000..2c97e7095e
--- /dev/null
+++ b/public/components/custom_panels/panel_modules/visualization_flyout/visualization_flyout.tsx
@@ -0,0 +1,369 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable no-console */
+/* eslint-disable react-hooks/exhaustive-deps */
+
+import {
+ EuiButton,
+ EuiButtonIcon,
+ EuiCallOut,
+ EuiDatePicker,
+ EuiDatePickerRange,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiFlyoutBody,
+ EuiFlyoutFooter,
+ EuiFlyoutHeader,
+ EuiFormRow,
+ EuiIcon,
+ EuiLoadingChart,
+ EuiSelect,
+ EuiSelectOption,
+ EuiSpacer,
+ EuiText,
+ EuiTitle,
+ ShortDate,
+} from '@elastic/eui';
+import _ from 'lodash';
+import React, { useEffect, useState } from 'react';
+import { FlyoutContainers } from '../../../common/flyout_containers';
+import { displayVisualization, getQueryResponse, isDateValid } from '../../helpers/utils';
+import { convertDateTime } from '../../helpers/utils';
+import PPLService from '../../../../services/requests/ppl';
+import { CoreStart } from '../../../../../../../src/core/public';
+import { CUSTOM_PANELS_API_PREFIX } from '../../../../../common/constants/custom_panels';
+import {
+ pplResponse,
+ SavedVisualizationType,
+ VisualizationType,
+} from '../../../../../common/types/custom_panels';
+import './visualization_flyout.scss';
+import { uiSettingsService } from '../../../../../common/utils';
+
+/*
+ * VisaulizationFlyout - This module create a flyout to add visualization
+ *
+ * Props taken in as params are:
+ * panelId: panel Id of current operational panel
+ * closeFlyout: function to close the flyout
+ * start: start time in date filter
+ * end: end time in date filter
+ * setToast: function to set toast in the panel
+ * http: http core service
+ * pplService: ppl requestor service
+ * setPanelVisualizations: function set the visualization list in panel
+ * isFlyoutReplacement: boolean to see if the flyout is trigger for add or replace visualization
+ * replaceVisualizationId: string id of the visualization to be replaced
+ */
+
+interface VisualizationFlyoutProps {
+ panelId: string;
+ pplFilterValue: string;
+ closeFlyout: () => void;
+ start: ShortDate;
+ end: ShortDate;
+ setToast: (
+ title: string,
+ color?: string,
+ text?: React.ReactChild | undefined,
+ side?: string | undefined
+ ) => void;
+ http: CoreStart['http'];
+ pplService: PPLService;
+ setPanelVisualizations: React.Dispatch>;
+ isFlyoutReplacement?: boolean | undefined;
+ replaceVisualizationId?: string | undefined;
+ appId?: string;
+}
+
+export const VisaulizationFlyout = ({
+ panelId,
+ appId = '',
+ pplFilterValue,
+ closeFlyout,
+ start,
+ end,
+ setToast,
+ http,
+ pplService,
+ setPanelVisualizations,
+ isFlyoutReplacement,
+ replaceVisualizationId,
+}: VisualizationFlyoutProps) => {
+ const [newVisualizationTitle, setNewVisualizationTitle] = useState('');
+ const [newVisualizationType, setNewVisualizationType] = useState('');
+ const [newVisualizationTimeField, setNewVisualizationTimeField] = useState('');
+ const [previewMetaData, setPreviewMetaData] = useState();
+ const [pplQuery, setPPLQuery] = useState('');
+ const [previewData, setPreviewData] = useState({} as pplResponse);
+ const [previewArea, setPreviewArea] = useState(<>>);
+ const [previewLoading, setPreviewLoading] = useState(false);
+ const [isPreviewError, setIsPreviewError] = useState('');
+ const [savedVisualizations, setSavedVisualizations] = useState([]);
+ const [visualizationOptions, setVisualizationOptions] = useState([]);
+ const [selectValue, setSelectValue] = useState('');
+
+ // DateTimePicker States
+ const startDate = convertDateTime(start, true, false);
+ const endDate = convertDateTime(end, false, false);
+
+ const isInputValid = () => {
+ if (!isDateValid(convertDateTime(start), convertDateTime(end, false), setToast, 'left')) {
+ return false;
+ }
+
+ if (selectValue === '') {
+ setToast('Please make a valid selection', 'danger', undefined, 'left');
+ return false;
+ }
+
+ return true;
+ };
+
+ const addVisualization = () => {
+ if (!isInputValid()) return;
+
+ if (isFlyoutReplacement) {
+ http
+ .post(`${CUSTOM_PANELS_API_PREFIX}/visualizations/replace`, {
+ body: JSON.stringify({
+ panelId,
+ savedVisualizationId: selectValue,
+ oldVisualizationId: replaceVisualizationId,
+ }),
+ })
+ .then(async (res) => {
+ setPanelVisualizations(res.visualizations);
+ setToast(`Visualization ${newVisualizationTitle} successfully added!`, 'success');
+ })
+ .catch((err) => {
+ setToast(`Error in adding ${newVisualizationTitle} visualization to the panel`, 'danger');
+ console.error(err);
+ });
+ } else {
+ http
+ .post(`${CUSTOM_PANELS_API_PREFIX}/visualizations`, {
+ body: JSON.stringify({
+ panelId,
+ savedVisualizationId: selectValue,
+ }),
+ })
+ .then(async (res) => {
+ setPanelVisualizations(res.visualizations);
+ setToast(`Visualization ${newVisualizationTitle} successfully added!`, 'success');
+ })
+ .catch((err) => {
+ setToast(`Error in adding ${newVisualizationTitle} visualization to the panel`, 'danger');
+ console.error(err);
+ });
+ }
+ closeFlyout();
+ };
+
+ const onRefreshPreview = () => {
+ if (!isInputValid()) return;
+
+ getQueryResponse(
+ pplService,
+ pplQuery,
+ newVisualizationType,
+ start,
+ end,
+ setPreviewData,
+ setPreviewLoading,
+ setIsPreviewError,
+ pplFilterValue,
+ newVisualizationTimeField
+ );
+ };
+
+ const timeRange = (
+
+ endDate}
+ aria-label="Start date"
+ dateFormat={uiSettingsService.get('dateFormat')}
+ />
+ }
+ endDateControl={
+ endDate}
+ aria-label="End date"
+ dateFormat={uiSettingsService.get('dateFormat')}
+ />
+ }
+ />
+
+ );
+
+ const flyoutHeader = (
+
+
+
+ {isFlyoutReplacement ? 'Replace visualization' : 'Select existing visualization'}
+
+
+
+ );
+
+ const onChangeSelection = (e: React.ChangeEvent) => {
+ setSelectValue(e.target.value);
+ };
+
+ const emptySavedVisualizations = (
+
+ No saved visualizations found!
+
+ );
+
+ const flyoutBody =
+ savedVisualizations.length > 0 ? (
+
+ <>
+
+
+ onChangeSelection(e)}
+ options={visualizationOptions}
+ />
+
+
+
+
+
+ Preview
+
+
+
+
+
+
+
+ {previewArea}
+ >
+
+ ) : (
+
+ <>
+ {'Please use the "create new visualization" option in add visualization menu.'}
+ >
+
+ );
+
+ const flyoutFooter = (
+
+
+
+ Cancel
+
+
+
+ Add
+
+
+
+
+ );
+
+ // Fetch all saved visualizations
+ const fetchSavedVisualizations = async () => {
+ return http
+ .get(`${CUSTOM_PANELS_API_PREFIX}/visualizations`)
+ .then((res) => {
+ if (res.visualizations.length > 0) {
+ setSavedVisualizations(res.visualizations);
+ const filterAppVis = res.visualizations.filter((vis: SavedVisualizationType) => {
+ return appId
+ ? vis.hasOwnProperty('application_id')
+ ? vis.application_id === appId
+ : false
+ : !vis.hasOwnProperty('application_id');
+ });
+ setVisualizationOptions(
+ filterAppVis.map((visualization: SavedVisualizationType) => {
+ return { value: visualization.id, text: visualization.name };
+ })
+ );
+ }
+ })
+ .catch((err) => {
+ console.error('Issue in fetching the operational panels', err);
+ });
+ };
+
+ useEffect(() => {
+ const previewTemplate = (
+ <>
+ {timeRange}
+
+
+ {previewLoading ? (
+
+ ) : isPreviewError !== '' ? (
+
+
+
+
+ {isPreviewError}
+
+
+ ) : (
+
+ {displayVisualization(previewMetaData, previewData, newVisualizationType)}
+
+ )}
+
+
+ >
+ );
+ setPreviewArea(previewTemplate);
+ }, [previewLoading]);
+
+ // On change of selected visualization change options
+ useEffect(() => {
+ for (let i = 0; i < savedVisualizations.length; i++) {
+ const visualization = savedVisualizations[i];
+ if (visualization.id === selectValue) {
+ setPPLQuery(visualization.query);
+ setNewVisualizationTitle(visualization.name);
+ setNewVisualizationType(visualization.type);
+ setPreviewMetaData(visualization);
+ setNewVisualizationTimeField(visualization.timeField);
+ break;
+ }
+ }
+ }, [selectValue]);
+
+ // load saved visualizations
+ useEffect(() => {
+ fetchSavedVisualizations();
+ }, []);
+
+ return (
+
+ );
+};
diff --git a/public/components/explorer/__tests__/__snapshots__/data_grid.test.tsx.snap b/public/components/explorer/__tests__/__snapshots__/data_grid.test.tsx.snap
new file mode 100644
index 0000000000..a98dbe7835
--- /dev/null
+++ b/public/components/explorer/__tests__/__snapshots__/data_grid.test.tsx.snap
@@ -0,0 +1,667 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Datagrid component Renders data grid component 1`] = `
+
+
+
+
+
+
+
+ double_per_ip_bytes
+
+
+ host
+
+
+ ip_count
+
+
+ per_ip_bytes
+
+
+ resp_code
+
+
+ sum_bytes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/explorer/__tests__/__snapshots__/no_results.test.tsx.snap b/public/components/explorer/__tests__/__snapshots__/no_results.test.tsx.snap
new file mode 100644
index 0000000000..e7e97a213b
--- /dev/null
+++ b/public/components/explorer/__tests__/__snapshots__/no_results.test.tsx.snap
@@ -0,0 +1,211 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`No result component Renders No result component 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ >
+
+
+
+
+
+
+
+
+
+ No results match your search criteria
+
+
+
+
+
+
+
+
+
+
+
+
+ Expand your time range or modify your query
+
+
+
+
+ Your query may not match anything in the current time range, or there may not be any data at all in the currently selected time range. Try change time range, query filters or choose different time fields
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/explorer/__tests__/data_grid.test.tsx b/public/components/explorer/__tests__/data_grid.test.tsx
new file mode 100644
index 0000000000..a45d7ecd91
--- /dev/null
+++ b/public/components/explorer/__tests__/data_grid.test.tsx
@@ -0,0 +1,48 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { DataGrid } from '../data_grid';
+import {
+ SELECTED_FIELDS,
+ AVAILABLE_FIELDS,
+ UNSELECTED_FIELDS,
+ QUERIED_FIELDS
+} from '../../../../common/constants/explorer';
+import {
+ AVAILABLE_FIELDS as SIDEBAR_AVAILABLE_FIELDS,
+ QUERY_FIELDS,
+ DATA_GRID_ROWS
+} from '../../../../test/event_analytics_constants';
+
+describe('Datagrid component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders data grid component', async () => {
+ const explorerFields = {
+ [SELECTED_FIELDS]: [],
+ [UNSELECTED_FIELDS]: [],
+ [AVAILABLE_FIELDS]: SIDEBAR_AVAILABLE_FIELDS,
+ [QUERIED_FIELDS]: QUERY_FIELDS
+ };
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
\ No newline at end of file
diff --git a/public/components/explorer/__tests__/explorer.test.tsx b/public/components/explorer/__tests__/explorer.test.tsx
new file mode 100644
index 0000000000..29078fed19
--- /dev/null
+++ b/public/components/explorer/__tests__/explorer.test.tsx
@@ -0,0 +1,54 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React, { MutableRefObject } from 'react';
+import { waitFor } from '@testing-library/react';
+import httpClientMock from '../../../../test/__mocks__/httpClientMock';
+// import { Explorer } from '../explorer';
+import PPLService from '../../../services/requests/ppl';
+import DSLService from '../../../services/requests/dsl';
+import SavedObjects from '../../../services/saved_objects/event_analytics/saved_objects';
+import TimestampUtils from '../../../services/timestamp/timestamp';
+import { coreStartMock } from '../../../../test/__mocks__/coreMocks';
+
+describe.skip('Event explorer component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders explorer component', async () => {
+ const pplService = new PPLService(httpClientMock);
+ const dslService = new DSLService(httpClientMock);
+ const tabId = 'query-panel-1';
+ const savedObjects = new SavedObjects(httpClientMock);
+ const timestampUtils = new TimestampUtils(dslService);
+ const setToast = jest.fn();
+ const history = jest.fn() as any;
+ history.replace = jest.fn();
+ history.push = jest.fn();
+ const notifications = coreStartMock.notifications;
+ const savedObjectId = 'JIcoln0BYMuJGDsOLTnM';
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
diff --git a/public/components/explorer/__tests__/no_results.test.tsx b/public/components/explorer/__tests__/no_results.test.tsx
new file mode 100644
index 0000000000..b87c8dc13e
--- /dev/null
+++ b/public/components/explorer/__tests__/no_results.test.tsx
@@ -0,0 +1,27 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { NoResults } from '../no_results';
+
+describe('No result component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders No result component', async () => {
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
\ No newline at end of file
diff --git a/public/components/explorer/data_grid.scss b/public/components/explorer/data_grid.scss
new file mode 100644
index 0000000000..6de07488a4
--- /dev/null
+++ b/public/components/explorer/data_grid.scss
@@ -0,0 +1,490 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * 1. Stack content vertically so the table can scroll when its constrained by a fixed container height.
+ */
+ doc-table {
+ @include euiScrollBar;
+ overflow: auto;
+ flex: 1 1 100%;
+ flex-direction: column; /* 1 */
+
+ .spinner {
+ position: absolute;
+ top: 40%;
+ left: 0;
+ right: 0;
+ z-index: $euiZLevel1;
+ opacity: 0.5;
+ }
+}
+
+.osdDocTable__container.loading {
+ opacity: 0.5;
+}
+
+.osdDocTable {
+ font-size: $euiFontSizeXS;
+
+ th {
+ white-space: nowrap;
+ padding-right: $euiSizeS;
+
+ .fa {
+ font-size: 1.1em;
+ }
+ }
+}
+
+.osd-table,
+.osdDocTable {
+ /**
+ * Style OpenSearch document _source in table view key: value
+ * Use alpha so this will stand out against non-white backgrounds, e.g. the highlighted
+ * row in the Context Log.
+ */
+
+ dl.source {
+ margin-bottom: 0;
+ line-height: 2em;
+ word-break: break-word;
+
+ dt,
+ dd {
+ display: inline;
+ }
+
+ dt {
+ background-color: transparentize(shade($euiColorPrimary, 20%), 0.9);
+ color: $euiTextColor;
+ padding: ($euiSizeXS / 2) $euiSizeXS;
+ margin-right: $euiSizeXS;
+ word-break: normal;
+ border-radius: $euiBorderRadius;
+ }
+ }
+}
+
+.osdDocTable__row {
+ td {
+ position: relative;
+
+ &:hover {
+ .osdDocTableRowFilterButton {
+ opacity: 1;
+ }
+ }
+ }
+}
+
+.osdDocTable__row--highlight {
+ td,
+ .osdDocTableRowFilterButton {
+ background-color: tintOrShade($euiColorPrimary, 90%, 70%);
+ }
+}
+
+.osdDocTable__bar {
+ margin: $euiSizeXS $euiSizeXS 0;
+}
+
+.osdDocTable__bar--footer {
+ position: relative;
+ margin: -($euiSize * 3) $euiSizeXS 0;
+}
+
+.osdDocTable__padBottom {
+ padding-bottom: $euiSizeXL;
+}
+
+.osdDocTable__error {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ flex: 1 0 100%;
+ text-align: center;
+}
+
+.truncate-by-height {
+ overflow: hidden;
+}
+
+.table {
+ // Nesting
+ .table {
+ background-color: $euiColorEmptyShade;
+ }
+}
+
+.osd-table {
+ // sub tables should not have a leading border
+ .table .table {
+ margin-bottom: 0;
+
+ tr:first-child > td {
+ border-top: none;
+ }
+
+ td.field-name {
+ font-weight: $euiFontWeightBold;
+ }
+ }
+
+ th {
+ text-align: left;
+ font-weight: bold;
+ }
+}
+
+table {
+ th {
+ i.fa-sort {
+ color: $euiColorLightShade;
+ }
+
+ button.fa-sort-asc,
+ button.fa-sort-down,
+ i.fa-sort-asc,
+ i.fa-sort-down {
+ color: $euiColorPrimary;
+ }
+
+ button.fa-sort-desc,
+ button.fa-sort-up,
+ i.fa-sort-desc,
+ i.fa-sort-up {
+ color: $euiColorPrimary;
+ }
+ }
+}
+
+/* ------------- table cell ---------- */
+.osdDocTableCell__dataField {
+ white-space: pre-wrap;
+}
+
+.osdDocTableCell__toggleDetails {
+ padding: 4px 0 0 0!important;
+}
+
+.osdDocTableCell__filter {
+ position: absolute;
+ white-space: nowrap;
+ right: 0;
+}
+
+/**
+ * 1. Align icon with text in cell.
+ * 2. Use opacity to make this element accessible to screen readers and keyboard.
+ * 3. Show on focus to enable keyboard accessibility.
+ */
+
+.osdDocTableRowFilterButton {
+ appearance: none;
+ background-color: $euiColorEmptyShade;
+ border: none;
+ padding: 0 $euiSizeXS;
+ font-size: $euiFontSizeS;
+ line-height: 1; /* 1 */
+ display: inline-block;
+ opacity: 0; /* 2 */
+
+ &:focus {
+ opacity: 1; /* 3 */
+ }
+}
+
+/* ------------- End of table cell ---------- */
+
+/* ------------- Discover like style -------- */
+.dscAppWrapper {
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ overflow: hidden;
+}
+
+.dscAppContainer {
+ > * {
+ position: relative;
+ }
+}
+discover-app {
+ flex-grow: 1;
+}
+
+.dscHistogram {
+ display: flex;
+ height: 200px;
+ padding: $euiSizeS;
+}
+
+// SASSTODO: replace the z-index value with a variable
+.dscWrapper {
+ padding-left: $euiSizeXL;
+ padding-right: $euiSizeS;
+ margin-top: $euiSizeM;
+ z-index: 1;
+ @include euiBreakpoint('xs', 's', 'm') {
+ padding-left: $euiSizeS;
+ }
+}
+
+@include euiPanel('.dscWrapper__content');
+
+.dscWrapper__content {
+ padding-top: $euiSizeXS;
+ background-color: $euiColorEmptyShade;
+
+ .osd-table {
+ margin-bottom: 0;
+ }
+}
+
+.dscTimechart {
+ display: block;
+ position: relative;
+
+ // SASSTODO: the visualizing component should have an option or a modifier
+ .series > rect {
+ fill-opacity: 0.5;
+ stroke-width: 1;
+ }
+}
+
+.dscResultCount {
+ padding-top: $euiSizeXS;
+}
+
+.dscTimechart__header {
+ display: flex;
+ justify-content: center;
+ min-height: $euiSizeXXL;
+ padding: $euiSizeXS 0;
+}
+
+.dscOverlay {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 20;
+ padding-top: $euiSizeM;
+
+ opacity: 0.75;
+ text-align: center;
+ background-color: transparent;
+}
+
+.dscTable {
+ overflow: auto;
+
+ // SASSTODO: add a monospace modifier to the doc-table component
+ .osdDocTable__row {
+ font-family: $euiCodeFontFamily;
+ font-size: $euiFontSizeXS;
+ }
+}
+
+// SASSTODO: replace the padding value with a variable
+.dscTable__footer {
+ background-color: $euiColorLightShade;
+ padding: 5px 10px;
+ text-align: center;
+}
+
+.dscResults {
+ h3 {
+ margin: -20px 0 10px 0;
+ text-align: center;
+ }
+}
+
+.dscResults__interval {
+ display: inline-block;
+ width: auto;
+}
+
+.dscSkipButton {
+ position: absolute;
+ right: $euiSizeM;
+ top: $euiSizeXS;
+}
+
+.dscTableFixedScroll {
+ overflow-x: auto;
+ padding-bottom: 0;
+
+ + .dscTableFixedScroll__scroller {
+ position: fixed;
+ bottom: 0;
+ overflow-x: auto;
+ overflow-y: hidden;
+ }
+}
+
+.dscCollapsibleSidebar {
+ position: relative;
+ z-index: 1;
+
+ .dscCollapsibleSidebar__collapseButton {
+ position: absolute;
+ top: 0;
+ right: -$euiSizeXL + 4;
+ cursor: pointer;
+ z-index: -1;
+ min-height: $euiSizeM;
+ min-width: $euiSizeM;
+ padding: $euiSizeXS * .5;
+ }
+
+ &.closed {
+ width: 0 !important;
+ border-right-width: 0;
+ border-left-width: 0;
+ .dscCollapsibleSidebar__collapseButton {
+ right: -$euiSizeL + 4;
+ }
+ }
+}
+
+@include euiBreakpoint('xs', 's', 'm') {
+ .dscCollapsibleSidebar {
+ &.closed {
+ display: none;
+ }
+
+ .dscCollapsibleSidebar__collapseButton {
+ display: none;
+ }
+ }
+}
+
+/* ------------- Detail table cell -------- */
+/**
+ * 1. Visually align the actions with the tabs. We can improve this by using flexbox instead, at a later point.
+ */
+ .osdDocTableDetails__actions {
+ float: right;
+ padding-top: $euiSizeS; /* 1 */
+}
+
+// Overwrite the border on the bootstrap table
+.osdDocTableDetails__row {
+
+ > td {
+ // Offsets negative margins from an inner flex group
+ padding: $euiSizeL !important;
+
+ tr:hover td {
+ background: tintOrShade($euiColorLightestShade, 50%, 20%);
+ }
+ }
+
+ td {
+ border-top: none !important;
+ }
+}
+
+/* ------------- open -------- */
+.osdDocTableOpen__button {
+ appearance: none;
+ background-color: transparent;
+ padding: 0;
+ border: none;
+ width: 14px; /* 1 */
+ height: 14px;
+}
+
+/* ------------- table header -------- */
+.osdDocTableHeader {
+ white-space: nowrap;
+}
+.osdDocTableHeader button {
+ margin-left: $euiSizeXS;
+}
+.osdDocTableHeader__move,
+.osdDocTableHeader__sortChange {
+ opacity: 0;
+ th:hover &,
+ &:focus {
+ opacity: 1;
+ }
+}
+
+/* ------------- doc_viewer -------- */
+.osdDocViewerTable {
+ margin-top: $euiSizeS;
+}
+
+.osdDocViewer {
+ pre,
+ .osdDocViewer__value {
+ display: inline-block;
+ word-break: break-all;
+ word-wrap: break-word;
+ white-space: pre-wrap;
+ color: $euiColorFullShade;
+ vertical-align: top;
+ padding-top: 2px;
+ }
+ .osdDocViewer__field {
+ padding-top: 8px;
+ }
+
+ .dscFieldName {
+ color: $euiColorDarkShade;
+ }
+
+ td,
+ pre {
+ font-family: $euiCodeFontFamily;
+ }
+
+ tr:first-child td {
+ border-top-color: transparent;
+ }
+
+ tr:hover {
+ .osdDocViewer__actionButton {
+ opacity: 1;
+ }
+ }
+}
+
+.osdDocViewer__buttons,
+.osdDocViewer__field {
+ white-space: nowrap;
+}
+.osdDocViewer__buttons {
+ width: 60px;
+
+ // Show all icons if one is focused,
+ // IE doesn't support, but the fallback is just the focused button becomes visible
+ &:focus-within {
+ .osdDocViewer__actionButton {
+ opacity: 1;
+ }
+ }
+}
+
+.osdDocViewer__field {
+ width: 160px;
+}
+
+.osdDocViewer__actionButton {
+ opacity: 0;
+
+ &:focus {
+ opacity: 1;
+ }
+}
+
+.osdDocViewer__warning {
+ margin-right: $euiSizeS;
+}
+
diff --git a/public/components/explorer/data_grid.tsx b/public/components/explorer/data_grid.tsx
new file mode 100644
index 0000000000..ad31d37458
--- /dev/null
+++ b/public/components/explorer/data_grid.tsx
@@ -0,0 +1,152 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import './data_grid.scss';
+
+import React, { useMemo, useState, useEffect, useRef, RefObject } from 'react';
+import { IExplorerFields } from '../../../common/types/explorer';
+import { DEFAULT_COLUMNS, PAGE_SIZE } from '../../../common/constants/explorer';
+import { getHeaders, getTrs, populateDataGrid } from './utils';
+import { HttpSetup } from '../../../../../src/core/public';
+import PPLService from '../../services/requests/ppl';
+
+interface DataGridProps {
+ http: HttpSetup;
+ pplService: PPLService;
+ rows: Array;
+ rowsAll: Array;
+ explorerFields: IExplorerFields;
+ timeStampField: string;
+ rawQuery: string;
+}
+
+export function DataGrid(props: DataGridProps) {
+ const { http, pplService, rows, rowsAll, explorerFields, timeStampField, rawQuery } = props;
+ const [limit, setLimit] = useState(PAGE_SIZE);
+ const loader = useRef(null);
+ const [rowRefs, setRowRefs] = useState[]>([]);
+
+ useEffect(() => {
+ if (!loader.current) return;
+
+ const observer = new IntersectionObserver(
+ (entries) => {
+ if (entries[0].isIntersecting) setLimit((limit) => limit + PAGE_SIZE);
+ },
+ {
+ root: null,
+ rootMargin: '500px',
+ threshold: 0,
+ }
+ );
+ observer.observe(loader.current);
+
+ return () => observer.disconnect();
+ }, [loader]);
+
+ const onFlyoutOpen = (docId: string) => {
+ rowRefs.forEach((rowRef) => {
+ rowRef.current?.closeAllFlyouts(docId);
+ });
+ };
+
+ const Queriedheaders = useMemo(() => getHeaders(explorerFields.queriedFields, DEFAULT_COLUMNS), [
+ explorerFields.queriedFields,
+ ]);
+ const [QueriedtableRows, setQueriedtableRows] = useState([]);
+ useEffect(() => {
+ setQueriedtableRows(
+ getTrs(
+ http,
+ explorerFields.queriedFields,
+ limit,
+ setLimit,
+ PAGE_SIZE,
+ timeStampField,
+ explorerFields,
+ pplService,
+ rawQuery,
+ rowRefs,
+ setRowRefs,
+ onFlyoutOpen,
+ rows
+ )
+ );
+ }, [rows, explorerFields.queriedFields]);
+
+ const headers = useMemo(() => getHeaders(explorerFields.selectedFields, DEFAULT_COLUMNS), [
+ explorerFields.selectedFields,
+ ]);
+ const [tableRows, setTableRows] = useState([]);
+ useEffect(() => {
+ const dataToRender =
+ explorerFields?.queriedFields && explorerFields.queriedFields.length > 0 ? rowsAll : rows;
+ setTableRows(
+ getTrs(
+ http,
+ explorerFields.selectedFields,
+ limit,
+ setLimit,
+ PAGE_SIZE,
+ timeStampField,
+ explorerFields,
+ pplService,
+ rawQuery,
+ rowRefs,
+ setRowRefs,
+ onFlyoutOpen,
+ dataToRender
+ )
+ );
+ }, [rows, explorerFields.selectedFields]);
+
+ useEffect(() => {
+ setQueriedtableRows((prev) =>
+ getTrs(
+ http,
+ explorerFields.queriedFields,
+ limit,
+ setLimit,
+ PAGE_SIZE,
+ timeStampField,
+ explorerFields,
+ pplService,
+ rawQuery,
+ rowRefs,
+ setRowRefs,
+ onFlyoutOpen,
+ rows,
+ prev
+ )
+ );
+ const dataToRender =
+ explorerFields?.queriedFields && explorerFields.queriedFields.length > 0 ? rowsAll : rows;
+ setTableRows((prev) =>
+ getTrs(
+ http,
+ explorerFields.selectedFields,
+ limit,
+ setLimit,
+ PAGE_SIZE,
+ timeStampField,
+ explorerFields,
+ pplService,
+ rawQuery,
+ rowRefs,
+ setRowRefs,
+ onFlyoutOpen,
+ dataToRender,
+ prev
+ )
+ );
+ }, [limit]);
+
+ return (
+ <>
+ {populateDataGrid(explorerFields, Queriedheaders, QueriedtableRows, headers, tableRows)}
+
+ >
+ );
+}
diff --git a/public/components/explorer/docTable/__tests__/__snapshots__/docViewer.test.tsx.snap b/public/components/explorer/docTable/__tests__/__snapshots__/docViewer.test.tsx.snap
new file mode 100644
index 0000000000..00693159c1
--- /dev/null
+++ b/public/components/explorer/docTable/__tests__/__snapshots__/docViewer.test.tsx.snap
@@ -0,0 +1,421 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Datagrid Doc viewer component Renders Doc viewer component 1`] = `
+
+
+
+
+
+
+
+
+
+ ,
+ "id": "doc_viewer_tab_2",
+ "name": "Table",
+ }
+ }
+ tabs={
+ Array [
+ Object {
+ "content":
+
+
+
+
+
+
+ ,
+ "id": "doc_viewer_tab_2",
+ "name": "Table",
+ },
+ Object {
+ "content":
+
+
+
+
+
+
+ ,
+ "id": "doc_viewer_tab_3",
+ "name": "JSON",
+ },
+ Object {
+ "content":
+
+
+
+
+
+
+ ,
+ "id": "doc_viewer_tab_4",
+ "name":
+
+ Traces
+
+
+ ,
+ },
+ ]
+ }
+ >
+
+
+
+
+
+
+ Table
+
+
+
+
+
+
+ JSON
+
+
+
+
+
+
+
+ Traces
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ avg(FlightDelayMin)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Carrier
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/explorer/docTable/__tests__/__snapshots__/docViewerRow.test.tsx.snap b/public/components/explorer/docTable/__tests__/__snapshots__/docViewerRow.test.tsx.snap
new file mode 100644
index 0000000000..b023ef06df
--- /dev/null
+++ b/public/components/explorer/docTable/__tests__/__snapshots__/docViewerRow.test.tsx.snap
@@ -0,0 +1,64 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Datagrid Doc viewer row component Renders Doc viewer row component 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+ 45.957544288332315
+
+
+
+`;
diff --git a/public/components/explorer/docTable/__tests__/docViewer.test.tsx b/public/components/explorer/docTable/__tests__/docViewer.test.tsx
new file mode 100644
index 0000000000..3a807d7c9a
--- /dev/null
+++ b/public/components/explorer/docTable/__tests__/docViewer.test.tsx
@@ -0,0 +1,34 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { DocViewer } from '../docViewer';
+
+describe('Datagrid Doc viewer component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders Doc viewer component', async () => {
+
+ const hit = {
+ 'Carrier': 'JetBeats',
+ 'avg(FlightDelayMin)': '45.957544288332315'
+ };
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
\ No newline at end of file
diff --git a/public/components/explorer/docTable/__tests__/docViewerRow.test.tsx b/public/components/explorer/docTable/__tests__/docViewerRow.test.tsx
new file mode 100644
index 0000000000..684ede48c7
--- /dev/null
+++ b/public/components/explorer/docTable/__tests__/docViewerRow.test.tsx
@@ -0,0 +1,39 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { DocViewRow } from '../docViewRow';
+
+describe('Datagrid Doc viewer row component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders Doc viewer row component', async () => {
+
+ const hit = {
+ 'Carrier': 'JetBeats',
+ 'avg(FlightDelayMin)': '45.957544288332315'
+ };
+ const selectedCols = [{
+ name: 'avg(FlightDelayMin)',
+ type: 'double'
+ }];
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
\ No newline at end of file
diff --git a/public/components/explorer/docTable/detailTable/docDetailTable.tsx b/public/components/explorer/docTable/detailTable/docDetailTable.tsx
new file mode 100644
index 0000000000..35c21917b3
--- /dev/null
+++ b/public/components/explorer/docTable/detailTable/docDetailTable.tsx
@@ -0,0 +1,93 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useState } from 'react';
+import { DocViewTableRow } from './table_row';
+
+export interface FieldMapping {
+ filterable?: boolean;
+ scripted?: boolean;
+ rowCount?: number;
+ type: string;
+ name: string;
+}
+
+export type DocViewFilterFn = (
+ mapping: FieldMapping | string | undefined,
+ value: unknown,
+ mode: '+' | '-'
+) => void;
+
+export interface DocViewRenderProps {
+ columns?: string[];
+ filter?: DocViewFilterFn;
+ hit: any;
+ onAddColumn?: (columnName: string) => void;
+ onRemoveColumn?: (columnName: string) => void;
+}
+
+const fieldType = 'string';
+const displayUnderscoreWarning = false;
+const displayNoMappingWarning = false;
+const isCollapsed = false;
+const isCollapsible = false;
+const isColumnActive = false;
+
+export function DocViewTable({
+ hit,
+ filter,
+ columns,
+ onAddColumn,
+ onRemoveColumn,
+}: DocViewRenderProps) {
+ const [fieldRowOpen, setFieldRowOpen] = useState({} as Record);
+
+ function toggleValueCollapse(field: string) {
+ fieldRowOpen[field] = fieldRowOpen[field] !== true;
+ setFieldRowOpen({ ...fieldRowOpen });
+ }
+
+ return (
+
+
+ {Object.keys(hit)
+ .sort((preKey, nextKey) => {
+ return preKey.toLowerCase().localeCompare(nextKey.toLowerCase());
+ })
+ .map((field) => {
+ const value = hit[field] === 'null' ? '' : hit[field];
+ const toggleColumn =
+ onRemoveColumn && onAddColumn && Array.isArray(columns)
+ ? () => {
+ if (columns.includes(field)) {
+ onRemoveColumn(field);
+ } else {
+ onAddColumn(field);
+ }
+ }
+ : undefined;
+
+ return (
+ toggleValueCollapse(field)}
+ onToggleColumn={toggleColumn}
+ value={value}
+ valueRaw={value}
+ />
+ );
+ })}
+
+
+ );
+}
diff --git a/public/components/explorer/docTable/detailTable/docDetailTitle.tsx b/public/components/explorer/docTable/detailTable/docDetailTitle.tsx
new file mode 100644
index 0000000000..f3e0bb3bf1
--- /dev/null
+++ b/public/components/explorer/docTable/detailTable/docDetailTitle.tsx
@@ -0,0 +1,55 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { EuiIcon } from '@elastic/eui';
+
+export const DocDetailTitle : React.FC = (props) => {
+ return (
+
+
+
+
+
+
+
+
+ Expanded document
+
+
+
+
+
+
+ );
+};
\ No newline at end of file
diff --git a/public/components/explorer/docTable/detailTable/table_helper.test.ts b/public/components/explorer/docTable/detailTable/table_helper.test.ts
new file mode 100644
index 0000000000..b714d76c5e
--- /dev/null
+++ b/public/components/explorer/docTable/detailTable/table_helper.test.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { arrayContainsObjects } from './table_helper';
+
+describe('arrayContainsObjects', () => {
+ it(`returns false for an array of primitives`, () => {
+ const actual = arrayContainsObjects(['test', 'test']);
+ expect(actual).toBeFalsy();
+ });
+
+ it(`returns true for an array of objects`, () => {
+ const actual = arrayContainsObjects([{}, {}]);
+ expect(actual).toBeTruthy();
+ });
+
+ it(`returns true for an array of objects and primitves`, () => {
+ const actual = arrayContainsObjects([{}, 'sdf']);
+ expect(actual).toBeTruthy();
+ });
+
+ it(`returns false for an array of null values`, () => {
+ const actual = arrayContainsObjects([null, null]);
+ expect(actual).toBeFalsy();
+ });
+
+ it(`returns false if no array is given`, () => {
+ const actual = arrayContainsObjects([null, null]);
+ expect(actual).toBeFalsy();
+ });
+});
diff --git a/public/components/explorer/docTable/detailTable/table_helper.tsx b/public/components/explorer/docTable/detailTable/table_helper.tsx
new file mode 100644
index 0000000000..b0b3229d07
--- /dev/null
+++ b/public/components/explorer/docTable/detailTable/table_helper.tsx
@@ -0,0 +1,18 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * Returns true if the given array contains at least 1 object
+ */
+export function arrayContainsObjects(value: unknown[]): boolean {
+ return Array.isArray(value) && value.some((v) => typeof v === 'object' && v !== null);
+}
+
+/**
+ * Removes markup added by kibana fields html formatter
+ */
+export function trimAngularSpan(text: string): string {
+ return text.replace(/^/, '').replace(/<\/span>$/, '');
+}
diff --git a/public/components/explorer/docTable/detailTable/table_row.tsx b/public/components/explorer/docTable/detailTable/table_row.tsx
new file mode 100644
index 0000000000..875c291916
--- /dev/null
+++ b/public/components/explorer/docTable/detailTable/table_row.tsx
@@ -0,0 +1,118 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import classNames from 'classnames';
+import React, { ReactNode } from 'react';
+// import { FieldMapping, DocViewFilterFn } from '../../doc_views/doc_views_types';
+import { DocViewTableRowBtnFilterAdd } from './table_row_btn_filter_add';
+import { DocViewTableRowBtnFilterRemove } from './table_row_btn_filter_remove';
+import { DocViewTableRowBtnToggleColumn } from './table_row_btn_toggle_column';
+import { DocViewTableRowBtnCollapse } from './table_row_btn_collapse';
+import { DocViewTableRowBtnFilterExists } from './table_row_btn_filter_exists';
+import { DocViewTableRowIconNoMapping } from './table_row_icon_no_mapping';
+import { DocViewTableRowIconUnderscore } from './table_row_icon_underscore';
+import { FieldName } from '../../../common/field_name/field_name';
+
+export interface FieldMapping {
+ filterable?: boolean;
+ scripted?: boolean;
+ rowCount?: number;
+ type: string;
+ name: string;
+}
+
+export type DocViewFilterFn = (
+ mapping: FieldMapping | string | undefined,
+ value: unknown,
+ mode: '+' | '-'
+) => void;
+
+export interface Props {
+ field: string;
+ fieldMapping?: FieldMapping;
+ fieldType: string;
+ displayNoMappingWarning: boolean;
+ displayUnderscoreWarning: boolean;
+ isCollapsible: boolean;
+ isColumnActive: boolean;
+ isCollapsed: boolean;
+ onToggleCollapse: () => void;
+ onFilter?: DocViewFilterFn;
+ onToggleColumn?: () => void;
+ value: string | ReactNode;
+ valueRaw: unknown;
+}
+
+export function DocViewTableRow({
+ field,
+ fieldMapping,
+ fieldType,
+ displayNoMappingWarning,
+ displayUnderscoreWarning,
+ isCollapsible,
+ isCollapsed,
+ isColumnActive,
+ onFilter,
+ onToggleCollapse,
+ onToggleColumn,
+ value,
+ valueRaw,
+}: Props) {
+ const valueClassName = classNames({
+ // eslint-disable-next-line @typescript-eslint/naming-convention
+ osdDocViewer__value: true,
+ 'truncate-by-height': isCollapsible && isCollapsed,
+ });
+
+ return (
+
+ {typeof onFilter === 'function' && (<>>
+ //
+ // onFilter(fieldMapping, valueRaw, '+')}
+ // />
+ // onFilter(fieldMapping, valueRaw, '-')}
+ // />
+ // {typeof onToggleColumn === 'function' && (
+ //
+ // )}
+ // onFilter('_exists_', field, '+')}
+ // scripted={fieldMapping && fieldMapping.scripted}
+ // />
+ //
+ )}
+
+
+
+
+ {isCollapsible && (
+
+ )}
+ {displayUnderscoreWarning && }
+ {displayNoMappingWarning && }
+
+
+
+ );
+}
diff --git a/public/components/explorer/docTable/detailTable/table_row_btn_collapse.tsx b/public/components/explorer/docTable/detailTable/table_row_btn_collapse.tsx
new file mode 100644
index 0000000000..8a1caaaa0d
--- /dev/null
+++ b/public/components/explorer/docTable/detailTable/table_row_btn_collapse.tsx
@@ -0,0 +1,31 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { i18n } from '@osd/i18n';
+import { EuiToolTip, EuiButtonIcon } from '@elastic/eui';
+
+export interface Props {
+ onClick: () => void;
+ isCollapsed: boolean;
+}
+
+export function DocViewTableRowBtnCollapse({ onClick, isCollapsed }: Props) {
+ const label = i18n.translate('discover.docViews.table.toggleFieldDetails', {
+ defaultMessage: 'Toggle field details',
+ });
+ return (
+
+ onClick()}
+ iconType={isCollapsed ? 'arrowRight' : 'arrowDown'}
+ iconSize={'s'}
+ />
+
+ );
+}
diff --git a/public/components/explorer/docTable/detailTable/table_row_btn_filter_add.tsx b/public/components/explorer/docTable/detailTable/table_row_btn_filter_add.tsx
new file mode 100644
index 0000000000..09a1944d90
--- /dev/null
+++ b/public/components/explorer/docTable/detailTable/table_row_btn_filter_add.tsx
@@ -0,0 +1,44 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { FormattedMessage } from '@osd/i18n/react';
+import { EuiToolTip, EuiButtonIcon } from '@elastic/eui';
+import { i18n } from '@osd/i18n';
+
+export interface Props {
+ onClick: () => void;
+ disabled: boolean;
+}
+
+export function DocViewTableRowBtnFilterAdd({ onClick, disabled = false }: Props) {
+ const tooltipContent = disabled ? (
+
+ ) : (
+
+ );
+
+ return (
+
+
+
+ );
+}
diff --git a/public/components/explorer/docTable/detailTable/table_row_btn_filter_exists.tsx b/public/components/explorer/docTable/detailTable/table_row_btn_filter_exists.tsx
new file mode 100644
index 0000000000..494aec4c10
--- /dev/null
+++ b/public/components/explorer/docTable/detailTable/table_row_btn_filter_exists.tsx
@@ -0,0 +1,56 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { FormattedMessage } from '@osd/i18n/react';
+import { EuiToolTip, EuiButtonIcon } from '@elastic/eui';
+import { i18n } from '@osd/i18n';
+
+export interface Props {
+ onClick: () => void;
+ disabled?: boolean;
+ scripted?: boolean;
+}
+
+export function DocViewTableRowBtnFilterExists({
+ onClick,
+ disabled = false,
+ scripted = false,
+}: Props) {
+ const tooltipContent = disabled ? (
+ scripted ? (
+
+ ) : (
+
+ )
+ ) : (
+
+ );
+
+ return (
+
+
+
+ );
+}
diff --git a/public/components/explorer/docTable/detailTable/table_row_btn_filter_remove.tsx b/public/components/explorer/docTable/detailTable/table_row_btn_filter_remove.tsx
new file mode 100644
index 0000000000..201fbf902e
--- /dev/null
+++ b/public/components/explorer/docTable/detailTable/table_row_btn_filter_remove.tsx
@@ -0,0 +1,44 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { FormattedMessage } from '@osd/i18n/react';
+import { EuiToolTip, EuiButtonIcon } from '@elastic/eui';
+import { i18n } from '@osd/i18n';
+
+export interface Props {
+ onClick: () => void;
+ disabled?: boolean;
+}
+
+export function DocViewTableRowBtnFilterRemove({ onClick, disabled = false }: Props) {
+ const tooltipContent = disabled ? (
+
+ ) : (
+
+ );
+
+ return (
+
+
+
+ );
+}
diff --git a/public/components/explorer/docTable/detailTable/table_row_btn_toggle_column.tsx b/public/components/explorer/docTable/detailTable/table_row_btn_toggle_column.tsx
new file mode 100644
index 0000000000..f9cc8a1cf0
--- /dev/null
+++ b/public/components/explorer/docTable/detailTable/table_row_btn_toggle_column.tsx
@@ -0,0 +1,54 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { FormattedMessage } from '@osd/i18n/react';
+import { EuiToolTip, EuiButtonIcon } from '@elastic/eui';
+import { i18n } from '@osd/i18n';
+
+export interface Props {
+ active: boolean;
+ disabled?: boolean;
+ onClick: () => void;
+}
+
+export function DocViewTableRowBtnToggleColumn({ onClick, active, disabled = false }: Props) {
+ if (disabled) {
+ return (
+
+ );
+ }
+ return (
+
+ }
+ >
+
+
+ );
+}
diff --git a/public/components/explorer/docTable/detailTable/table_row_icon_no_mapping.tsx b/public/components/explorer/docTable/detailTable/table_row_icon_no_mapping.tsx
new file mode 100644
index 0000000000..5991c30790
--- /dev/null
+++ b/public/components/explorer/docTable/detailTable/table_row_icon_no_mapping.tsx
@@ -0,0 +1,35 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+
+import React from 'react';
+import { EuiIconTip } from '@elastic/eui';
+import { i18n } from '@osd/i18n';
+
+export function DocViewTableRowIconNoMapping() {
+ const ariaLabel = i18n.translate('discover.docViews.table.noCachedMappingForThisFieldAriaLabel', {
+ defaultMessage: 'Warning',
+ });
+ const tooltipContent = i18n.translate(
+ 'discover.docViews.table.noCachedMappingForThisFieldTooltip',
+ {
+ defaultMessage:
+ 'No cached mapping for this field. Refresh field list from the Management > Index Patterns page',
+ }
+ );
+ return (
+
+ );
+}
diff --git a/public/components/explorer/docTable/detailTable/table_row_icon_underscore.tsx b/public/components/explorer/docTable/detailTable/table_row_icon_underscore.tsx
new file mode 100644
index 0000000000..f0bd9a5a6e
--- /dev/null
+++ b/public/components/explorer/docTable/detailTable/table_row_icon_underscore.tsx
@@ -0,0 +1,38 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { EuiIconTip } from '@elastic/eui';
+import { i18n } from '@osd/i18n';
+
+export function DocViewTableRowIconUnderscore() {
+ const ariaLabel = i18n.translate(
+ 'discover.docViews.table.fieldNamesBeginningWithUnderscoreUnsupportedAriaLabel',
+ {
+ defaultMessage: 'Warning',
+ }
+ );
+ const tooltipContent = i18n.translate(
+ 'discover.docViews.table.fieldNamesBeginningWithUnderscoreUnsupportedTooltip',
+ {
+ defaultMessage: 'Field names beginning with {underscoreSign} are not supported',
+ values: { underscoreSign: '_' },
+ }
+ );
+
+ return (
+
+ );
+}
diff --git a/public/components/explorer/docTable/docView.scss b/public/components/explorer/docTable/docView.scss
new file mode 100644
index 0000000000..fbe69b2a63
--- /dev/null
+++ b/public/components/explorer/docTable/docView.scss
@@ -0,0 +1,51 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+.selected-event-row {
+ background-color: rgba(5, 143, 244, 0.1);
+}
+
+.doc-flyout table {
+ width: 100%;
+ display: inline-block;
+ overflow-x: scroll;
+}
+
+.doc-flyout td.eui-textNoWrap {
+ padding-top: 1.25vh;
+}
+
+.doc-flyout td {
+ vertical-align: top;
+ padding: 0.5vh;
+}
+
+.compare-checkbox {
+ padding: 8px;
+}
+
+.header-button {
+ margin-right: 55px;
+}
+
+.cnt-picker {
+ width: 80px;
+ text-align: center;
+}
+
+.events-flyout-resize {
+ position: absolute;
+ right: 50px;
+ top: 17px;
+ z-index: 3;
+}
+
+.vertical-center {
+ margin-top: auto;
+}
+
+.trace-link {
+ margin-left: 5px;
+}
diff --git a/public/components/explorer/docTable/docViewRow.tsx b/public/components/explorer/docTable/docViewRow.tsx
new file mode 100644
index 0000000000..06a6bb3a1f
--- /dev/null
+++ b/public/components/explorer/docTable/docViewRow.tsx
@@ -0,0 +1,284 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import './docView.scss';
+import moment from 'moment';
+import React, { forwardRef, useImperativeHandle, useMemo, useState } from 'react';
+import { toPairs, uniqueId, has, forEach, isEqual } from 'lodash';
+import { EuiIcon, EuiLink } from '@elastic/eui';
+import { useEffect } from 'react';
+import { IExplorerFields, IField } from '../../../../common/types/explorer';
+import { DocFlyout } from './doc_flyout';
+import { HttpStart } from '../../../../../../src/core/public';
+import { OTEL_TRACE_ID, DATE_PICKER_FORMAT } from '../../../../common/constants/explorer';
+import { SurroundingFlyout } from './surrounding_flyout';
+import PPLService from '../../../services/requests/ppl';
+import { isValidTraceId } from '../utils';
+
+export interface IDocType {
+ [key: string]: string;
+}
+
+interface IDocViewRowProps {
+ http: HttpStart;
+ doc: IDocType;
+ docId: string;
+ selectedCols: IField[];
+ timeStampField: string;
+ explorerFields: IExplorerFields;
+ pplService: PPLService;
+ rawQuery: string;
+ onFlyoutOpen: (docId: string) => void;
+}
+
+export const DocViewRow = forwardRef((props: IDocViewRowProps, ref) => {
+ const {
+ http,
+ doc,
+ docId,
+ selectedCols,
+ timeStampField,
+ explorerFields,
+ pplService,
+ rawQuery,
+ onFlyoutOpen,
+ } = props;
+
+ const [detailsOpen, setDetailsOpen] = useState(false);
+ const [surroundingEventsOpen, setSurroundingEventsOpen] = useState(false);
+ const [openTraces, setOpenTraces] = useState(false);
+ const [flyoutToggleSize, setFlyoutToggleSize] = useState(true);
+
+ useImperativeHandle(ref, () => ({
+ closeAllFlyouts(openDocId: string) {
+ if (openDocId !== docId && (detailsOpen || surroundingEventsOpen)) {
+ setSurroundingEventsOpen(false);
+ setDetailsOpen(false);
+ }
+ },
+ }));
+
+ const getTdTmpl = (conf: { clsName: string; content: React.ReactDOM | string }) => {
+ const { clsName, content } = conf;
+ return (
+
+ {typeof content === 'boolean' ? String(content) : content}
+
+ );
+ };
+
+ const getDlTmpl = (conf: { doc: IDocType }, isFlyout: boolean) => {
+ const { doc } = conf;
+
+ return (
+
+
+
+ {toPairs(doc).map((entry: string[]) => {
+ const isTraceField = entry[0] === OTEL_TRACE_ID;
+ return (
+
+ {entry[0]}:
+
+
+ {isTraceField && isValidTraceId(entry[1]) && !isFlyout ? (
+ {entry[1]}
+ ) : (
+ entry[1]
+ )}
+
+
+
+ );
+ })}
+
+
+
+ );
+ };
+
+ const tracesFlyout = () => {
+ setOpenTraces(true);
+ if (!detailsOpen) toggleDetailOpen();
+ };
+
+ const getDiscoverSourceLikeDOM = (doc: IDocType, isFlyout: boolean) => {
+ return getDlTmpl({ doc }, isFlyout);
+ };
+
+ const toggleDetailOpen = () => {
+ if (surroundingEventsOpen) {
+ setSurroundingEventsOpen(false);
+ setDetailsOpen(false);
+ } else {
+ const newState = !detailsOpen;
+ setDetailsOpen(newState);
+ }
+ };
+
+ const getExpColapTd = () => {
+ return (
+
+ {
+ toggleDetailOpen();
+ }}
+ >
+ {detailsOpen || surroundingEventsOpen ? (
+
+ ) : (
+
+ )}
+
+
+ );
+ };
+
+ const getTds = (doc: IDocType, selectedCols: IField[], isFlyout: boolean) => {
+ const cols = [];
+ const fieldClsName = 'osdDocTableCell__dataField eui-textBreakAll eui-textBreakWord';
+ const timestampClsName = 'eui-textNoWrap';
+ // No field is selected
+ if (!selectedCols || selectedCols.length === 0) {
+ if (has(doc, timeStampField)) {
+ cols.push(
+ getTdTmpl({
+ clsName: timestampClsName,
+ content: moment.utc(doc[timeStampField]).local().format(DATE_PICKER_FORMAT),
+ })
+ );
+ }
+ const _sourceLikeDOM = getDiscoverSourceLikeDOM(doc, isFlyout);
+ cols.push(
+ getTdTmpl({
+ clsName: fieldClsName,
+ content: _sourceLikeDOM,
+ })
+ );
+ } else {
+ // Has at least one field selected
+ const filteredDoc = {};
+ forEach(selectedCols, (selCol) => {
+ if (has(doc, selCol.name)) {
+ filteredDoc[selCol.name] = doc[selCol.name];
+ }
+ });
+ forEach(filteredDoc, (val, key) => {
+ cols.push(
+ getTdTmpl({
+ clsName: fieldClsName,
+ content: isEqual(key, timeStampField)
+ ? moment.utc(val).local().format(DATE_PICKER_FORMAT)
+ : val,
+ })
+ );
+ });
+ }
+
+ // Add detail toggling column
+ cols.unshift(getExpColapTd());
+ return cols;
+ };
+
+ const memorizedTds = useMemo(() => {
+ return getTds(doc, selectedCols, false);
+ }, [doc, selectedCols, detailsOpen, surroundingEventsOpen]);
+
+ const memorizedDocFlyout = useMemo(() => {
+ return (
+
+ );
+ }, [
+ http,
+ detailsOpen,
+ doc,
+ timeStampField,
+ selectedCols,
+ explorerFields,
+ openTraces,
+ rawQuery,
+ flyoutToggleSize,
+ ]);
+
+ const memorizedSurroundingFlyout = useMemo(() => {
+ return (
+
+ );
+ }, [
+ http,
+ detailsOpen,
+ doc,
+ timeStampField,
+ selectedCols,
+ explorerFields,
+ openTraces,
+ pplService,
+ rawQuery,
+ selectedCols,
+ flyoutToggleSize,
+ ]);
+
+ let flyout;
+ if (detailsOpen) {
+ flyout = memorizedDocFlyout;
+ }
+
+ if (surroundingEventsOpen) {
+ flyout = memorizedSurroundingFlyout;
+ }
+
+ useEffect(() => {
+ if (detailsOpen) {
+ onFlyoutOpen(docId);
+ }
+ }, [detailsOpen]);
+
+ return (
+ <>
+
+ {memorizedTds}
+
+ {flyout}
+ >
+ );
+});
diff --git a/public/components/explorer/docTable/docViewer.tsx b/public/components/explorer/docTable/docViewer.tsx
new file mode 100644
index 0000000000..240e7fdcea
--- /dev/null
+++ b/public/components/explorer/docTable/docViewer.tsx
@@ -0,0 +1,121 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useEffect, useMemo, useState } from 'react';
+import _ from 'lodash';
+import {
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiLink,
+ EuiPanel,
+ EuiTabbedContent,
+ EuiTabbedContentTab,
+} from '@elastic/eui';
+import { DocViewTable } from './detailTable/docDetailTable';
+import { JsonCodeBlock } from './json_code_block/json_code_block';
+import { IDocType } from './docViewRow';
+import { HttpSetup } from '../../../../../../src/core/public';
+import { TraceBlock } from './trace_block/trace_block';
+import { OTEL_TRACE_ID } from '../../../../common/constants/explorer';
+import { isValidTraceId } from '../utils';
+
+interface IDocViewerProps {
+ http: HttpSetup;
+ hit: IDocType;
+ openTraces: boolean;
+}
+
+export function DocViewer(props: IDocViewerProps) {
+ const [curSelectedTab, setCurSelectedTab] = useState(null);
+ const [logTraceId, setLogTraceId] = useState('');
+ const [tracesLink, setTracesLink] = useState(<>>);
+
+ // can be passed in later
+ const getTabList = () => {
+ return [
+ {
+ id: _.uniqueId('doc_viewer_tab_'),
+ name: 'Table',
+ component: (tabProps: any) => (
+ {}}
+ onAddColumn={() => {}}
+ onRemoveColumn={() => {}}
+ {...tabProps}
+ />
+ ),
+ otherProps: {},
+ },
+ {
+ id: _.uniqueId('doc_viewer_tab_'),
+ name: 'JSON',
+ component: (tabProps: any) => ,
+ otherProps: {},
+ },
+ {
+ id: _.uniqueId('doc_viewer_tab_'),
+ name: (
+ <>
+ Traces
+ {tracesLink}
+ >
+ ),
+
+ component: (tabProps: any) => ,
+ otherProps: {},
+ },
+ ];
+ };
+
+ const tabs = useMemo(() => {
+ return getTabList().map((tab) => {
+ const Component = tab.component;
+ return {
+ id: tab.id,
+ name: tab.name,
+
+ content: (
+
+
+
+ {' '}
+
+
+
+ ),
+ };
+ });
+ }, [props.hit, logTraceId, tracesLink]);
+
+ if (!tabs.length) {
+ // There there's a minimum of 2 tabs active in Discover.
+ // This condition takes care of unit tests with 0 tabs.
+ return null;
+ }
+
+ useEffect(() => {
+ const traceId = props.hit.hasOwnProperty(OTEL_TRACE_ID) ? props.hit[OTEL_TRACE_ID] : '';
+ setLogTraceId(traceId);
+ if (traceId !== '' && isValidTraceId(traceId))
+ setTracesLink(
+
+ );
+ }, []);
+
+ return (
+
+ setCurSelectedTab(selectedTab)}
+ />
+
+ );
+}
diff --git a/public/components/explorer/docTable/doc_flyout.tsx b/public/components/explorer/docTable/doc_flyout.tsx
new file mode 100644
index 0000000000..fdff39ea39
--- /dev/null
+++ b/public/components/explorer/docTable/doc_flyout.tsx
@@ -0,0 +1,149 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import './docView.scss';
+import React from 'react';
+import {
+ EuiButton,
+ EuiButtonIcon,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiFlyoutBody,
+ EuiFlyoutHeader,
+ EuiTitle,
+ EuiToolTip,
+} from '@elastic/eui';
+import moment from 'moment';
+import { FlyoutContainers } from '../../common/flyout_containers';
+import { IDocType } from './docViewRow';
+import { DocViewer } from './docViewer';
+import { uiSettingsService } from '../../../../common/utils';
+import { IExplorerFields } from '../../../../common/types/explorer';
+import { getHeaders, populateDataGrid } from '../utils';
+import { DEFAULT_COLUMNS } from '../../../../common/constants/explorer';
+import { HttpSetup } from '../../../../../../src/core/public';
+import { PPL_STATS_REGEX } from '../../../../common/constants/shared';
+
+interface Props {
+ http: HttpSetup;
+ detailsOpen: boolean;
+ setDetailsOpen: React.Dispatch>;
+ doc: IDocType;
+ timeStampField: string;
+ memorizedTds: JSX.Element[];
+ explorerFields: IExplorerFields;
+ openTraces: boolean;
+ rawQuery: string;
+ toggleSize: boolean;
+ setToggleSize: React.Dispatch>;
+ setOpenTraces: React.Dispatch>;
+ setSurroundingEventsOpen: React.Dispatch>;
+}
+
+export const DocFlyout = ({
+ http,
+ detailsOpen,
+ setDetailsOpen,
+ doc,
+ timeStampField,
+ memorizedTds,
+ explorerFields,
+ openTraces,
+ rawQuery,
+ toggleSize,
+ setToggleSize,
+ setOpenTraces,
+ setSurroundingEventsOpen,
+}: Props) => {
+ const closeFlyout = () => {
+ setDetailsOpen(false);
+ setOpenTraces(false);
+ };
+
+ const openSurroundingFlyout = () => {
+ setSurroundingEventsOpen(true);
+ closeFlyout();
+ };
+
+ const flyoutHeader = (
+
+
+
+
+
+ {doc.hasOwnProperty(timeStampField)
+ ? `Event: ${moment(doc[timeStampField]).format(
+ uiSettingsService.get('dateFormat')
+ )}`
+ : `Event Details`}
+
+
+
+
+ {
+ setToggleSize((isOn) => !isOn);
+ }}
+ />
+
+
+ Cannot view surrounding events with `stats` command in PPL query
+ ) : !doc.hasOwnProperty(timeStampField) ? (
+ Cannot view surrounding events without time field in query response
+ ) : (
+ View surrounding events based on timestamp
+ )
+ }
+ >
+
+ View surrounding events
+
+
+
+
+
+ );
+
+ const flyoutBody = (
+
+ {populateDataGrid(
+ explorerFields,
+ getHeaders(explorerFields.queriedFields, DEFAULT_COLUMNS.slice(1), true),
+ {memorizedTds} ,
+ getHeaders(explorerFields.selectedFields, DEFAULT_COLUMNS.slice(1), true),
+ {memorizedTds}
+ )}
+
+
+ );
+
+ const flyoutFooter = <>>;
+
+ return (
+
+ );
+};
diff --git a/public/components/explorer/docTable/index.ts b/public/components/explorer/docTable/index.ts
new file mode 100644
index 0000000000..13b7318faa
--- /dev/null
+++ b/public/components/explorer/docTable/index.ts
@@ -0,0 +1,7 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export * from './docViewer';
+export * from './docViewRow';
\ No newline at end of file
diff --git a/public/components/explorer/docTable/json_code_block/__tests__/__snapshots__/json_code_block.test.tsx.snap b/public/components/explorer/docTable/json_code_block/__tests__/__snapshots__/json_code_block.test.tsx.snap
new file mode 100644
index 0000000000..fd63e4c24d
--- /dev/null
+++ b/public/components/explorer/docTable/json_code_block/__tests__/__snapshots__/json_code_block.test.tsx.snap
@@ -0,0 +1,142 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Doc viewer JSON block component Renders JSON block component 1`] = `
+
+
+
+
+ {
+ "Carrier": "JetBeats",
+ "avg(FlightDelayMin)": "45.957544288332315"
+}
+
+ }
+ >
+ {
+ "Carrier": "JetBeats",
+ "avg(FlightDelayMin)": "45.957544288332315"
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/explorer/docTable/json_code_block/__tests__/json_code_block.test.tsx b/public/components/explorer/docTable/json_code_block/__tests__/json_code_block.test.tsx
new file mode 100644
index 0000000000..c79a7611f0
--- /dev/null
+++ b/public/components/explorer/docTable/json_code_block/__tests__/json_code_block.test.tsx
@@ -0,0 +1,34 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { JsonCodeBlock } from '../json_code_block';
+
+describe('Doc viewer JSON block component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders JSON block component', async () => {
+
+ const hit = {
+ 'Carrier': 'JetBeats',
+ 'avg(FlightDelayMin)': '45.957544288332315'
+ };
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
\ No newline at end of file
diff --git a/public/components/explorer/docTable/json_code_block/json_code_block.tsx b/public/components/explorer/docTable/json_code_block/json_code_block.tsx
new file mode 100644
index 0000000000..a687cdb49f
--- /dev/null
+++ b/public/components/explorer/docTable/json_code_block/json_code_block.tsx
@@ -0,0 +1,20 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { EuiCodeBlock } from '@elastic/eui';
+import { i18n } from '@osd/i18n';
+import { IDocType } from '../docViewRow';
+
+export function JsonCodeBlock({ hit }: { hit: IDocType }) {
+ const label = i18n.translate('discover.docViews.json.codeEditorAriaLabel', {
+ defaultMessage: 'Read only JSON view of an elasticsearch document',
+ });
+ return (
+
+ {JSON.stringify(hit, null, 2)}
+
+ );
+}
diff --git a/public/components/explorer/docTable/surrounding_flyout.tsx b/public/components/explorer/docTable/surrounding_flyout.tsx
new file mode 100644
index 0000000000..5ca0701dc8
--- /dev/null
+++ b/public/components/explorer/docTable/surrounding_flyout.tsx
@@ -0,0 +1,279 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import './docView.scss';
+import React, { useEffect, useState } from 'react';
+import {
+ EuiButton,
+ EuiButtonEmpty,
+ EuiButtonIcon,
+ EuiCallOut,
+ EuiFieldNumber,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiFlyoutBody,
+ EuiFlyoutHeader,
+ EuiFormRow,
+ EuiSpacer,
+ EuiText,
+ EuiTitle,
+ EuiToolTip,
+} from '@elastic/eui';
+import { FlyoutContainers } from '../../common/flyout_containers';
+import { IDocType } from './docViewRow';
+import { IExplorerFields, IField } from '../../../../common/types/explorer';
+import { getHeaders, fetchSurroundingData, rangeNumDocs, populateDataGrid } from '../utils';
+import { DEFAULT_COLUMNS } from '../../../../common/constants/explorer';
+import { HttpSetup } from '../../../../../../src/core/public';
+import PPLService from '../../../services/requests/ppl';
+
+interface Props {
+ http: HttpSetup;
+ detailsOpen: boolean;
+ setDetailsOpen: React.Dispatch>;
+ doc: IDocType;
+ timeStampField: string;
+ memorizedTds: JSX.Element[];
+ explorerFields: IExplorerFields;
+ openTraces: boolean;
+ setOpenTraces: React.Dispatch>;
+ setSurroundingEventsOpen: React.Dispatch>;
+ pplService: PPLService;
+ rawQuery: string;
+ selectedCols: IField[];
+ getTds: (doc: IDocType, selectedCols: IField[], isFlyout: boolean) => JSX.Element[];
+ toggleSize: boolean;
+ setToggleSize: React.Dispatch>;
+}
+
+export const SurroundingFlyout = ({
+ http,
+ detailsOpen,
+ setDetailsOpen,
+ doc,
+ timeStampField,
+ memorizedTds,
+ explorerFields,
+ openTraces,
+ setOpenTraces,
+ setSurroundingEventsOpen,
+ pplService,
+ rawQuery,
+ selectedCols,
+ getTds,
+ toggleSize,
+ setToggleSize,
+}: Props) => {
+ const [numNewEvents, setNumNewEvents] = useState(5);
+ const [valueOldEvents, setNumOldEvents] = useState(5);
+ const [loadingNewEvents, setLoadingNewEvents] = useState(false);
+ const [loadingOldEvents, setLoadingOldEvents] = useState(false);
+ const [oldEventsError, setOldEventsError] = useState('');
+ const [newEventsError, setNewEventsError] = useState('');
+ const [newEventsData, setNewEventsData] = useState([[]]);
+ const [oldEventsData, setOldEventsData] = useState([[]]);
+
+ const closeFlyout = () => {
+ setDetailsOpen(false);
+ setOpenTraces(false);
+ setSurroundingEventsOpen(false);
+ };
+
+ const openDetailsFlyout = () => {
+ setDetailsOpen(true);
+ setOpenTraces(false);
+ setSurroundingEventsOpen(false);
+ };
+
+ const loadData = async (typeOfDocs: 'new' | 'old', value: number) => {
+ const numDocs = rangeNumDocs(value);
+ let resultCount = 0;
+ if (typeOfDocs === 'new') {
+ resultCount = await fetchSurroundingData(
+ pplService,
+ rawQuery,
+ timeStampField,
+ doc[timeStampField],
+ numDocs,
+ 'new',
+ setNewEventsData,
+ setNewEventsError,
+ setLoadingNewEvents,
+ selectedCols,
+ getTds
+ );
+ setNumNewEvents(resultCount);
+ } else {
+ resultCount = await fetchSurroundingData(
+ pplService,
+ rawQuery,
+ timeStampField,
+ doc[timeStampField],
+ numDocs,
+ 'old',
+ setOldEventsData,
+ setOldEventsError,
+ setLoadingOldEvents,
+ selectedCols,
+ getTds
+ );
+ setNumOldEvents(resultCount);
+ }
+ };
+
+ const loadButton = (typeOfDocs: 'new' | 'old') => {
+ typeOfDocs === 'new'
+ ? loadData(typeOfDocs, numNewEvents + 5)
+ : loadData(typeOfDocs, valueOldEvents + 5);
+ };
+
+ const handleKeyDown = (
+ event: React.KeyboardEvent,
+ typeOfDocs: 'new' | 'old'
+ ) => {
+ if (event.key === 'Enter') {
+ loadData(typeOfDocs, typeOfDocs === 'new' ? numNewEvents : valueOldEvents);
+ }
+ };
+
+ const onChangeNewEvents = (e: React.ChangeEvent) => {
+ setNumNewEvents(parseInt(e.target.value));
+ };
+
+ const onChangeOldEvents = (e: React.ChangeEvent) => {
+ setNumOldEvents(parseInt(e.target.value));
+ };
+
+ const flyoutHeader = (
+
+
+
+
+
+ View surrounding events
+
+
+
+
+ {
+ setToggleSize((isOn) => !isOn);
+ }}
+ />
+
+
+
+ View event details
+
+
+
+
+ );
+
+ const getInputForm = (
+ iconType: string,
+ onChange: React.ChangeEventHandler,
+ value: number,
+ typeOfDocs: 'new' | 'old'
+ ) => {
+ return (
+
+
+
+ loadButton(typeOfDocs)}
+ iconType={iconType}
+ >
+ Load
+
+
+
+
+
+ onChange(e)}
+ aria-label={typeOfDocs === 'new' ? 'fetch newer events' : 'fetch older events'}
+ min={0}
+ max={10000}
+ onKeyDown={(e) => handleKeyDown(e, typeOfDocs)}
+ />
+
+
+
+
+ {typeOfDocs === 'new' ? 'newer' : 'older'} events
+
+
+
+ );
+ };
+
+ const flyoutBody = (
+
+ {getInputForm('arrowUp', onChangeNewEvents, numNewEvents, 'new')}
+
+
+ {newEventsError !== '' && (
+
+ )}
+
+ {populateDataGrid(
+ explorerFields,
+ getHeaders(explorerFields.queriedFields, DEFAULT_COLUMNS.slice(1), true),
+ <>
+ {newEventsData}
+ {memorizedTds}
+ {oldEventsData}
+ >,
+ getHeaders(explorerFields.selectedFields, DEFAULT_COLUMNS.slice(1), true),
+ <>
+ {newEventsData}
+ {memorizedTds}
+ {oldEventsData}
+ >
+ )}
+
+ {oldEventsError !== '' && (
+
+ )}
+
+
+ {getInputForm('arrowDown', onChangeOldEvents, valueOldEvents, 'old')}
+
+ );
+
+ const flyoutFooter = <>>;
+
+ useEffect(() => {
+ loadData('new', 5);
+ loadData('old', 5);
+ }, []);
+
+ return (
+
+ );
+};
diff --git a/public/components/explorer/docTable/trace_block/trace_block.tsx b/public/components/explorer/docTable/trace_block/trace_block.tsx
new file mode 100644
index 0000000000..6227666e8d
--- /dev/null
+++ b/public/components/explorer/docTable/trace_block/trace_block.tsx
@@ -0,0 +1,47 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { TraceDetailRender } from '../../../application_analytics/components/flyout_components/trace_detail_render';
+import React, { useEffect } from 'react';
+import { HttpSetup } from '../../../../../../../src/core/public';
+import { EuiCallOut, EuiLink } from '@elastic/eui';
+import { TRACE_ANALYTICS_DOCUMENTATION_LINK } from '../../../../../common/constants/trace_analytics';
+import {
+ OPEN_TELEMETRY_LOG_CORRELATION_LINK,
+ OTEL_TRACE_ID,
+} from '../../../../../common/constants/explorer';
+import { IDocType } from '../docViewRow';
+import { isValidTraceId } from '../../utils';
+
+interface props {
+ http: HttpSetup;
+ hit: IDocType;
+ logTraceId: string;
+}
+
+export const TraceBlock = ({ http, hit, logTraceId }: props) => {
+ if (logTraceId === '' || !isValidTraceId(logTraceId)) {
+ return (
+ <>
+
+ Please make sure to add "{OTEL_TRACE_ID}" field to the logs.
+
+ More info on{' '}
+
+ Trace Analytics
+
+
+ More info on{' '}
+
+ Log Correlation
+
+
+
+ >
+ );
+ }
+
+ return ;
+};
diff --git a/public/components/explorer/event_analytics.tsx b/public/components/explorer/event_analytics.tsx
new file mode 100644
index 0000000000..7690e474d4
--- /dev/null
+++ b/public/components/explorer/event_analytics.tsx
@@ -0,0 +1,121 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { EuiGlobalToastList } from '@elastic/eui';
+import { Toast } from '@elastic/eui/src/components/toast/global_toast_list';
+import { EmptyTabParams } from 'common/types/explorer';
+import { isEmpty } from 'lodash';
+import React, { ReactChild, useState } from 'react';
+import { HashRouter, Route, Switch, useHistory } from 'react-router-dom';
+import { RAW_QUERY } from '../../../common/constants/explorer';
+import { ObservabilitySideBar } from '../common/side_nav';
+import { Home as EventExplorerHome } from './home';
+import { LogExplorer } from './log_explorer';
+
+export const EventAnalytics = ({
+ chrome,
+ parentBreadcrumbs,
+ pplService,
+ dslService,
+ savedObjects,
+ timestampUtils,
+ http,
+ notifications,
+ ...props
+}: any) => {
+ const history = useHistory();
+ const [toasts, setToasts] = useState([]);
+
+ const eventAnalyticsBreadcrumb = {
+ text: 'Event analytics',
+ href: '#/event_analytics',
+ };
+
+ const setToast = (title: string, color = 'success', text?: ReactChild, side?: string) => {
+ if (!text) text = '';
+ setToasts([...toasts, { id: new Date().toISOString(), title, text, color } as Toast]);
+ };
+
+ const getExistingEmptyTab = ({ tabIds, queries, explorerData }: EmptyTabParams) => {
+ let emptyTabId = '';
+ for (let i = 0; i < tabIds!.length; i++) {
+ const tid = tabIds![i];
+ if (isEmpty(queries[tid][RAW_QUERY]) && isEmpty(explorerData[tid])) {
+ emptyTabId = tid;
+ break;
+ }
+ }
+ return emptyTabId;
+ };
+
+ return (
+ <>
+ {
+ setToasts(toasts.filter((toast) => toast.id !== removedToast.id));
+ }}
+ toastLifeTimeMs={6000}
+ />
+
+
+ {
+ chrome.setBreadcrumbs([
+ ...parentBreadcrumbs,
+ eventAnalyticsBreadcrumb,
+ {
+ text: 'Explorer',
+ href: `#/event_analytics/explorer`,
+ },
+ ]);
+ return (
+
+ );
+ }}
+ />
+ {
+ chrome.setBreadcrumbs([
+ ...parentBreadcrumbs,
+ eventAnalyticsBreadcrumb,
+ {
+ text: 'Home',
+ href: '#/event_analytics',
+ },
+ ]);
+ return (
+
+
+
+ );
+ }}
+ />
+
+
+ >
+ );
+};
diff --git a/public/components/explorer/explorer.scss b/public/components/explorer/explorer.scss
new file mode 100644
index 0000000000..423e226e39
--- /dev/null
+++ b/public/components/explorer/explorer.scss
@@ -0,0 +1,17 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+ .liveStream {
+ margin : 8px;
+ height: 40px;
+ align-items: center;
+ justify-content: center;
+ flex-direction: row;
+ display: flex;
+ flex-grow: 1;
+ vertical-align: baseline;
+ }
+
+
\ No newline at end of file
diff --git a/public/components/explorer/explorer.tsx b/public/components/explorer/explorer.tsx
new file mode 100644
index 0000000000..27cb168fa2
--- /dev/null
+++ b/public/components/explorer/explorer.tsx
@@ -0,0 +1,1176 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable react-hooks/exhaustive-deps */
+
+import './explorer.scss';
+import React, { useState, useMemo, useEffect, useRef, useCallback, ReactElement } from 'react';
+import { batch, useDispatch, useSelector } from 'react-redux';
+import { isEmpty, cloneDeep, isEqual, has, reduce } from 'lodash';
+import { FormattedMessage } from '@osd/i18n/react';
+import { EuiLoadingSpinner, EuiSpacer } from '@elastic/eui';
+import {
+ EuiText,
+ EuiButtonIcon,
+ EuiTabbedContent,
+ EuiTabbedContentTab,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiLink,
+ EuiContextMenuItem,
+} from '@elastic/eui';
+import dateMath from '@elastic/datemath';
+import classNames from 'classnames';
+import { Search } from '../common/search/search';
+import { CountDistribution } from './visualizations/count_distribution';
+import { DataGrid } from './data_grid';
+import { Sidebar } from './sidebar';
+import { NoResults } from './no_results';
+import { HitsCounter } from './hits_counter/hits_counter';
+import { TimechartHeader } from './timechart_header';
+import { ExplorerVisualizations } from './visualizations';
+import { IField, IQueryTab, IDefaultTimestampState } from '../../../common/types/explorer';
+import {
+ TAB_CHART_TITLE,
+ TAB_EVENT_TITLE,
+ RAW_QUERY,
+ SELECTED_DATE_RANGE,
+ SELECTED_FIELDS,
+ SELECTED_TIMESTAMP,
+ AVAILABLE_FIELDS,
+ TIME_INTERVAL_OPTIONS,
+ SAVED_QUERY,
+ SAVED_VISUALIZATION,
+ SAVED_OBJECT_ID,
+ SAVED_OBJECT_TYPE,
+ NEW_TAB,
+ TAB_CREATED_TYPE,
+ EVENT_ANALYTICS_DOCUMENTATION_URL,
+ TAB_EVENT_ID,
+ TAB_CHART_ID,
+ DEFAULT_AVAILABILITY_QUERY,
+ DATE_PICKER_FORMAT,
+} from '../../../common/constants/explorer';
+import {
+ PPL_STATS_REGEX,
+ PPL_NEWLINE_REGEX,
+ LIVE_OPTIONS,
+ LIVE_END_TIME,
+} from '../../../common/constants/shared';
+import { getIndexPatternFromRawQuery, preprocessQuery, buildQuery } from '../../../common/utils';
+import { useFetchEvents, useFetchVisualizations } from './hooks';
+import { changeQuery, changeDateRange, selectQueries } from './slices/query_slice';
+import { selectQueryResult } from './slices/query_result_slice';
+import { selectFields, updateFields, sortFields } from './slices/field_slice';
+import { updateTabName } from './slices/query_tab_slice';
+import { selectCountDistribution } from './slices/count_distribution_slice';
+import { selectExplorerVisualization } from './slices/visualization_slice';
+import {
+ selectVisualizationConfig,
+ change as changeVisualizationConfig,
+} from './slices/viualization_config_slice';
+import { change as updateVizConfig } from './slices/viualization_config_slice';
+import { IExplorerProps, IVisualizationContainerProps } from '../../../common/types/explorer';
+import { TabContext } from './hooks';
+import { getVizContainerProps } from '../visualizations/charts/helpers';
+import { parseGetSuggestions, onItemSelect } from '../common/search/autocomplete_logic';
+import { formatError } from './utils';
+import { sleep } from '../common/live_tail/live_tail_button';
+
+const TYPE_TAB_MAPPING = {
+ [SAVED_QUERY]: TAB_EVENT_ID,
+ [SAVED_VISUALIZATION]: TAB_CHART_ID,
+};
+
+export const Explorer = ({
+ pplService,
+ dslService,
+ tabId,
+ savedObjects,
+ timestampUtils,
+ setToast,
+ http,
+ history,
+ notifications,
+ savedObjectId,
+ curSelectedTabId,
+ searchBarConfigs,
+ appId = '',
+ appBaseQuery = '',
+ addVisualizationToPanel,
+ startTime,
+ endTime,
+ setStartTime,
+ setEndTime,
+ callback,
+ callbackInApp,
+}: IExplorerProps) => {
+ const dispatch = useDispatch();
+ const requestParams = { tabId };
+ const { getLiveTail, getEvents, getAvailableFields, isEventsLoading } = useFetchEvents({
+ pplService,
+ requestParams,
+ });
+ const { getVisualizations, getCountVisualizations, isVisLoading } = useFetchVisualizations({
+ pplService,
+ requestParams,
+ });
+ const appLogEvents = tabId.startsWith('application-analytics-tab');
+ const query = useSelector(selectQueries)[tabId];
+ const explorerData = useSelector(selectQueryResult)[tabId];
+ const explorerFields = useSelector(selectFields)[tabId];
+ const countDistribution = useSelector(selectCountDistribution)[tabId];
+ const explorerVisualizations = useSelector(selectExplorerVisualization)[tabId];
+ const userVizConfigs = useSelector(selectVisualizationConfig)[tabId] || {};
+ const [selectedContentTabId, setSelectedContentTab] = useState(TAB_EVENT_ID);
+ const [selectedCustomPanelOptions, setSelectedCustomPanelOptions] = useState([]);
+ const [selectedPanelName, setSelectedPanelName] = useState('');
+ const [curVisId, setCurVisId] = useState('bar');
+ const [prevIndex, setPrevIndex] = useState('');
+ const [isPanelTextFieldInvalid, setIsPanelTextFieldInvalid] = useState(false);
+ const [isSidebarClosed, setIsSidebarClosed] = useState(false);
+ const [timeIntervalOptions, setTimeIntervalOptions] = useState(TIME_INTERVAL_OPTIONS);
+ const [isOverridingTimestamp, setIsOverridingTimestamp] = useState(false);
+ const [tempQuery, setTempQuery] = useState(query[RAW_QUERY]);
+ const [isLiveTailPopoverOpen, setIsLiveTailPopoverOpen] = useState(false);
+ const [isLiveTailOn, setIsLiveTailOn] = useState(false);
+ const [liveTailTabId, setLiveTailTabId] = useState(TAB_EVENT_ID);
+ const [liveTailName, setLiveTailName] = useState('Live');
+ const [liveHits, setLiveHits] = useState(0);
+ const [browserTabFocus, setBrowserTabFocus] = useState(true);
+ const [liveTimestamp, setLiveTimestamp] = useState(DATE_PICKER_FORMAT);
+ const [triggerAvailability, setTriggerAvailability] = useState(false);
+
+ const queryRef = useRef();
+ const appBasedRef = useRef('');
+ appBasedRef.current = appBaseQuery;
+ const selectedPanelNameRef = useRef('');
+ const explorerFieldsRef = useRef();
+ const isLiveTailOnRef = useRef(false);
+ const liveTailTabIdRef = useRef('');
+ const liveTailNameRef = useRef('Live');
+ queryRef.current = query;
+ selectedPanelNameRef.current = selectedPanelName;
+ explorerFieldsRef.current = explorerFields;
+ isLiveTailOnRef.current = isLiveTailOn;
+ liveTailTabIdRef.current = liveTailTabId;
+ liveTailNameRef.current = liveTailName;
+
+ let minInterval = 'y';
+ const findAutoInterval = (start: string = '', end: string = '') => {
+ if (start?.length === 0 || end?.length === 0 || start === end)
+ return ['d', [...TIME_INTERVAL_OPTIONS]];
+ const momentStart = dateMath.parse(start)!;
+ const momentEnd = dateMath.parse(end)!;
+ const diffSeconds = momentEnd.unix() - momentStart.unix();
+
+ // less than 1 second
+ if (diffSeconds <= 1) minInterval = 'ms';
+ // less than 2 minutes
+ else if (diffSeconds <= 60 * 2) minInterval = 's';
+ // less than 2 hours
+ else if (diffSeconds <= 3600 * 2) minInterval = 'm';
+ // less than 2 days
+ else if (diffSeconds <= 86400 * 2) minInterval = 'h';
+ // less than 1 month
+ else if (diffSeconds <= 86400 * 31) minInterval = 'd';
+ // less than 3 months
+ else if (diffSeconds <= 86400 * 93) minInterval = 'w';
+ // less than 1 year
+ else if (diffSeconds <= 86400 * 366) minInterval = 'M';
+
+ setTimeIntervalOptions([
+ { text: 'Auto', value: 'auto_' + minInterval },
+ ...TIME_INTERVAL_OPTIONS,
+ ]);
+ };
+
+ useEffect(() => {
+ document.addEventListener('visibilitychange', function () {
+ if (document.hidden) {
+ setBrowserTabFocus(false);
+ } else {
+ setBrowserTabFocus(true);
+ }
+ });
+ });
+
+ const composeFinalQuery = (
+ curQuery: any,
+ startingTime: string,
+ endingTime: string,
+ timeField: string,
+ isLiveQuery: boolean
+ ) => {
+ const fullQuery = buildQuery(appBasedRef.current, curQuery![RAW_QUERY]);
+ if (isEmpty(fullQuery)) return '';
+ return preprocessQuery({
+ rawQuery: fullQuery,
+ startTime: startingTime,
+ endTime: endingTime,
+ timeField,
+ isLiveQuery,
+ });
+ };
+
+ const getSavedDataById = async (objectId: string) => {
+ // load saved query/visualization if object id exists
+ await savedObjects
+ .fetchSavedObjects({
+ objectId,
+ })
+ .then(async (res) => {
+ const savedData = res.observabilityObjectList[0];
+ const isSavedQuery = has(savedData, SAVED_QUERY);
+ const savedType = isSavedQuery ? SAVED_QUERY : SAVED_VISUALIZATION;
+ const objectData = isSavedQuery ? savedData.savedQuery : savedData.savedVisualization;
+ const currQuery = appLogEvents
+ ? objectData?.query.replace(appBaseQuery + '| ', '')
+ : objectData?.query || '';
+
+ if (appLogEvents) {
+ if (objectData?.selected_date_range?.start && objectData?.selected_date_range?.end) {
+ setStartTime(objectData.selected_date_range.start);
+ setEndTime(objectData.selected_date_range.end);
+ }
+ }
+
+ // update redux
+ batch(async () => {
+ await dispatch(
+ changeQuery({
+ tabId,
+ query: {
+ [RAW_QUERY]: currQuery,
+ [SELECTED_TIMESTAMP]: objectData?.selected_timestamp?.name || 'timestamp',
+ [SAVED_OBJECT_ID]: objectId,
+ [SAVED_OBJECT_TYPE]: savedType,
+ [SELECTED_DATE_RANGE]:
+ objectData?.selected_date_range?.start && objectData?.selected_date_range?.end
+ ? [objectData.selected_date_range.start, objectData.selected_date_range.end]
+ : ['now-15m', 'now'],
+ },
+ })
+ );
+ await dispatch(
+ updateFields({
+ tabId,
+ data: {
+ [SELECTED_FIELDS]: [...objectData?.selected_fields?.tokens],
+ },
+ })
+ );
+ await dispatch(
+ updateTabName({
+ tabId,
+ tabName: objectData.name,
+ })
+ );
+ // fill saved user configs
+ if (objectData?.type) {
+ await dispatch(
+ updateVizConfig({
+ tabId,
+ vizId: objectData?.type,
+ data: JSON.parse(objectData.user_configs),
+ })
+ );
+ }
+ });
+
+ // update UI state with saved data
+ setSelectedPanelName(objectData?.name || '');
+ setCurVisId(objectData?.type || 'bar');
+ setTempQuery((staleTempQuery: string) => {
+ return appLogEvents ? currQuery : objectData?.query || staleTempQuery;
+ });
+ const tabToBeFocused = isSavedQuery
+ ? TYPE_TAB_MAPPING[SAVED_QUERY]
+ : TYPE_TAB_MAPPING[SAVED_VISUALIZATION];
+ setSelectedContentTab(tabToBeFocused);
+ await fetchData();
+ })
+ .catch((error) => {
+ notifications.toasts.addError(error, {
+ title: `Cannot get saved data for object id: ${objectId}`,
+ });
+ });
+ };
+
+ const getDefaultTimestampByIndexPattern = async (
+ indexPattern: string
+ ): Promise => await timestampUtils.getTimestamp(indexPattern);
+
+ const fetchData = async (startingTime?: string, endingTime?: string) => {
+ const curQuery = queryRef.current;
+ const rawQueryStr = buildQuery(appBasedRef.current, curQuery![RAW_QUERY]);
+ const curIndex = getIndexPatternFromRawQuery(rawQueryStr);
+ if (isEmpty(rawQueryStr)) return;
+
+ if (isEmpty(curIndex)) {
+ setToast('Query does not include valid index.', 'danger');
+ return;
+ }
+
+ let curTimestamp: string = curQuery![SELECTED_TIMESTAMP];
+
+ if (isEmpty(curTimestamp)) {
+ const defaultTimestamp = await getDefaultTimestampByIndexPattern(curIndex);
+ if (isEmpty(defaultTimestamp.default_timestamp)) {
+ setToast(defaultTimestamp.message, 'danger');
+ return;
+ }
+ curTimestamp = defaultTimestamp.default_timestamp;
+ if (defaultTimestamp.hasSchemaConflict) {
+ setToast(defaultTimestamp.message, 'danger');
+ }
+ }
+
+ if (isEqual(typeof startingTime, 'undefined') && isEqual(typeof endingTime, 'undefined')) {
+ startingTime = curQuery![SELECTED_DATE_RANGE][0];
+ endingTime = curQuery![SELECTED_DATE_RANGE][1];
+ }
+
+ // compose final query
+ const finalQuery = composeFinalQuery(
+ curQuery,
+ startingTime!,
+ endingTime!,
+ curTimestamp,
+ isLiveTailOnRef.current
+ );
+
+ await dispatch(
+ changeQuery({
+ tabId,
+ query: {
+ finalQuery,
+ [SELECTED_TIMESTAMP]: curTimestamp,
+ },
+ })
+ );
+
+ // search
+ if (finalQuery.match(PPL_STATS_REGEX)) {
+ getVisualizations();
+ getAvailableFields(`search source=${curIndex}`);
+ } else {
+ findAutoInterval(startTime, endTime);
+ if (isLiveTailOnRef.current) {
+ getLiveTail(undefined, (error) => {
+ const formattedError = formatError(error.name, error.message, error.body.message);
+ notifications.toasts.addError(formattedError, {
+ title: 'Error fetching events',
+ });
+ });
+ } else {
+ getEvents(undefined, (error) => {
+ const formattedError = formatError(error.name, error.message, error.body.message);
+ notifications.toasts.addError(formattedError, {
+ title: 'Error fetching events',
+ });
+ });
+ }
+ getCountVisualizations(minInterval);
+ }
+
+ // for comparing usage if for the same tab, user changed index from one to another
+ if (!isLiveTailOnRef.current) {
+ setPrevIndex(curTimestamp);
+ if (!queryRef.current!.isLoaded) {
+ dispatch(
+ changeQuery({
+ tabId,
+ query: {
+ isLoaded: true,
+ },
+ })
+ );
+ }
+ }
+ };
+
+ const isIndexPatternChanged = (currentQuery: string, prevTabQuery: string) =>
+ !isEqual(getIndexPatternFromRawQuery(currentQuery), getIndexPatternFromRawQuery(prevTabQuery));
+
+ const updateTabData = async (objectId: string) => {
+ await getSavedDataById(objectId);
+ };
+
+ const prepareAvailability = async () => {
+ setSelectedContentTab(TAB_CHART_ID);
+ setTriggerAvailability(true);
+ await setTempQuery(DEFAULT_AVAILABILITY_QUERY);
+ await updateQueryInStore(DEFAULT_AVAILABILITY_QUERY);
+ await handleTimeRangePickerRefresh(true);
+ };
+
+ useEffect(() => {
+ if (!isEmpty(appBasedRef.current)) {
+ if (callback) {
+ callback(() => prepareAvailability());
+ }
+ if (callbackInApp) {
+ callbackInApp(() => prepareAvailability());
+ }
+ }
+ }, [appBasedRef.current]);
+
+ useEffect(() => {
+ if (queryRef.current!.isLoaded) return;
+ let objectId;
+ if (queryRef.current![TAB_CREATED_TYPE] === NEW_TAB || appLogEvents) {
+ objectId = queryRef.current!.savedObjectId || '';
+ } else {
+ objectId = queryRef.current!.savedObjectId || savedObjectId;
+ }
+ if (objectId) {
+ updateTabData(objectId);
+ } else {
+ fetchData();
+ }
+ }, []);
+
+ useEffect(() => {
+ if (appLogEvents) {
+ if (savedObjectId) {
+ updateTabData(savedObjectId);
+ }
+ }
+ }, [savedObjectId]);
+
+ const handleAddField = (field: IField) => toggleFields(field, AVAILABLE_FIELDS, SELECTED_FIELDS);
+
+ const handleRemoveField = (field: IField) =>
+ toggleFields(field, SELECTED_FIELDS, AVAILABLE_FIELDS);
+
+ const handleTimePickerChange = async (timeRange: string[]) => {
+ if (appLogEvents) {
+ setStartTime(timeRange[0]);
+ setEndTime(timeRange[1]);
+ }
+ await dispatch(
+ changeDateRange({
+ tabId: requestParams.tabId,
+ data: {
+ [RAW_QUERY]: queryRef.current![RAW_QUERY],
+ [SELECTED_DATE_RANGE]: timeRange,
+ },
+ })
+ );
+ };
+
+ const showPermissionErrorToast = () => {
+ setToast(
+ 'Please ask your administrator to enable Event Analytics for you.',
+ 'danger',
+
+ Documentation
+
+ );
+ };
+
+ const handleTimeRangePickerRefresh = (availability?: boolean) => {
+ handleQuerySearch(availability);
+ };
+
+ /**
+ * Toggle fields between selected and unselected sets
+ * @param field field to be toggled
+ * @param FieldSetToRemove set where this field to be removed from
+ * @param FieldSetToAdd set where this field to be added
+ */
+ const toggleFields = (field: IField, FieldSetToRemove: string, FieldSetToAdd: string) => {
+ const nextFields = cloneDeep(explorerFields);
+ const thisFieldSet = nextFields[FieldSetToRemove];
+ const nextFieldSet = thisFieldSet.filter((fd: IField) => fd.name !== field.name);
+ nextFields[FieldSetToRemove] = nextFieldSet;
+ nextFields[FieldSetToAdd].push(field);
+ batch(() => {
+ dispatch(
+ updateFields({
+ tabId,
+ data: {
+ ...nextFields,
+ },
+ })
+ );
+ dispatch(
+ sortFields({
+ tabId,
+ data: [FieldSetToAdd],
+ })
+ );
+ });
+ };
+
+ const sidebarClassName = classNames({
+ closed: isSidebarClosed,
+ });
+
+ const mainSectionClassName = classNames({
+ 'col-md-10': !isSidebarClosed,
+ 'col-md-12': isSidebarClosed,
+ });
+
+ const handleOverrideTimestamp = async (timestamp: IField) => {
+ const curQuery = queryRef.current;
+ const rawQueryStr = buildQuery(appBaseQuery, curQuery![RAW_QUERY]);
+ const curIndex = getIndexPatternFromRawQuery(rawQueryStr);
+ if (isEmpty(rawQueryStr) || isEmpty(curIndex)) {
+ setToast('Cannot override timestamp because there was no valid index found.', 'danger');
+ return;
+ }
+
+ setIsOverridingTimestamp(true);
+
+ await dispatch(
+ changeQuery({
+ tabId,
+ query: {
+ [SELECTED_TIMESTAMP]: timestamp?.name || '',
+ },
+ })
+ );
+
+ setIsOverridingTimestamp(false);
+ handleQuerySearch();
+ };
+
+ const totalHits: number = useMemo(() => {
+ if (isLiveTailOn && countDistribution?.data) {
+ const hits = reduce(
+ countDistribution.data['count()'],
+ (sum, n) => {
+ return sum + n;
+ },
+ liveHits
+ );
+ setLiveHits(hits);
+ return hits;
+ }
+ return 0;
+ }, [countDistribution?.data]);
+
+ const getMainContent = () => {
+ return (
+
+
+
+
+ {explorerData && !isEmpty(explorerData.jsonData) ? (
+
+
+ {countDistribution?.data && !isLiveTailOnRef.current && (
+ <>
+
+
+ {
+ return sum + n;
+ },
+ 0
+ )}
+ showResetButton={false}
+ onResetQuery={() => {}}
+ />
+
+
+ {
+ getCountVisualizations(intrv);
+ }}
+ stateInterval="auto"
+ />
+
+
+
+ >
+ )}
+
+
+
+
+
+
+ {isLiveTailOnRef.current && (
+ <>
+
+
+
+
+ Live streaming
+
+
+ {}}
+ />
+
+ since {liveTimestamp}
+
+
+ >
+ )}
+
+
+
+
+
+
+
+
+ ) : (
+
+ )}
+
+
+
+ );
+ };
+
+ function getMainContentTab({
+ tabID,
+ tabTitle,
+ getContent,
+ }: {
+ tabID: string;
+ tabTitle: string;
+ getContent: () => JSX.Element;
+ }) {
+ return {
+ id: tabID,
+ name: (
+ <>
+
+ {tabTitle}
+
+ >
+ ),
+ content: <>{getContent()}>,
+ };
+ }
+
+ const visualizations: IVisualizationContainerProps = useMemo(() => {
+ return getVizContainerProps({
+ vizId: curVisId,
+ rawVizData: explorerVisualizations,
+ query,
+ indexFields: explorerFields,
+ userConfigs: userVizConfigs[curVisId] || {},
+ appData: { fromApp: appLogEvents },
+ });
+ }, [curVisId, explorerVisualizations, explorerFields, query, userVizConfigs]);
+
+ const callbackForConfig = (childFunc: () => void) => {
+ if (childFunc && triggerAvailability) {
+ childFunc();
+ setTriggerAvailability(false);
+ }
+ };
+
+ const getExplorerVis = () => {
+ return (
+
+ );
+ };
+
+ const getMainContentTabs = () => {
+ return [
+ getMainContentTab({
+ tabID: TAB_EVENT_ID,
+ tabTitle: TAB_EVENT_TITLE,
+ getContent: () => getMainContent(),
+ }),
+ getMainContentTab({
+ tabID: TAB_CHART_ID,
+ tabTitle: TAB_CHART_TITLE,
+ getContent: () => getExplorerVis(),
+ }),
+ ];
+ };
+
+ const memorizedMainContentTabs = useMemo(() => {
+ return getMainContentTabs();
+ }, [
+ curVisId,
+ isPanelTextFieldInvalid,
+ explorerData,
+ explorerFields,
+ isSidebarClosed,
+ countDistribution,
+ explorerVisualizations,
+ selectedContentTabId,
+ isOverridingTimestamp,
+ visualizations,
+ query,
+ isLiveTailOnRef.current,
+ ]);
+
+ const handleContentTabClick = (selectedTab: IQueryTab) => setSelectedContentTab(selectedTab.id);
+
+ const updateQueryInStore = async (updateQuery: string) => {
+ await dispatch(
+ changeQuery({
+ tabId,
+ query: {
+ [RAW_QUERY]: updateQuery.replaceAll(PPL_NEWLINE_REGEX, ''),
+ },
+ })
+ );
+ };
+
+ const updateCurrentTimeStamp = async (timestamp: string) => {
+ await dispatch(
+ changeQuery({
+ tabId,
+ query: {
+ [SELECTED_TIMESTAMP]: timestamp,
+ },
+ })
+ );
+ };
+
+ const handleQuerySearch = useCallback(
+ async (availability?: boolean) => {
+ // clear previous selected timestamp when index pattern changes
+ if (
+ !isEmpty(tempQuery) &&
+ !isEmpty(query[RAW_QUERY]) &&
+ isIndexPatternChanged(tempQuery, query[RAW_QUERY])
+ ) {
+ await updateCurrentTimeStamp('');
+ }
+ if (availability !== true) {
+ await updateQueryInStore(tempQuery);
+ }
+ fetchData();
+ },
+ [tempQuery, query[RAW_QUERY]]
+ );
+
+ const handleQueryChange = async (newQuery: string) => {
+ setTempQuery(newQuery);
+ };
+
+ const handleSavingObject = async () => {
+ const currQuery = queryRef.current;
+ const currFields = explorerFieldsRef.current;
+ if (isEmpty(currQuery![RAW_QUERY]) && isEmpty(appBaseQuery)) {
+ setToast('No query to save.', 'danger');
+ return;
+ }
+ if (isEmpty(selectedPanelNameRef.current)) {
+ setIsPanelTextFieldInvalid(true);
+ setToast('Name field cannot be empty.', 'danger');
+ return;
+ }
+ setIsPanelTextFieldInvalid(false);
+ if (isEqual(selectedContentTabId, TAB_EVENT_ID)) {
+ const isTabMatchingSavedType = isEqual(currQuery![SAVED_OBJECT_TYPE], SAVED_QUERY);
+ if (!isEmpty(currQuery![SAVED_OBJECT_ID]) && isTabMatchingSavedType) {
+ await savedObjects
+ .updateSavedQueryById({
+ query: currQuery![RAW_QUERY],
+ fields: currFields![SELECTED_FIELDS],
+ dateRange: currQuery![SELECTED_DATE_RANGE],
+ name: selectedPanelNameRef.current,
+ timestamp: currQuery![SELECTED_TIMESTAMP],
+ objectId: currQuery![SAVED_OBJECT_ID],
+ type: '',
+ })
+ .then((res: any) => {
+ setToast(
+ `Query '${selectedPanelNameRef.current}' has been successfully updated.`,
+ 'success'
+ );
+ dispatch(
+ updateTabName({
+ tabId,
+ tabName: selectedPanelNameRef.current,
+ })
+ );
+ return res;
+ })
+ .catch((error: any) => {
+ notifications.toasts.addError(error, {
+ title: `Cannot update query '${selectedPanelNameRef.current}'`,
+ });
+ });
+ } else {
+ // create new saved query
+ savedObjects
+ .createSavedQuery({
+ query: currQuery![RAW_QUERY],
+ fields: currFields![SELECTED_FIELDS],
+ dateRange: currQuery![SELECTED_DATE_RANGE],
+ name: selectedPanelNameRef.current,
+ timestamp: currQuery![SELECTED_TIMESTAMP],
+ objectId: '',
+ type: '',
+ })
+ .then((res: any) => {
+ history.replace(`/event_analytics/explorer/${res.objectId}`);
+ setToast(
+ `New query '${selectedPanelNameRef.current}' has been successfully saved.`,
+ 'success'
+ );
+ batch(() => {
+ dispatch(
+ changeQuery({
+ tabId,
+ query: {
+ [SAVED_OBJECT_ID]: res.objectId,
+ [SAVED_OBJECT_TYPE]: SAVED_QUERY,
+ },
+ })
+ );
+ dispatch(
+ updateTabName({
+ tabId,
+ tabName: selectedPanelNameRef.current,
+ })
+ );
+ });
+ history.replace(`/event_analytics/explorer/${res.objectId}`);
+ return res;
+ })
+ .catch((error: any) => {
+ if (error?.body?.statusCode === 403) {
+ showPermissionErrorToast();
+ } else {
+ notifications.toasts.addError(error, {
+ title: `Cannot save query '${selectedPanelNameRef.current}'`,
+ });
+ }
+ });
+ }
+ // to-dos - update selected custom panel
+ if (!isEmpty(selectedCustomPanelOptions)) {
+ // update custom panel - query
+ }
+ } else if (isEqual(selectedContentTabId, TAB_CHART_ID)) {
+ if (
+ (isEmpty(currQuery![RAW_QUERY]) && isEmpty(appBaseQuery)) ||
+ isEmpty(explorerVisualizations)
+ ) {
+ setToast(`There is no query or(and) visualization to save`, 'danger');
+ return;
+ }
+ let savingVisRes;
+ const vizDescription = userVizConfigs[curVisId]?.dataConfig?.panelOptions?.description || '';
+ const isTabMatchingSavedType = isEqual(currQuery![SAVED_OBJECT_TYPE], SAVED_VISUALIZATION);
+ if (!isEmpty(currQuery![SAVED_OBJECT_ID]) && isTabMatchingSavedType) {
+ savingVisRes = await savedObjects
+ .updateSavedVisualizationById({
+ query: buildQuery(appBaseQuery, currQuery![RAW_QUERY]),
+ fields: currFields![SELECTED_FIELDS],
+ dateRange: currQuery![SELECTED_DATE_RANGE],
+ name: selectedPanelNameRef.current,
+ timestamp: currQuery![SELECTED_TIMESTAMP],
+ objectId: currQuery![SAVED_OBJECT_ID],
+ type: curVisId,
+ userConfigs: userVizConfigs.hasOwnProperty(curVisId)
+ ? JSON.stringify(userVizConfigs[curVisId])
+ : JSON.stringify({}),
+ description: vizDescription,
+ })
+ .then((res: any) => {
+ setToast(
+ `Visualization '${selectedPanelNameRef.current}' has been successfully updated.`,
+ 'success'
+ );
+ dispatch(
+ updateTabName({
+ tabId,
+ tabName: selectedPanelNameRef.current,
+ })
+ );
+ return res;
+ })
+ .catch((error: any) => {
+ notifications.toasts.addError(error, {
+ title: `Cannot update Visualization '${selectedPanelNameRef.current}'`,
+ });
+ });
+ } else {
+ // create new saved visualization
+ savingVisRes = await savedObjects
+ .createSavedVisualization({
+ query: buildQuery(appBaseQuery, currQuery![RAW_QUERY]),
+ fields: currFields![SELECTED_FIELDS],
+ dateRange: currQuery![SELECTED_DATE_RANGE],
+ type: curVisId,
+ name: selectedPanelNameRef.current,
+ timestamp: currQuery![SELECTED_TIMESTAMP],
+ applicationId: appId,
+ userConfigs: userVizConfigs.hasOwnProperty(curVisId)
+ ? JSON.stringify(userVizConfigs[curVisId])
+ : JSON.stringify({}),
+ description: vizDescription,
+ })
+ .then((res: any) => {
+ batch(() => {
+ dispatch(
+ changeQuery({
+ tabId,
+ query: {
+ [SAVED_OBJECT_ID]: res.objectId,
+ [SAVED_OBJECT_TYPE]: SAVED_VISUALIZATION,
+ },
+ })
+ );
+ dispatch(
+ updateTabName({
+ tabId,
+ tabName: selectedPanelNameRef.current,
+ })
+ );
+ });
+ if (appLogEvents) {
+ addVisualizationToPanel(res.objectId, selectedPanelNameRef.current);
+ } else {
+ history.replace(`/event_analytics/explorer/${res.objectId}`);
+ }
+ setToast(
+ `New visualization '${selectedPanelNameRef.current}' has been successfully saved.`,
+ 'success'
+ );
+ return res;
+ })
+ .catch((error: any) => {
+ notifications.toasts.addError(error, {
+ title: `Cannot save Visualization '${selectedPanelNameRef.current}'`,
+ });
+ });
+ }
+ if (!has(savingVisRes, 'objectId')) return;
+ // update custom panel - visualization
+ if (!isEmpty(selectedCustomPanelOptions)) {
+ savedObjects
+ .bulkUpdateCustomPanel({
+ selectedCustomPanels: selectedCustomPanelOptions,
+ savedVisualizationId: savingVisRes.objectId,
+ })
+ .then((res: any) => {
+ setToast(
+ `Visualization '${selectedPanelNameRef.current}' has been successfully saved to operation panels.`,
+ 'success'
+ );
+ })
+ .catch((error: any) => {
+ notifications.toasts.addError(error, {
+ title: `Cannot add Visualization '${selectedPanelNameRef.current}' to operation panels`,
+ });
+ });
+ }
+ }
+ };
+
+ const liveTailLoop = async (
+ name: string,
+ startingTime: string,
+ endingTime: string,
+ delayTime: number
+ ) => {
+ setLiveTailName(name);
+ setLiveTailTabId((curSelectedTabId.current as unknown) as string);
+ setIsLiveTailOn(true);
+ setToast('Live tail On', 'success');
+ setIsLiveTailPopoverOpen(false);
+ setLiveTimestamp(dateMath.parse(endingTime)?.utc().format(DATE_PICKER_FORMAT) || '');
+ setLiveHits(0);
+ await sleep(2000);
+ const curLiveTailname = liveTailNameRef.current;
+ while (isLiveTailOnRef.current === true && curLiveTailname === liveTailNameRef.current) {
+ handleLiveTailSearch(startingTime, endingTime);
+ if (liveTailTabIdRef.current !== curSelectedTabId.current) {
+ setIsLiveTailOn(false);
+ isLiveTailOnRef.current = false;
+ setLiveTailName('Live');
+ setLiveHits(0);
+ }
+ await sleep(delayTime);
+ }
+ };
+
+ const stopLive = () => {
+ setLiveTailName('Live');
+ setIsLiveTailOn(false);
+ setLiveHits(0);
+ setIsLiveTailPopoverOpen(false);
+ if (isLiveTailOnRef.current) setToast('Live tail Off', 'danger');
+ };
+
+ useEffect(() => {
+ if (isEqual(selectedContentTabId, TAB_CHART_ID) || !browserTabFocus) {
+ stopLive();
+ }
+ }, [selectedContentTabId, browserTabFocus]);
+
+ // stop live tail if the page is moved using breadcrumbs
+ let lastUrl = location.href;
+ new MutationObserver(() => {
+ const url = location.href;
+ if (url !== lastUrl) {
+ lastUrl = url;
+ stopLive();
+ }
+ }).observe(document, { subtree: true, childList: true });
+
+ const popoverItems: ReactElement[] = LIVE_OPTIONS.map((e) => {
+ return (
+ {
+ liveTailLoop(e.label, e.startTime, LIVE_END_TIME, e.delayTime);
+ }}
+ data-test-subj={'eventLiveTail__delay' + e.label}
+ >
+ {e.label}
+
+ );
+ });
+
+ const dateRange =
+ isEmpty(startTime) || isEmpty(endTime)
+ ? isEmpty(query.selectedDateRange)
+ ? ['now-15m', 'now']
+ : [query.selectedDateRange[0], query.selectedDateRange[1]]
+ : [startTime, endTime];
+
+ const handleLiveTailSearch = useCallback(
+ async (startingTime: string, endingTime: string) => {
+ await updateQueryInStore(tempQuery);
+ fetchData(startingTime, endingTime);
+ },
+ [tempQuery]
+ );
+
+ return (
+
+
+ handleTimePickerChange(timeRange)}
+ selectedPanelName={selectedPanelNameRef.current}
+ selectedCustomPanelOptions={selectedCustomPanelOptions}
+ setSelectedPanelName={setSelectedPanelName}
+ setSelectedCustomPanelOptions={setSelectedCustomPanelOptions}
+ handleSavingObject={handleSavingObject}
+ isPanelTextFieldInvalid={isPanelTextFieldInvalid}
+ savedObjects={savedObjects}
+ showSavePanelOptionsList={isEqual(selectedContentTabId, TAB_CHART_ID)}
+ handleTimeRangePickerRefresh={handleTimeRangePickerRefresh}
+ isLiveTailPopoverOpen={isLiveTailPopoverOpen}
+ closeLiveTailPopover={() => setIsLiveTailPopoverOpen(false)}
+ popoverItems={popoverItems}
+ isLiveTailOn={isLiveTailOnRef.current}
+ selectedSubTabId={selectedContentTabId}
+ searchBarConfigs={searchBarConfigs}
+ getSuggestions={parseGetSuggestions}
+ onItemSelect={onItemSelect}
+ tabId={tabId}
+ baseQuery={appBaseQuery}
+ stopLive={stopLive}
+ setIsLiveTailPopoverOpen={setIsLiveTailPopoverOpen}
+ liveTailName={liveTailNameRef.current}
+ />
+ tab.id === selectedContentTabId)}
+ onTabClick={(selectedTab: EuiTabbedContentTab) => handleContentTabClick(selectedTab)}
+ tabs={memorizedMainContentTabs}
+ />
+
+
+ );
+};
diff --git a/public/components/explorer/hits_counter/__tests__/__snapshots__/hits_counter.test.tsx.snap b/public/components/explorer/hits_counter/__tests__/__snapshots__/hits_counter.test.tsx.snap
new file mode 100644
index 0000000000..13a8ec20ce
--- /dev/null
+++ b/public/components/explorer/hits_counter/__tests__/__snapshots__/hits_counter.test.tsx.snap
@@ -0,0 +1,142 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Hits counter component Renders hits counter 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+ 815
+
+
+
+ hits
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/explorer/hits_counter/__tests__/hits_counter.test.tsx b/public/components/explorer/hits_counter/__tests__/hits_counter.test.tsx
new file mode 100644
index 0000000000..fca4b5fee0
--- /dev/null
+++ b/public/components/explorer/hits_counter/__tests__/hits_counter.test.tsx
@@ -0,0 +1,32 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { HitsCounter } from '../hits_counter';
+
+describe('Hits counter component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders hits counter', async () => {
+ const onResetQuery = jest.fn();
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
\ No newline at end of file
diff --git a/public/components/explorer/hits_counter/hits_counter.tsx b/public/components/explorer/hits_counter/hits_counter.tsx
new file mode 100644
index 0000000000..8b7d3f1d09
--- /dev/null
+++ b/public/components/explorer/hits_counter/hits_counter.tsx
@@ -0,0 +1,71 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+
+import React from 'react';
+import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui';
+import { FormattedMessage, I18nProvider } from '@osd/i18n/react';
+import { i18n } from '@osd/i18n';
+import { formatNumWithCommas } from '../../common/helpers';
+
+export interface HitsCounterProps {
+ /**
+ * the number of query hits
+ */
+ hits: number;
+ /**
+ * displays the reset button
+ */
+ showResetButton: boolean;
+ /**
+ * resets the query
+ */
+ onResetQuery: () => void;
+}
+
+export function HitsCounter({ hits, showResetButton, onResetQuery }: HitsCounterProps) {
+ return (
+
+
+
+
+ {formatNumWithCommas(hits)} {' '}
+
+
+
+ {showResetButton && (
+
+
+
+
+
+ )}
+
+
+ );
+}
diff --git a/public/components/explorer/hits_counter/index.ts b/public/components/explorer/hits_counter/index.ts
new file mode 100644
index 0000000000..93706c4947
--- /dev/null
+++ b/public/components/explorer/hits_counter/index.ts
@@ -0,0 +1,6 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { HitsCounter } from './hits_counter';
diff --git a/public/components/explorer/home.scss b/public/components/explorer/home.scss
new file mode 100644
index 0000000000..bc4d8f66d0
--- /dev/null
+++ b/public/components/explorer/home.scss
@@ -0,0 +1,20 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+.event-home {
+ float: left;
+ width: 100%;
+ max-width: 1130px;
+ #autocomplete-textarea {
+ min-height: 80px;
+ }
+ .ppl-link {
+ right: 5px;
+ }
+}
+
+#home-his-title {
+ padding-left: 10px;
+}
\ No newline at end of file
diff --git a/public/components/explorer/home.tsx b/public/components/explorer/home.tsx
new file mode 100644
index 0000000000..3e10ad6824
--- /dev/null
+++ b/public/components/explorer/home.tsx
@@ -0,0 +1,472 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import './home.scss';
+
+import React, { useState, ReactElement, useRef, useEffect } from 'react';
+import { useDispatch, batch, useSelector } from 'react-redux';
+import { uniqueId } from 'lodash';
+import { useHistory } from 'react-router-dom';
+import {
+ EuiPage,
+ EuiPageBody,
+ EuiPageHeader,
+ EuiPageHeaderSection,
+ EuiTitle,
+ EuiPageContent,
+ EuiSpacer,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiButton,
+ EuiPopover,
+ EuiContextMenuPanel,
+ EuiContextMenuItem,
+ EuiOverlayMask,
+ EuiLink,
+ EuiPageContentHeader,
+ EuiPageContentHeaderSection,
+ EuiText,
+ EuiHorizontalRule,
+} from '@elastic/eui';
+import { Search } from '../common/search/search';
+import { DeleteModal } from '../common/helpers/delete_modal';
+import {
+ RAW_QUERY,
+ TAB_ID_TXT_PFX,
+ SELECTED_DATE_RANGE,
+ EVENT_ANALYTICS_DOCUMENTATION_URL,
+ TAB_CREATED_TYPE,
+ NEW_TAB,
+ REDIRECT_TAB,
+} from '../../../common/constants/explorer';
+import {
+ OBSERVABILITY_BASE,
+ EVENT_ANALYTICS,
+ SAVED_OBJECTS,
+} from '../../../common/constants/shared';
+import { EmptyTabParams, SavedQueryRes, SavedVizRes } from '../../../common/types/explorer';
+import { HttpStart } from '../../../../../src/core/public';
+import SavedObjects from '../../services/saved_objects/event_analytics/saved_objects';
+import { addTab, selectQueryTabs } from './slices/query_tab_slice';
+import { init as initFields } from './slices/field_slice';
+import { init as initQuery, changeQuery } from './slices/query_slice';
+import { init as initQueryResult, selectQueryResult } from './slices/query_result_slice';
+import { SavedQueryTable } from './home_table/saved_query_table';
+import { selectQueries } from './slices/query_slice';
+import { setSelectedQueryTab } from './slices/query_tab_slice';
+import { CUSTOM_PANELS_API_PREFIX } from '../../../common/constants/custom_panels';
+import { getSampleDataModal } from '../common/helpers/add_sample_modal';
+import { parseGetSuggestions, onItemSelect } from '../common/search/autocomplete_logic';
+
+interface IHomeProps {
+ pplService: any;
+ dslService: any;
+ savedObjects: SavedObjects;
+ setToast: (
+ title: string,
+ color?: string,
+ text?: React.ReactChild | undefined,
+ side?: string | undefined
+ ) => void;
+ getExistingEmptyTab: (params: EmptyTabParams) => string;
+ http: HttpStart;
+}
+
+export const Home = (props: IHomeProps) => {
+ const { pplService, dslService, savedObjects, setToast, getExistingEmptyTab, http } = props;
+ const history = useHistory();
+ const dispatch = useDispatch();
+
+ const queries = useSelector(selectQueries);
+ const explorerData = useSelector(selectQueryResult);
+ const tabIds = useSelector(selectQueryTabs).queryTabIds;
+ const queryRef = useRef();
+ const tabIdsRef = useRef();
+ const explorerDataRef = useRef();
+ queryRef.current = queries;
+ tabIdsRef.current = tabIds;
+ explorerDataRef.current = explorerData;
+
+ const [searchQuery, setSearchQuery] = useState('');
+ const [selectedDateRange, setSelectedDateRange] = useState(['now-15m', 'now']);
+ const [savedHistories, setSavedHistories] = useState([]);
+ const [selectedHistories, setSelectedHistories] = useState([]);
+ const [isActionsPopoverOpen, setIsActionsPopoverOpen] = useState(false);
+ const [isTableLoading, setIsTableLoading] = useState(false);
+ const [modalLayout, setModalLayout] = useState( );
+ const [isModalVisible, setIsModalVisible] = useState(false);
+ const selectedDateRangeRef = useRef();
+ selectedDateRangeRef.current = selectedDateRange;
+
+ const closeModal = () => {
+ setIsModalVisible(false);
+ };
+
+ const showModal = () => {
+ setIsModalVisible(true);
+ };
+
+ const fetchHistories = async () => {
+ const res = await savedObjects.fetchSavedObjects({
+ objectType: ['savedQuery', 'savedVisualization'],
+ sortOrder: 'desc',
+ fromIndex: 0,
+ });
+ const nonAppObjects = res.observabilityObjectList.filter(
+ (object: SavedQueryRes | SavedVizRes) =>
+ (object.savedVisualization && !object.savedVisualization.application_id) ||
+ object.savedQuery
+ );
+ setSavedHistories(nonAppObjects);
+ };
+
+ const deleteHistoryList = async () => {
+ const objectIdsToDelete = selectedHistories.map((history) => history.data.objectId);
+ await savedObjects
+ .deleteSavedObjectsList({ objectIdList: objectIdsToDelete })
+ .then(async (res) => {
+ setSavedHistories((staleHistories) => {
+ return staleHistories.filter((his) => {
+ return !objectIdsToDelete.includes(his.objectId);
+ });
+ });
+ setToast(`Histories has been successfully deleted.`, 'success');
+ })
+ .catch((error) => {
+ setToast(`Cannot delete Histories, error: ${error.message}`, 'danger');
+ })
+ .finally(() => {
+ closeModal();
+ });
+ };
+
+ const addNewTab = async () => {
+ // get a new tabId
+ const tabId = uniqueId(TAB_ID_TXT_PFX);
+
+ // create a new tab
+ await batch(() => {
+ dispatch(initQuery({ tabId }));
+ dispatch(initQueryResult({ tabId }));
+ dispatch(initFields({ tabId }));
+ dispatch(addTab({ tabId }));
+ });
+
+ return tabId;
+ };
+
+ useEffect(() => {
+ fetchHistories();
+ }, []);
+
+ const dispatchInitialData = (tabId: string) => {
+ batch(() => {
+ dispatch(
+ changeQuery({
+ tabId,
+ query: {
+ [RAW_QUERY]: searchQuery,
+ [SELECTED_DATE_RANGE]: selectedDateRangeRef.current,
+ [TAB_CREATED_TYPE]: NEW_TAB,
+ },
+ })
+ );
+ dispatch(setSelectedQueryTab({ tabId }));
+ });
+ };
+
+ const handleQuerySearch = async () => {
+ const emptyTabId = getExistingEmptyTab({
+ tabIds: tabIdsRef.current,
+ queries: queryRef.current,
+ explorerData: explorerDataRef.current,
+ });
+ const newTabId = emptyTabId ? emptyTabId : await addNewTab();
+
+ // update this new tab with data
+ await dispatchInitialData(newTabId);
+
+ // redirect to explorer
+ history.push('/event_analytics/explorer');
+ };
+
+ const handleQueryChange = async (query: string) => setSearchQuery(query);
+
+ const handleTimePickerChange = async (timeRange: string[]) => setSelectedDateRange(timeRange);
+
+ const handleHistoryClick = async (objectId: string) => {
+ const emptyTabId = getExistingEmptyTab({
+ tabIds: tabIdsRef.current,
+ queries: queryRef.current,
+ explorerData: explorerDataRef.current,
+ });
+ const newTabId = emptyTabId ? emptyTabId : await addNewTab();
+ batch(() => {
+ dispatch(
+ changeQuery({
+ tabId: newTabId,
+ query: {
+ [TAB_CREATED_TYPE]: REDIRECT_TAB,
+ },
+ })
+ );
+ dispatch(setSelectedQueryTab({ tabId: newTabId }));
+ });
+ // redirect to explorer
+ history.push(`/event_analytics/explorer/${objectId}`);
+ };
+
+ const addSampledata = async () => {
+ setModalLayout(
+ getSampleDataModal(closeModal, async () => {
+ closeModal();
+ await addSampleEvents();
+ })
+ );
+ showModal();
+ };
+
+ const addSampleEvents = async () => {
+ try {
+ setIsTableLoading(true);
+ const flights = await http
+ .get('../api/saved_objects/_find', {
+ query: {
+ type: 'index-pattern',
+ search_fields: 'title',
+ search: 'opensearch_dashboards_sample_data_flights',
+ },
+ })
+ .then((resp: any) => resp.total === 0);
+ const logs = await http
+ .get('../api/saved_objects/_find', {
+ query: {
+ type: 'index-pattern',
+ search_fields: 'title',
+ search: 'opensearch_dashboards_sample_data_logs',
+ },
+ })
+ .then((resp: any) => resp.total === 0);
+ if (flights || logs) setToast('Adding sample data. This can take some time.');
+ await Promise.all([
+ flights ? http.post('../api/sample_data/flights') : Promise.resolve(),
+ logs ? http.post('../api/sample_data/logs') : Promise.resolve(),
+ ]);
+
+ await http
+ .get(
+ `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}/addSampleSavedObjects/event_analytics`
+ )
+ .then(async (resp: any) => {
+ await http.post(`${CUSTOM_PANELS_API_PREFIX}/panels/addSamplePanels`, {
+ body: JSON.stringify({
+ savedVisualizationIds: [...resp?.savedVizIds],
+ }),
+ });
+
+ const res = await savedObjects.fetchSavedObjects({
+ objectIdList: [...resp?.savedVizIds, ...resp?.savedQueryIds] || [],
+ objectType: ['savedQuery', 'savedVisualization'],
+ sortOrder: 'desc',
+ fromIndex: 0,
+ });
+ setSavedHistories((staleHistoryList) => {
+ return [...res.observabilityObjectList, ...staleHistoryList];
+ });
+ });
+ setToast(`Sample events added successfully.`);
+ } catch (error: any) {
+ setToast(`Cannot add sample events data, error: ${error}`, 'danger');
+ console.error(error.body.message);
+ } finally {
+ setIsTableLoading(false);
+ }
+ };
+
+ const popoverButton = (
+ setIsActionsPopoverOpen(!isActionsPopoverOpen)}
+ data-test-subj="eventHomeAction"
+ >
+ Actions
+
+ );
+
+ const deleteHistory = () => {
+ const customPanelString = `${selectedHistories.length > 1 ? 'histories' : 'history'}`;
+ setModalLayout(
+
+ );
+ showModal();
+ };
+
+ const popoverItems: ReactElement[] = [
+ {
+ setIsActionsPopoverOpen(false);
+ deleteHistory();
+ }}
+ data-test-subj="eventHomeAction__delete"
+ >
+ Delete
+ ,
+ {
+ setIsActionsPopoverOpen(false);
+ history.push(`/event_analytics/explorer`);
+ }}
+ data-test-subj="eventHomeAction__explorer"
+ >
+ Event Explorer
+ ,
+ {
+ setIsActionsPopoverOpen(false);
+ addSampledata();
+ }}
+ data-test-subj="eventHomeAction__addSamples"
+ >
+ Add samples
+ ,
+ ];
+
+ return (
+ <>
+
+
+
+
+
+ Event analytics
+
+
+
+
+
+
+ {}}
+ setEndTime={() => {}}
+ showSaveButton={false}
+ runButtonText="New Query"
+ getSuggestions={parseGetSuggestions}
+ onItemSelect={onItemSelect}
+ />
+
+
+
+
+
+
+
+
+
+
+ Queries and Visualizations
+ ({savedHistories.length})
+
+
+
+
+ Use Events Analytics to monitor, correlate, analyze and visualize machine
+ generated data through Piped Processing Language. Save frequently searched queries
+ and visualizations for quick access{' '}
+
+ Learn more
+
+
+
+
+
+
+ setIsActionsPopoverOpen(false)}
+ >
+
+
+
+
+
+
+
+
+
+ {savedHistories.length > 0 ? (
+
+ ) : (
+ <>
+
+
+ No Queries or Visualizations
+
+
+ Use events analytics to create and save frequently searched
+
+ queries and visualizations, using PPL.
+
+
+
+
+
+ history.push(`/event_analytics/explorer`)}
+ data-test-subj="actionEventExplorer"
+ >
+ Event Explorer
+
+
+
+ addSampledata()}
+ data-test-subj="actionAddSamples"
+ >
+ Add samples
+
+
+
+
+ >
+ )}
+
+
+
+
+
+ {isModalVisible && modalLayout}
+ >
+ );
+};
diff --git a/public/components/explorer/home_table/__tests__/__snapshots__/saved_query_table.test.tsx.snap b/public/components/explorer/home_table/__tests__/__snapshots__/saved_query_table.test.tsx.snap
new file mode 100644
index 0000000000..fa0ee7e42a
--- /dev/null
+++ b/public/components/explorer/home_table/__tests__/__snapshots__/saved_query_table.test.tsx.snap
@@ -0,0 +1,1686 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Saved query table component Renders saved query table 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Type
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="field_value_selection_0"
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="euiFilterGroup__popoverPanel"
+ panelPaddingSize="none"
+ withTitle={false}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Type
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Select all rows
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name
+
+
+
+
+
+
+
+
+
+
+ Type
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name
+
+
+
+
+ Mock Flight count by destination save to panel
+
+
+
+
+
+
+
+
+ Type
+
+
+
+ Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name
+
+
+
+
+ Mock Flight count by destination
+
+
+
+
+
+
+
+
+ Type
+
+
+
+ Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ :
+ 10
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Rows per page
+
+ :
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/explorer/home_table/__tests__/saved_query_table.test.tsx b/public/components/explorer/home_table/__tests__/saved_query_table.test.tsx
new file mode 100644
index 0000000000..c8e4eee8bd
--- /dev/null
+++ b/public/components/explorer/home_table/__tests__/saved_query_table.test.tsx
@@ -0,0 +1,35 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { SavedQueryTable } from '../saved_query_table';
+import { SAVED_HISTORIES } from '../../../../../test/event_analytics_constants';
+
+describe('Saved query table component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders saved query table', async () => {
+ const handleHistoryClick = jest.fn();
+ const handleSelectHistory = jest.fn();
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
\ No newline at end of file
diff --git a/public/components/explorer/home_table/saved_query_table.tsx b/public/components/explorer/home_table/saved_query_table.tsx
new file mode 100644
index 0000000000..0588232a52
--- /dev/null
+++ b/public/components/explorer/home_table/saved_query_table.tsx
@@ -0,0 +1,150 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useState, useRef } from 'react';
+import { EuiLink, EuiInMemoryTable, EuiIcon } from '@elastic/eui';
+import { FILTER_OPTIONS } from '../../../../common/constants/explorer';
+
+interface savedQueryTableProps {
+ savedHistories: Array;
+ handleHistoryClick: (objectId: string) => void;
+ handleSelectHistory: (selectedHistories: Array) => void;
+ isTableLoading: boolean;
+ selectedHistories: Array;
+}
+
+export function SavedQueryTable({
+ savedHistories,
+ handleHistoryClick,
+ handleSelectHistory,
+ isTableLoading,
+}: savedQueryTableProps) {
+ const [pageIndex, setPageIndex] = useState(0);
+ const [pageSize, setPageSize] = useState(10);
+ const pageIndexRef = useRef();
+ pageIndexRef.current = pageIndex;
+ const pageSizeRef = useRef();
+ pageSizeRef.current = pageSize;
+
+ const onTableChange = ({ page = {} }) => {
+ const { index: pageIndex, size: pageSize } = page;
+
+ setPageIndex(pageIndex);
+ setPageSize(pageSize);
+ };
+
+ const columns = [
+ {
+ field: 'type',
+ name: '',
+ sortable: true,
+ width: '40px',
+ render: (item: any) => {
+ if (item == 'Visualization') {
+ return (
+
+
+
+ );
+ } else {
+ return (
+
+
+
+ );
+ }
+ },
+ },
+ {
+ field: 'data',
+ name: 'Name',
+ width: '70%',
+ sortable: true,
+ truncateText: true,
+ render: (item: any) => {
+ return (
+ {
+ handleHistoryClick(item.objectId);
+ }}
+ data-test-subj="eventHome__savedQueryTableName"
+ >
+ {item.name}
+
+ );
+ },
+ },
+ {
+ field: 'type',
+ name: 'Type',
+ },
+ ];
+
+ const histories = savedHistories.map((h) => {
+ const isSavedVisualization = h.hasOwnProperty('savedVisualization');
+ const savedObject = isSavedVisualization ? h.savedVisualization : h.savedQuery;
+ const curType = isSavedVisualization ? 'savedVisualization' : 'savedQuery';
+ const record = {
+ objectId: h.objectId,
+ objectType: curType,
+ name: savedObject.name,
+ query: savedObject.query,
+ date_start: savedObject.selected_date_range.start,
+ date_end: savedObject.selected_date_range.end,
+ timestamp: savedObject.selected_timestamp?.name,
+ fields: savedObject.selected_fields?.tokens || [],
+ };
+ return {
+ id: h.objectId,
+ data: record,
+ name: savedObject.name,
+ type: isSavedVisualization ? 'Visualization' : 'Query',
+ };
+ });
+
+ const search = {
+ box: {
+ incremental: true,
+ },
+ filters: [
+ {
+ type: 'field_value_selection',
+ field: 'type',
+ name: 'Type',
+ multiSelect: false,
+ options: FILTER_OPTIONS.map((i) => ({
+ value: i,
+ name: i,
+ view: i,
+ })),
+ },
+ ],
+ };
+
+ const pagination = {
+ pageIndex,
+ pageSize,
+ totalItemCount: histories.length,
+ pageSizeOptions: [5, 10, 20, 50],
+ };
+
+ return (
+ {
+ handleSelectHistory(selectedHistories);
+ },
+ }}
+ />
+ );
+}
diff --git a/public/components/explorer/hooks/index.ts b/public/components/explorer/hooks/index.ts
new file mode 100644
index 0000000000..68b898f14e
--- /dev/null
+++ b/public/components/explorer/hooks/index.ts
@@ -0,0 +1,8 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { useFetchEvents } from './use_fetch_events';
+export { useFetchVisualizations } from './use_fetch_visualizations';
+export { TabContext } from './use_tab_context';
diff --git a/public/components/explorer/hooks/use_fetch_events.ts b/public/components/explorer/hooks/use_fetch_events.ts
new file mode 100644
index 0000000000..8abd87c997
--- /dev/null
+++ b/public/components/explorer/hooks/use_fetch_events.ts
@@ -0,0 +1,229 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { useState, useRef } from 'react';
+import { batch } from 'react-redux';
+import { isEmpty } from 'lodash';
+import { useDispatch, useSelector } from 'react-redux';
+import { IField } from 'common/types/explorer';
+import {
+ FINAL_QUERY,
+ SELECTED_FIELDS,
+ UNSELECTED_FIELDS,
+ AVAILABLE_FIELDS,
+ QUERIED_FIELDS,
+} from '../../../../common/constants/explorer';
+import { fetchSuccess, reset as queryResultReset } from '../slices/query_result_slice';
+import { selectQueries } from '../slices/query_slice';
+import { reset as visualizationReset } from '../slices/visualization_slice';
+import { updateFields, sortFields, selectFields } from '../slices/field_slice';
+import PPLService from '../../../services/requests/ppl';
+
+interface IFetchEventsParams {
+ pplService: PPLService;
+ requestParams: { tabId: string };
+}
+
+export const useFetchEvents = ({ pplService, requestParams }: IFetchEventsParams) => {
+ const dispatch = useDispatch();
+ const [isEventsLoading, setIsEventsLoading] = useState(false);
+ const queries = useSelector(selectQueries);
+ const fields = useSelector(selectFields);
+ const [response, setResponse] = useState();
+ const queriesRef = useRef();
+ const fieldsRef = useRef();
+ const responseRef = useRef();
+ queriesRef.current = queries;
+ fieldsRef.current = fields;
+ responseRef.current = response;
+
+ const fetchEvents = async (
+ { query }: { query: string },
+ format: string,
+ handler: (res: any) => void,
+ errorHandler?: (error: any) => void
+ ) => {
+ setIsEventsLoading(true);
+ await pplService
+ .fetch(
+ {
+ query,
+ format,
+ },
+ errorHandler
+ )
+ .then((res: any) => {
+ handler(res);
+ })
+ .catch((err: any) => {
+ console.error(err);
+ })
+ .finally(() => {
+ setIsEventsLoading(false);
+ });
+ };
+
+ const dispatchOnGettingHis = (res: any) => {
+ const selectedFields: Array = fieldsRef.current![requestParams.tabId][
+ SELECTED_FIELDS
+ ].map((field: IField) => field.name);
+ setResponse(res);
+ batch(() => {
+ dispatch(
+ queryResultReset({
+ tabId: requestParams.tabId,
+ })
+ );
+ dispatch(
+ fetchSuccess({
+ tabId: requestParams.tabId,
+ data: {
+ ...res,
+ },
+ })
+ );
+ dispatch(
+ updateFields({
+ tabId: requestParams.tabId,
+ data: {
+ [UNSELECTED_FIELDS]: res?.schema ? [...res.schema] : [],
+ [QUERIED_FIELDS]: [],
+ [AVAILABLE_FIELDS]: res?.schema
+ ? isEmpty(selectedFields)
+ ? [...res.schema]
+ : [
+ ...res?.schema.filter(
+ (curField: IField) => !selectedFields.includes(curField.name)
+ ),
+ ]
+ : [],
+ },
+ })
+ );
+ dispatch(
+ sortFields({
+ tabId: requestParams.tabId,
+ data: [AVAILABLE_FIELDS, UNSELECTED_FIELDS],
+ })
+ );
+ dispatch(
+ visualizationReset({
+ tabId: requestParams.tabId,
+ })
+ );
+ });
+ };
+
+ const dispatchOnNoHis = (res: any) => {
+ setResponse(res);
+ batch(() => {
+ dispatch(
+ queryResultReset({
+ tabId: requestParams.tabId,
+ })
+ );
+ dispatch(
+ updateFields({
+ tabId: requestParams.tabId,
+ data: {
+ [SELECTED_FIELDS]: [],
+ [UNSELECTED_FIELDS]: [],
+ [QUERIED_FIELDS]: [],
+ [AVAILABLE_FIELDS]: res?.schema ? [...res.schema] : [],
+ },
+ })
+ );
+ dispatch(
+ sortFields({
+ tabId: requestParams.tabId,
+ data: [AVAILABLE_FIELDS],
+ })
+ );
+ dispatch(
+ visualizationReset({
+ tabId: requestParams.tabId,
+ })
+ );
+ });
+ };
+
+ const getLiveTail = (query: string = '', errorHandler?: (error: any) => void) => {
+ const cur = queriesRef.current;
+ const searchQuery = isEmpty(query) ? cur![requestParams.tabId][FINAL_QUERY] : query;
+ fetchEvents(
+ { query: searchQuery },
+ 'jdbc',
+ (res: any) => {
+ if (!isEmpty(res.jsonData)) {
+ if (!isEmpty(responseRef.current)) {
+ res.jsonData = res.jsonData.concat(responseRef.current.jsonData);
+ res.datarows = res.datarows.concat(responseRef.current.datarows);
+ res.total = res.total + responseRef.current.total;
+ res.size = res.size + responseRef.current.size;
+ }
+ dispatchOnGettingHis(res);
+ }
+ if (isEmpty(res.jsonData) && isEmpty(responseRef.current)) {
+ dispatchOnNoHis(res);
+ }
+ },
+ errorHandler
+ );
+ };
+
+ const getEvents = (query: string = '', errorHandler?: (error: any) => void) => {
+ const cur = queriesRef.current;
+ const searchQuery = isEmpty(query) ? cur![requestParams.tabId][FINAL_QUERY] : query;
+ fetchEvents(
+ { query: searchQuery },
+ 'jdbc',
+ (res: any) => {
+ if (!isEmpty(res.jsonData)) {
+ return dispatchOnGettingHis(res);
+ }
+ // when no hits and needs to get available fields to override default timestamp
+ dispatchOnNoHis(res);
+ },
+ errorHandler
+ );
+ };
+
+ const getAvailableFields = (query: string) => {
+ fetchEvents({ query }, 'jdbc', (res: any) => {
+ batch(() => {
+ dispatch(
+ fetchSuccess({
+ tabId: requestParams.tabId,
+ data: {
+ jsonDataAll: res.jsonData,
+ },
+ })
+ );
+ dispatch(
+ updateFields({
+ tabId: requestParams.tabId,
+ data: {
+ [AVAILABLE_FIELDS]: res?.schema ? [...res.schema] : [],
+ },
+ })
+ );
+ dispatch(
+ sortFields({
+ tabId: requestParams.tabId,
+ data: [AVAILABLE_FIELDS, UNSELECTED_FIELDS],
+ })
+ );
+ });
+ });
+ };
+
+ return {
+ isEventsLoading,
+ getLiveTail,
+ getEvents,
+ getAvailableFields,
+ fetchEvents,
+ };
+};
diff --git a/public/components/explorer/hooks/use_fetch_visualizations.ts b/public/components/explorer/hooks/use_fetch_visualizations.ts
new file mode 100644
index 0000000000..c60492c8c9
--- /dev/null
+++ b/public/components/explorer/hooks/use_fetch_visualizations.ts
@@ -0,0 +1,130 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { useState, useRef } from 'react';
+import { batch, useDispatch, useSelector } from 'react-redux';
+import {
+ FINAL_QUERY,
+ QUERIED_FIELDS,
+ RAW_QUERY,
+ SELECTED_FIELDS,
+ SELECTED_TIMESTAMP,
+} from '../../../../common/constants/explorer';
+import { render as renderCountDis } from '../slices/count_distribution_slice';
+import { selectQueries } from '../slices/query_slice';
+import { render as renderExplorerVis } from '../slices/visualization_slice';
+import { updateFields, sortFields } from '../slices/field_slice';
+import PPLService from '../../../services/requests/ppl';
+import { fetchSuccess } from '../slices/query_result_slice';
+
+interface IFetchVisualizationsParams {
+ pplService: PPLService;
+ requestParams: { tabId: string };
+}
+
+export const useFetchVisualizations = ({
+ pplService,
+ requestParams,
+}: IFetchVisualizationsParams) => {
+ const dispatch = useDispatch();
+ const [isVisLoading, setIsVisLoading] = useState(false);
+ const queries = useSelector(selectQueries);
+ const queriesRef = useRef();
+ queriesRef.current = queries;
+
+ const fetchVisualizations = async (
+ { query }: { query: string },
+ format: string,
+ handler: (res: any) => void
+ ) => {
+ setIsVisLoading(true);
+
+ await pplService
+ .fetch({
+ query,
+ format,
+ })
+ .then((res: any) => {
+ handler(res);
+ })
+ .catch((err: any) => {
+ console.error(err);
+ })
+ .finally(() => {
+ setIsVisLoading(false);
+ });
+ };
+
+ const getCountVisualizations = (interval: string) => {
+ const cur = queriesRef.current;
+ const rawQuery = cur![requestParams.tabId][FINAL_QUERY];
+ fetchVisualizations(
+ {
+ query: `${rawQuery} | stats count() by span(${
+ cur![requestParams.tabId][SELECTED_TIMESTAMP]
+ }, 1${(interval = interval ? interval : 'm')})`,
+ },
+ 'viz',
+ (res: any) => {
+ dispatch(
+ renderCountDis({
+ tabId: requestParams.tabId,
+ data: res,
+ })
+ );
+ }
+ );
+ };
+
+ const getVisualizations = () => {
+ const cur = queriesRef.current;
+ const rawQuery = cur![requestParams.tabId][FINAL_QUERY];
+ fetchVisualizations(
+ {
+ query: rawQuery,
+ },
+ 'viz',
+ (res: any) => {
+ batch(() => {
+ dispatch(
+ renderExplorerVis({
+ tabId: requestParams.tabId,
+ data: res,
+ })
+ );
+ dispatch(
+ fetchSuccess({
+ tabId: requestParams.tabId,
+ data: {
+ jsonData: res?.jsonData || {},
+ },
+ })
+ );
+ dispatch(
+ updateFields({
+ tabId: requestParams.tabId,
+ data: {
+ [QUERIED_FIELDS]: res?.metadata?.fields || [],
+ [SELECTED_FIELDS]: [],
+ },
+ })
+ );
+ dispatch(
+ sortFields({
+ tabId: requestParams.tabId,
+ data: [QUERIED_FIELDS],
+ })
+ );
+ });
+ }
+ );
+ };
+
+ return {
+ isVisLoading,
+ getVisualizations,
+ getCountVisualizations,
+ };
+};
diff --git a/public/components/explorer/hooks/use_tab_context.ts b/public/components/explorer/hooks/use_tab_context.ts
new file mode 100644
index 0000000000..32e9902c31
--- /dev/null
+++ b/public/components/explorer/hooks/use_tab_context.ts
@@ -0,0 +1,3 @@
+import { createContext } from 'react';
+
+export const TabContext = createContext({});
diff --git a/public/components/explorer/log_explorer.scss b/public/components/explorer/log_explorer.scss
new file mode 100644
index 0000000000..772a5b873b
--- /dev/null
+++ b/public/components/explorer/log_explorer.scss
@@ -0,0 +1,35 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+.queryTabs {
+ .euiTabs {
+ .tab-title {
+ max-width: 8rem;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ }
+ svg {
+ vertical-align: inherit;
+ }
+ .linkNewTag{
+ display: inline-block;
+ text-align: center;
+ font-size: 0.875rem;
+ line-height: 3.5;
+ padding: 0.5rem;
+ min-width: 6rem;
+ }
+ }
+}
+
+.tab-title {
+ display: inline-block;
+ margin-right: 5px;
+}
+
+.search-area {
+ position: relative;
+}
\ No newline at end of file
diff --git a/public/components/explorer/log_explorer.tsx b/public/components/explorer/log_explorer.tsx
new file mode 100644
index 0000000000..dd10d70a76
--- /dev/null
+++ b/public/components/explorer/log_explorer.tsx
@@ -0,0 +1,217 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable react-hooks/exhaustive-deps */
+
+import './log_explorer.scss';
+import React, { useEffect, useMemo, useRef, useState } from 'react';
+import { useDispatch, useSelector, batch } from 'react-redux';
+import { uniqueId, map, isEmpty } from 'lodash';
+import $ from 'jquery';
+import { EuiIcon, EuiText, EuiTabbedContentTab, EuiTabbedContent } from '@elastic/eui';
+import { Explorer } from './explorer';
+import { ILogExplorerProps } from '../../../common/types/explorer';
+import {
+ TAB_TITLE,
+ TAB_ID_TXT_PFX,
+ SAVED_OBJECT_ID,
+ NEW_TAB,
+ REDIRECT_TAB,
+ TAB_EVENT_ID,
+ TAB_CHART_ID,
+ APP_ANALYTICS_TAB_ID_REGEX,
+} from '../../../common/constants/explorer';
+import { selectQueryTabs, setSelectedQueryTab } from './slices/query_tab_slice';
+import { selectQueries } from './slices/query_slice';
+import { selectQueryResult } from './slices/query_result_slice';
+import { initializeTabData, removeTabData } from '../application_analytics/helpers/utils';
+
+const searchBarConfigs = {
+ [TAB_EVENT_ID]: {
+ showSaveButton: true,
+ showSavePanelOptionsList: false,
+ },
+ [TAB_CHART_ID]: {
+ showSaveButton: true,
+ showSavePanelOptionsList: true,
+ },
+};
+
+export const LogExplorer = ({
+ pplService,
+ dslService,
+ savedObjects,
+ timestampUtils,
+ setToast,
+ savedObjectId,
+ getExistingEmptyTab,
+ history,
+ notifications,
+ http,
+}: ILogExplorerProps) => {
+ const dispatch = useDispatch();
+ const tabIds = useSelector(selectQueryTabs).queryTabIds.filter(
+ (tabid: string) => !tabid.match(APP_ANALYTICS_TAB_ID_REGEX)
+ );
+ const tabNames = useSelector(selectQueryTabs).tabNames;
+ const queries = useSelector(selectQueries);
+ const curSelectedTabId = useSelector(selectQueryTabs).selectedQueryTab;
+ const explorerData = useSelector(selectQueryResult);
+ const queryRef = useRef();
+ const tabIdsRef = useRef();
+ const explorerDataRef = useRef();
+ const curSelectedTabIdRef = useRef();
+ queryRef.current = queries;
+ tabIdsRef.current = tabIds;
+ explorerDataRef.current = explorerData;
+ curSelectedTabIdRef.current = curSelectedTabId;
+
+ const [tabCreatedTypes, setTabCreatedTypes] = useState({});
+
+ // Append add-new-tab link to the end of the tab list, and remove it once tabs state changes
+ useEffect(() => {
+ const newLink = $(
+ '+ Add new '
+ ).on('click', () => {
+ addNewTab(NEW_TAB);
+ });
+ $('.queryTabs > .euiTabs').append(newLink);
+ return () => {
+ $('.queryTabs > .euiTabs .linkNewTag').remove();
+ };
+ }, [tabIds]);
+
+ const handleTabClick = (selectedTab: EuiTabbedContentTab) => {
+ history.replace(
+ `/event_analytics/explorer/${queryRef.current![selectedTab.id][SAVED_OBJECT_ID] || ''}`
+ );
+ dispatch(setSelectedQueryTab({ tabId: selectedTab.id }));
+ };
+
+ const handleTabClose = (TabIdToBeClosed: string) => {
+ if (tabIds.length === 1) {
+ setToast('Cannot close last tab.', 'danger');
+ return;
+ }
+
+ const index: number = tabIds.indexOf(TabIdToBeClosed);
+ const curSelectedTab = curSelectedTabIdRef.current;
+ let newIdToFocus = '';
+ if (TabIdToBeClosed === curSelectedTab) {
+ if (index === 0) {
+ newIdToFocus = tabIds[index + 1];
+ } else if (index > 0) {
+ newIdToFocus = tabIds[index - 1];
+ }
+ }
+ removeTabData(dispatch, TabIdToBeClosed, newIdToFocus);
+ };
+
+ const addNewTab = async (where: string) => {
+ // get a new tabId
+ const tabId = uniqueId(TAB_ID_TXT_PFX);
+
+ // create a new tab
+ await initializeTabData(dispatch, tabId, where);
+
+ setTabCreatedTypes((staleState) => {
+ return {
+ ...staleState,
+ [tabId]: where,
+ };
+ });
+
+ return tabId;
+ };
+
+ const dispatchSavedObjectId = async () => {
+ const emptyTabId = getExistingEmptyTab({
+ tabIds: tabIdsRef.current,
+ queries: queryRef.current,
+ explorerData: explorerDataRef.current,
+ });
+ const newTabId = emptyTabId ? emptyTabId : await addNewTab(REDIRECT_TAB);
+ return newTabId;
+ };
+
+ useEffect(() => {
+ if (!isEmpty(savedObjectId)) {
+ dispatchSavedObjectId();
+ }
+ }, []);
+
+ function getQueryTab({
+ tabTitle,
+ tabId,
+ handlesTabClose,
+ }: {
+ tabTitle: string;
+ tabId: string;
+ handlesTabClose: (TabIdToBeClosed: string) => void;
+ }) {
+ return {
+ id: tabId,
+ name: (
+ <>
+
+ {tabTitle}
+ {
+ e.stopPropagation();
+ handlesTabClose(tabId);
+ }}
+ data-test-subj="eventExplorer__tabClose"
+ />
+
+ >
+ ),
+ content: (
+ <>
+
+ >
+ ),
+ };
+ }
+
+ const memorizedTabs = useMemo(() => {
+ const res = map(tabIds, (tabId) => {
+ return getQueryTab({
+ tabTitle: tabNames[tabId] || TAB_TITLE,
+ tabId,
+ handlesTabClose: handleTabClose,
+ });
+ });
+
+ return res;
+ }, [tabIds, tabNames, tabCreatedTypes]);
+
+ return (
+ <>
+ tab.id === curSelectedTabId)}
+ onTabClick={(selectedTab: EuiTabbedContentTab) => handleTabClick(selectedTab)}
+ data-test-subj="eventExplorer__topLevelTabbing"
+ />
+ >
+ );
+};
diff --git a/public/components/explorer/no_results.tsx b/public/components/explorer/no_results.tsx
new file mode 100644
index 0000000000..8020997294
--- /dev/null
+++ b/public/components/explorer/no_results.tsx
@@ -0,0 +1,52 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { FormattedMessage, I18nProvider } from '@osd/i18n/react';
+import { EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText } from '@elastic/eui';
+
+export const NoResults = () => {
+ return (
+
+ <>
+
+
+
+
+
+ }
+ color="warning"
+ iconType="help"
+ data-test-subj="discoverNoResults"
+ />
+ <>
+
+
+
+
+
+
+
+
+
+ >
+
+
+ >
+
+ );
+};
diff --git a/public/components/explorer/reducers/fetch_reducers.ts b/public/components/explorer/reducers/fetch_reducers.ts
new file mode 100644
index 0000000000..6853cee584
--- /dev/null
+++ b/public/components/explorer/reducers/fetch_reducers.ts
@@ -0,0 +1,11 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const fetchSuccess = (state, { payload }) => {
+ state[payload.tabId] = {
+ ...state[payload.tabId],
+ ...payload.data
+ };
+};
\ No newline at end of file
diff --git a/public/components/explorer/reducers/index.ts b/public/components/explorer/reducers/index.ts
new file mode 100644
index 0000000000..9bdf291214
--- /dev/null
+++ b/public/components/explorer/reducers/index.ts
@@ -0,0 +1,6 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { fetchSuccess } from './fetch_reducers';
\ No newline at end of file
diff --git a/public/components/explorer/reducers/query_reducers.ts b/public/components/explorer/reducers/query_reducers.ts
new file mode 100644
index 0000000000..bd4273e73b
--- /dev/null
+++ b/public/components/explorer/reducers/query_reducers.ts
@@ -0,0 +1,10 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const queryChange = (state = {}, action) => {
+ return {
+ ...action.payload
+ };
+};
\ No newline at end of file
diff --git a/public/components/explorer/save_panel/__tests__/__snapshots__/save_panel.test.tsx.snap b/public/components/explorer/save_panel/__tests__/__snapshots__/save_panel.test.tsx.snap
new file mode 100644
index 0000000000..6344e67ecf
--- /dev/null
+++ b/public/components/explorer/save_panel/__tests__/__snapshots__/save_panel.test.tsx.snap
@@ -0,0 +1,695 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Saved query table component Renders saved query table 1`] = `
+
+
+
+ Custom operational dashboards/application
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ [Logs] Web traffic Panel
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ [Logs] Web traffic Panel 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Search existing dashboards or applications by name
+
+
+
+
+
+
+
+ Name
+
+
+
+
+
+
+
+
+
+
+
+
+ Name for your savings
+
+
+
+
+
+
+`;
diff --git a/public/components/explorer/save_panel/__tests__/save_panel.test.tsx b/public/components/explorer/save_panel/__tests__/save_panel.test.tsx
new file mode 100644
index 0000000000..8a907ac2a0
--- /dev/null
+++ b/public/components/explorer/save_panel/__tests__/save_panel.test.tsx
@@ -0,0 +1,40 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { SavePanel } from '../save_panel';
+import { SELECTED_PANELS_OPTIONS } from '../../../../../test/event_analytics_constants';
+import SavedObjects from '../../../../services/saved_objects/event_analytics/saved_objects';
+import httpClientMock from '../../../../../test/__mocks__/httpClientMock';
+
+describe('Saved query table component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders saved query table', async () => {
+ const handleNameChange = jest.fn();
+ const handleOptionChange = jest.fn();
+ const savedObjects = new SavedObjects(httpClientMock);
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
\ No newline at end of file
diff --git a/public/components/explorer/save_panel/index.ts b/public/components/explorer/save_panel/index.ts
new file mode 100644
index 0000000000..de81603f7a
--- /dev/null
+++ b/public/components/explorer/save_panel/index.ts
@@ -0,0 +1,6 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { SavePanel } from './save_panel';
\ No newline at end of file
diff --git a/public/components/explorer/save_panel/save_panel.tsx b/public/components/explorer/save_panel/save_panel.tsx
new file mode 100644
index 0000000000..e18022db5a
--- /dev/null
+++ b/public/components/explorer/save_panel/save_panel.tsx
@@ -0,0 +1,95 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useState } from 'react';
+import { useDispatch, useSelector } from 'react-redux';
+import { EuiTitle, EuiComboBox, EuiFormRow, EuiSpacer, EuiFieldText } from '@elastic/eui';
+import { useEffect } from 'react';
+import { isEmpty } from 'lodash';
+import SavedObjects from '../../../services/saved_objects/event_analytics/saved_objects';
+
+interface ISavedPanelProps {
+ selectedOptions: any;
+ handleNameChange: any;
+ handleOptionChange: any;
+ savedObjects: SavedObjects;
+ savePanelName: string;
+ showOptionList: boolean;
+}
+
+interface CustomPanelOptions {
+ id: string;
+ name: string;
+ dateCreated: string;
+ dateModified: string;
+}
+
+export const SavePanel = ({
+ selectedOptions,
+ handleNameChange,
+ handleOptionChange,
+ savedObjects,
+ savePanelName,
+ showOptionList,
+}: ISavedPanelProps) => {
+ const [options, setOptions] = useState([]);
+
+ const getCustomPabnelList = async (savedObjects: SavedObjects) => {
+ const optionRes = await savedObjects
+ .fetchCustomPanels()
+ .then((res: any) => {
+ return res;
+ })
+ .catch((error: any) => console.error(error));
+ setOptions(optionRes?.panels || []);
+ };
+
+ useEffect(() => {
+ getCustomPabnelList(savedObjects);
+ }, []);
+
+ return (
+ <>
+ {showOptionList && (
+ <>
+
+ {'Custom operational dashboards/application'}
+
+
+ {
+ handleOptionChange(options);
+ }}
+ selectedOptions={selectedOptions}
+ options={options.map((option: CustomPanelOptions) => {
+ return {
+ panel: option,
+ label: option.name,
+ };
+ })}
+ isClearable={true}
+ data-test-subj="eventExplorer__querySaveComboBox"
+ />
+
+ >
+ )}
+
+ Name
+
+
+ {
+ handleNameChange(e.target.value);
+ }}
+ data-test-subj="eventExplorer__querySaveName"
+ />
+
+ >
+ );
+};
diff --git a/public/components/explorer/sidebar/__tests__/__snapshots__/field.test.tsx.snap b/public/components/explorer/sidebar/__tests__/__snapshots__/field.test.tsx.snap
new file mode 100644
index 0000000000..44f6114c26
--- /dev/null
+++ b/public/components/explorer/sidebar/__tests__/__snapshots__/field.test.tsx.snap
@@ -0,0 +1,296 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Field component Renders a sidebar field 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ agent
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ agent
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ agent
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/explorer/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap b/public/components/explorer/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap
new file mode 100644
index 0000000000..2b5fa4647e
--- /dev/null
+++ b/public/components/explorer/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap
@@ -0,0 +1,8651 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Siderbar component Renders empty sidebar component 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Siderbar component Renders sidebar component 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Query fields
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ double_per_ip_bytes
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ double_per_ip_bytes
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ double_per_ip_bytes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ host
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ host
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ host
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ ip_count
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ ip_count
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ip_count
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ per_ip_bytes
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ per_ip_bytes
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ per_ip_bytes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ resp_code
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ resp_code
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ resp_code
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ sum_bytes
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ sum_bytes
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sum_bytes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Selected Fields
+
+
+
+
+
+
+
+
+
+
+
+ Available Fields
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ agent
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ agent
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ agent
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ bytes
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ bytes
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ bytes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ clientip
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ clientip
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ clientip
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ event
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ event
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ event
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ extension
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ extension
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ extension
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ geo
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ geo
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ geo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ host
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ host
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ host
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ index
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ index
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ index
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ ip
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ ip
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ip
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ machine
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ machine
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ machine
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ memory
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ memory
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ memory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ message
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ message
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ phpmemory
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ phpmemory
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ phpmemory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ referer
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ referer
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ referer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ request
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ request
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ request
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ response
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ response
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ response
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ tags
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ tags
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ tags
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Default Timestamp
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ timestamp
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+ Default Timestamp
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ timestamp
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ timestamp
+
+
+
+
+
+
+
+
+ Default Timestamp
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ url
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ url
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ url
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Override
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ utc_time
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ />
+ }
+ closePopover={[Function]}
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+ Override
+
+
+
+
+
+
+
+
+
+ }
+ fieldIcon={
+
+ }
+ fieldName={
+
+ utc_time
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ size="s"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ utc_time
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/explorer/sidebar/__tests__/field.test.tsx b/public/components/explorer/sidebar/__tests__/field.test.tsx
new file mode 100644
index 0000000000..c6660d9346
--- /dev/null
+++ b/public/components/explorer/sidebar/__tests__/field.test.tsx
@@ -0,0 +1,41 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { Field } from '../field';
+import { AGENT_FIELD } from '../../../../../test/event_analytics_constants';
+
+describe('Field component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders a sidebar field', async () => {
+ const onToggleField = jest.fn();
+ const handleOverrideTimestamp = jest.fn();
+ const selectedTimestamp = 'timestamp';
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
\ No newline at end of file
diff --git a/public/components/explorer/sidebar/__tests__/sidebar.test.tsx b/public/components/explorer/sidebar/__tests__/sidebar.test.tsx
new file mode 100644
index 0000000000..0e8e23ec44
--- /dev/null
+++ b/public/components/explorer/sidebar/__tests__/sidebar.test.tsx
@@ -0,0 +1,93 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { Sidebar } from '../sidebar';
+import {
+ SELECTED_FIELDS,
+ AVAILABLE_FIELDS,
+ UNSELECTED_FIELDS,
+ QUERIED_FIELDS
+} from '../../../../../common/constants/explorer';
+import {
+ AVAILABLE_FIELDS as SIDEBAR_AVAILABLE_FIELDS,
+ QUERY_FIELDS,
+ JSON_DATA,
+ JSON_DATA_ALL
+} from '../../../../../test/event_analytics_constants';
+
+describe('Siderbar component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders empty sidebar component', async () => {
+ const explorerFields = {
+ [SELECTED_FIELDS]: [],
+ [AVAILABLE_FIELDS]: [],
+ [UNSELECTED_FIELDS]: [],
+ [QUERIED_FIELDS]: []
+ };
+ const handleAddField = jest.fn();
+ const handleOverrideTimestamp = jest.fn();
+ const selectedTimestamp = 'timestamp';
+ const explorerData = {};
+ const handleRemoveField = jest.fn();
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+
+ it('Renders sidebar component', async () => {
+ const explorerFields = {
+ [SELECTED_FIELDS]: [],
+ [UNSELECTED_FIELDS]: [],
+ [AVAILABLE_FIELDS]: SIDEBAR_AVAILABLE_FIELDS,
+ [QUERIED_FIELDS]: QUERY_FIELDS
+ };
+ const handleAddField = jest.fn();
+ const handleOverrideTimestamp = jest.fn();
+ const selectedTimestamp = 'timestamp';
+ const explorerData = {
+ 'jsonData': JSON_DATA,
+ 'jsonDataAll': JSON_DATA_ALL
+ };
+ const handleRemoveField = jest.fn();
+
+ const wrapper = mount(
+
+ );
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
\ No newline at end of file
diff --git a/public/components/explorer/sidebar/field.tsx b/public/components/explorer/sidebar/field.tsx
new file mode 100644
index 0000000000..3b6b127ae0
--- /dev/null
+++ b/public/components/explorer/sidebar/field.tsx
@@ -0,0 +1,184 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useState } from 'react';
+import { i18n } from '@osd/i18n';
+import { isEqual, toUpper, upperFirst } from 'lodash';
+import {
+ EuiPopover,
+ EuiButtonIcon,
+ EuiToolTip,
+ EuiButton,
+ EuiMark,
+ EuiLoadingSpinner,
+ EuiPopoverTitle,
+ EuiPanel,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiTitle,
+} from '@elastic/eui';
+import { FieldButton } from '../../common/field_button';
+import { FieldIcon } from '../../common/field_icon';
+import { IField } from '../../../../common/types/explorer';
+import { FieldInsights } from './field_insights';
+
+interface IFieldProps {
+ field: IField;
+ selectedTimestamp: string;
+ isOverridingTimestamp: boolean;
+ handleOverrideTimestamp: (timestamp: { name: string; type: string }) => void;
+ selected: boolean;
+ showToggleButton: boolean;
+ showTimestampOverrideButton: boolean;
+ isFieldToggleButtonDisabled: boolean;
+ onToggleField: (field: IField) => void;
+}
+
+export const Field = (props: IFieldProps) => {
+ const {
+ query,
+ field,
+ selectedTimestamp,
+ isOverridingTimestamp,
+ handleOverrideTimestamp,
+ selected,
+ isFieldToggleButtonDisabled = false,
+ showTimestampOverrideButton = true,
+ onToggleField,
+ } = props;
+
+ const [isFieldDetailsOpen, setIsFieldDetailsOpen] = useState(false);
+
+ const addLabelAria = i18n.translate('addButtonAriaLabel', {
+ defaultMessage: 'Add {field} to table',
+ values: { field: field.name },
+ });
+ const removeLabelAria = i18n.translate('removeButtonAriaLabel', {
+ defaultMessage: 'Remove {field} from table',
+ values: { field: field.name },
+ });
+
+ const togglePopover = () => {
+ setIsFieldDetailsOpen((staleState) => !staleState);
+ };
+
+ const toggleField = (field: IField) => {
+ onToggleField(field);
+ };
+
+ const getFieldActionDOM = () => {
+ return (
+ <>
+
+ <>
+ {showTimestampOverrideButton && isEqual(field.type, 'timestamp') ? (
+ isEqual(selectedTimestamp, field.name) ? (
+
+ Default Timestamp
+
+ ) : isOverridingTimestamp ? (
+
+ ) : (
+ handleOverrideTimestamp(field)}
+ data-test-subj="eventExplorer__overrideDefaultTimestamp"
+ >
+ Override
+
+ )
+ ) : null}
+ >
+
+
+ <>
+ {isFieldToggleButtonDisabled ? (
+
+ ) : (
+ ) => {
+ if (e.type === 'click') {
+ e.currentTarget.focus();
+ }
+ e.preventDefault();
+ e.stopPropagation();
+ toggleField(field);
+ }}
+ data-test-subj={`fieldToggle-${field.name}`}
+ aria-label={selected ? removeLabelAria : addLabelAria}
+ />
+ )}
+ >
+
+ >
+ );
+ };
+
+ return (
+ setIsFieldDetailsOpen(false)}
+ anchorPosition="rightUp"
+ panelClassName="dscSidebarItem__fieldPopoverPanel"
+ button={
+ }
+ fieldName={
+
+ {field.name}
+
+ }
+ fieldAction={getFieldActionDOM()}
+ onClick={togglePopover}
+ />
+ }
+ >
+
+
+
+ {toUpper(field.name)}
+
+
+ {upperFirst(field.type)}
+
+
+
+
+ );
+};
diff --git a/public/components/explorer/sidebar/field_insights.tsx b/public/components/explorer/sidebar/field_insights.tsx
new file mode 100644
index 0000000000..fd03ce1f57
--- /dev/null
+++ b/public/components/explorer/sidebar/field_insights.tsx
@@ -0,0 +1,153 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useMemo, useState, useContext, useEffect } from 'react';
+import { indexOf, last } from 'lodash';
+import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiBasicTable } from '@elastic/eui';
+import { getIndexPatternFromRawQuery } from '../../../../common/utils/query_utils';
+import { TabContext } from '../hooks/use_tab_context';
+
+export const FieldInsights = ({ field, query }: any) => {
+ const { pplService } = useContext(TabContext);
+ const { rawQuery } = query;
+ const index = getIndexPatternFromRawQuery(rawQuery);
+ const generalReports = [
+ {
+ id: 'top_values',
+ name: 'Top values',
+ query: `source = ${index} | top 5 ${field.name} | sort - ${field.name}`,
+ format: 'jdbc',
+ },
+ {
+ id: 'rare_values',
+ name: 'Rare values',
+ query: `source = ${index} | rare ${field.name} | sort + ${field.name}`,
+ format: 'jdbc',
+ },
+ ];
+
+ const numericalOnlyReports = [
+ {
+ id: 'average',
+ name: 'Average overtime',
+ query: `source = ${index} | stats avg(${field.name})`,
+ format: 'viz',
+ },
+ {
+ id: 'maximum',
+ name: 'Maximum overtime',
+ query: `source = ${index} | stats max(${field.name})`,
+ format: 'viz',
+ },
+ {
+ id: 'minimum',
+ name: 'Minimum overtime',
+ query: `source = ${index} | stats min(${field.name})`,
+ format: 'viz',
+ },
+ ];
+ const numericalTypes = ['short', 'integer', 'long', 'float', 'double'];
+ const isNumericalField = indexOf(numericalTypes, field.type) > 0;
+ const [curReport, setCurReport] = useState({ ...generalReports[0] });
+ const [reportContent, setReportContent] = useState({});
+
+ const statsInsightsQueries = [
+ {
+ id: 'stats',
+ name: 'Stats',
+ query: `source = ${index} | stats avg(${field.name}), max(${field.name}), min(${field.name})`,
+ format: 'viz',
+ },
+ ];
+
+ const fetchData = async (requests) => {
+ return await Promise.all(
+ requests.map((reqQuery) => {
+ const req = {
+ format: reqQuery.format,
+ query: reqQuery.query,
+ };
+ return getInsights(req);
+ })
+ );
+ };
+
+ useEffect(() => {
+ let requests = [...generalReports];
+ if (isNumericalField) requests = [...requests, ...statsInsightsQueries];
+ fetchData(requests)
+ .then((res) => {
+ // numerical field
+ generalReports.map((report, index) => {
+ if (!res[index]?.jsonData) return;
+ setReportContent((staleState) => {
+ return {
+ ...staleState,
+ [report.id]: res[index]?.jsonData || {},
+ };
+ });
+ });
+ if (res.length > 2) {
+ const statsRes = last(res);
+ if (!statsRes?.metadata) return;
+ numericalOnlyReports.map((rep, index) => {
+ const fieldName = statsRes.metadata?.fields[index]?.name;
+ setReportContent((staleState) => {
+ return {
+ ...staleState,
+ [rep.id]: [{ [field.name]: statsRes.data[fieldName][0] }],
+ };
+ });
+ });
+ }
+ })
+ .catch((error) => console.error(error));
+ }, []);
+
+ const getInsights = async (query: string) => {
+ try {
+ return await pplService.fetch(query);
+ } catch (error) {
+ console.error(error);
+ }
+ };
+
+ const insightsContent = useMemo(() => {
+ const columns = [
+ {
+ field: field.name,
+ name: field.name,
+ },
+ ];
+ const repItems = reportContent[curReport.id] || [];
+
+ return ;
+ }, [curReport, reportContent, field.name]);
+
+ return (
+
+
+
+ {generalReports.map((report) => {
+ return (
+
+ setCurReport(report)}>{report.name}
+
+ );
+ })}
+ {indexOf(numericalTypes, field.type) > 0 &&
+ numericalOnlyReports.map((report) => {
+ return (
+
+ setCurReport(report)}>{report.name}
+
+ );
+ })}
+
+
+ {insightsContent}
+
+ );
+};
diff --git a/public/components/explorer/sidebar/index.ts b/public/components/explorer/sidebar/index.ts
new file mode 100644
index 0000000000..bfd2e650ea
--- /dev/null
+++ b/public/components/explorer/sidebar/index.ts
@@ -0,0 +1,6 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { Sidebar } from './sidebar';
\ No newline at end of file
diff --git a/public/components/explorer/sidebar/sidebar.scss b/public/components/explorer/sidebar/sidebar.scss
new file mode 100644
index 0000000000..8ef4cc8759
--- /dev/null
+++ b/public/components/explorer/sidebar/sidebar.scss
@@ -0,0 +1,112 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+.dscSidebar__container {
+ padding-left: 0 !important;
+ padding-right: 0 !important;
+ background-color: transparent;
+ border-right-color: transparent;
+ border-bottom-color: transparent;
+}
+
+.dscIndexPattern__container {
+ display: flex;
+ align-items: center;
+ height: $euiSize * 3;
+ margin-top: -$euiSizeS;
+}
+
+.dscIndexPattern__triggerButton {
+ @include euiTitle('xs');
+ line-height: $euiSizeXXL;
+}
+
+.dscFieldList {
+ list-style: none;
+ margin-bottom: 0;
+}
+
+.dscFieldListHeader {
+ padding: $euiSizeS $euiSizeS 0 $euiSizeS;
+ background-color: lightOrDarkTheme(tint($euiColorPrimary, 90%), $euiColorLightShade);
+}
+
+.dscFieldList--popular {
+ background-color: lightOrDarkTheme(tint($euiColorPrimary, 90%), $euiColorLightShade);
+}
+
+.dscFieldChooser {
+ padding-left: $euiSize;
+}
+
+.dscFieldChooser__toggle {
+ color: $euiColorMediumShade;
+ margin-left: $euiSizeS !important;
+}
+
+.dscSidebarItem {
+ &:hover,
+ &:focus-within,
+ &[class*='-isActive'] {
+ .dscSidebarItem__action {
+ opacity: 1;
+ }
+ }
+}
+
+/**
+ * 1. Only visually hide the action, so that it's still accessible to screen readers.
+ * 2. When tabbed to, this element needs to be visible for keyboard accessibility.
+ */
+.dscSidebarItem__action {
+ opacity: 0; /* 1 */
+ transition: none;
+
+ &:focus {
+ opacity: 1; /* 2 */
+ }
+ font-size: $euiFontSizeXS;
+ padding: 2px 6px !important;
+ height: 22px !important;
+ min-width: auto !important;
+ .euiButton__content {
+ padding: 0 4px;
+ }
+}
+
+.dscFieldSearch {
+ padding: $euiSizeS;
+}
+
+.dscFieldSearch__toggleButton {
+ width: calc(100% - #{$euiSizeS});
+ color: $euiColorPrimary;
+ padding-left: $euiSizeXS;
+ margin-left: $euiSizeXS;
+}
+
+.dscFieldSearch__filterWrapper {
+ flex-grow: 0;
+}
+
+.dscFieldSearch__formWrapper {
+ padding: $euiSizeM;
+}
+
+.dscFieldDetails {
+ color: $euiTextColor;
+ margin-bottom: $euiSizeS;
+}
+
+.dscSidebarItem__fieldPopoverPanel {
+ min-width: 300px;
+ max-width: 600px;
+ max-height: 600px;
+ overflow-y: scroll;
+}
+
+.override_timestamp_loading {
+ vertical-align: middle;
+}
diff --git a/public/components/explorer/sidebar/sidebar.tsx b/public/components/explorer/sidebar/sidebar.tsx
new file mode 100644
index 0000000000..2d520dd4d0
--- /dev/null
+++ b/public/components/explorer/sidebar/sidebar.tsx
@@ -0,0 +1,215 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import './sidebar.scss';
+
+import React, { useState } from 'react';
+import { isEmpty } from 'lodash';
+import { EuiTitle, EuiSpacer, EuiButtonIcon, EuiFieldSearch } from '@elastic/eui';
+import { i18n } from '@osd/i18n';
+import { FormattedMessage, I18nProvider } from '@osd/i18n/react';
+import { cssNumber } from 'jquery';
+import { Field } from './field';
+import { IExplorerFields, IField } from '../../../../common/types/explorer';
+
+interface ISidebarProps {
+ query: string;
+ explorerFields: IExplorerFields;
+ explorerData: any;
+ selectedTimestamp: string;
+ isOverridingTimestamp: boolean;
+ isFieldToggleButtonDisabled: boolean;
+ handleOverrideTimestamp: (timestamp: { name: string; type: string }) => void;
+ handleAddField: (field: IField) => void;
+ handleRemoveField: (field: IField) => void;
+}
+
+export const Sidebar = (props: ISidebarProps) => {
+ const {
+ query,
+ explorerFields,
+ explorerData,
+ selectedTimestamp,
+ isOverridingTimestamp,
+ isFieldToggleButtonDisabled,
+ handleOverrideTimestamp,
+ handleAddField,
+ handleRemoveField,
+ } = props;
+
+ const [showFields, setShowFields] = useState(false);
+ const [searchTerm, setSearchTerm] = useState('');
+
+ return (
+
+
+
+
+ {
+ setSearchTerm(e.target.value);
+ }}
+ placeholder="Search field names"
+ value={searchTerm}
+ data-test-subj="eventExplorer__sidebarSearch"
+ />
+
+
+
+ {((explorerData && !isEmpty(explorerData.jsonData) && !isEmpty(explorerFields)) ||
+ !isEmpty(explorerFields.availableFields)) && (
+ <>
+ {explorerFields?.queriedFields && explorerFields.queriedFields?.length > 0 && (
+ <>
+
+
+
+
+
+
+
+ {explorerFields.queriedFields &&
+ explorerFields.queriedFields.map((field) => {
+ return (
+
+
+
+ );
+ })}
+
+ >
+ )}
+
+
+
+
+
+
+
+ {explorerData &&
+ !isEmpty(explorerData.jsonData) &&
+ explorerFields.selectedFields &&
+ explorerFields.selectedFields.map((field) => {
+ return (
+
+
+
+ );
+ })}
+
+
+
+
+
+
+
+
+ setShowFields(!showFields)}
+ aria-label={
+ showFields
+ ? i18n.translate(
+ 'discover.fieldChooser.filter.indexAndFieldsSectionHideAriaLabel',
+ {
+ defaultMessage: 'Hide fields',
+ }
+ )
+ : i18n.translate(
+ 'discover.fieldChooser.filter.indexAndFieldsSectionShowAriaLabel',
+ {
+ defaultMessage: 'Show fields',
+ }
+ )
+ }
+ />
+
+
+
+ {explorerFields.availableFields &&
+ explorerFields.availableFields
+ .filter((field) => searchTerm === '' || field.name.indexOf(searchTerm) !== -1)
+ .map((field) => {
+ return (
+
+
+
+ );
+ })}
+
+ >
+ )}
+
+
+
+ );
+};
diff --git a/public/components/explorer/slices/count_distribution_slice.ts b/public/components/explorer/slices/count_distribution_slice.ts
new file mode 100644
index 0000000000..ad1331bfa3
--- /dev/null
+++ b/public/components/explorer/slices/count_distribution_slice.ts
@@ -0,0 +1,31 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { createSlice } from '@reduxjs/toolkit';
+import { initialTabId } from '../../../framework/redux/store/shared_state';
+import { REDUX_EXPL_SLICE_COUNT_DISTRIBUTION } from '../../../../common/constants/explorer';
+
+const initialState = {
+ [initialTabId]: {},
+};
+
+export const countDistributionSlice = createSlice({
+ name: REDUX_EXPL_SLICE_COUNT_DISTRIBUTION,
+ initialState,
+ reducers: {
+ render: (state, { payload }) => {
+ state[payload.tabId] = {
+ ...payload.data,
+ };
+ },
+ },
+ extraReducers: (builder) => {},
+});
+
+export const { render } = countDistributionSlice.actions;
+
+export const selectCountDistribution = (state) => state.countDistribution;
+
+export default countDistributionSlice.reducer;
diff --git a/public/components/explorer/slices/field_slice.ts b/public/components/explorer/slices/field_slice.ts
new file mode 100644
index 0000000000..7519d2ef1c
--- /dev/null
+++ b/public/components/explorer/slices/field_slice.ts
@@ -0,0 +1,69 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { createSlice } from '@reduxjs/toolkit';
+import { forEach } from 'lodash';
+import { initialTabId } from '../../../framework/redux/store/shared_state';
+import {
+ SELECTED_FIELDS,
+ UNSELECTED_FIELDS,
+ AVAILABLE_FIELDS,
+ QUERIED_FIELDS,
+ REDUX_EXPL_SLICE_FIELDS,
+} from '../../../../common/constants/explorer';
+import { IField } from '../../../../common/types/explorer';
+
+const initialFields = {
+ [SELECTED_FIELDS]: [],
+ [UNSELECTED_FIELDS]: [],
+ [AVAILABLE_FIELDS]: [],
+ [QUERIED_FIELDS]: [],
+};
+
+const initialState = {
+ [initialTabId]: {
+ ...initialFields,
+ },
+};
+
+export const fieldSlice = createSlice({
+ name: REDUX_EXPL_SLICE_FIELDS,
+ initialState,
+ reducers: {
+ init: (state, { payload }) => {
+ state[payload.tabId] = {
+ ...initialFields,
+ };
+ },
+ updateFields: (state, { payload }) => {
+ state[payload.tabId] = {
+ ...state[payload.tabId],
+ ...payload.data,
+ };
+ },
+ reset: (state, { payload }) => {
+ state[payload.tabId] = {
+ ...initialFields,
+ };
+ },
+ remove: (state, { payload }) => {
+ delete state[payload.tabId];
+ },
+ sortFields: (state, { payload }) => {
+ forEach(payload.data, (toSort: string) => {
+ state[payload.tabId][toSort].sort((prev: IField, cur: IField) =>
+ prev.name.localeCompare(cur.name)
+ );
+ });
+ },
+ },
+ extraReducers: (builder) => {},
+});
+
+export const { init, reset, remove, updateFields, sortFields } = fieldSlice.actions;
+
+export const selectFields = (state) => state.fields;
+
+export default fieldSlice.reducer;
diff --git a/public/components/explorer/slices/query_result_slice.ts b/public/components/explorer/slices/query_result_slice.ts
new file mode 100644
index 0000000000..2d3369d4a5
--- /dev/null
+++ b/public/components/explorer/slices/query_result_slice.ts
@@ -0,0 +1,36 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { createSlice } from '@reduxjs/toolkit';
+import { fetchSuccess as fetchSuccessReducer } from '../reducers';
+import { initialTabId } from '../../../framework/redux/store/shared_state';
+import { REDUX_EXPL_SLICE_QUERY_RESULT } from '../../../../common/constants/explorer';
+
+const initialState = {
+ [initialTabId]: {},
+};
+
+export const queryResultSlice = createSlice({
+ name: REDUX_EXPL_SLICE_QUERY_RESULT,
+ initialState,
+ reducers: {
+ fetchSuccess: fetchSuccessReducer,
+ reset: (state, { payload }) => {
+ state[payload.tabId] = {};
+ },
+ init: (state, { payload }) => {
+ state[payload.tabId] = {};
+ },
+ remove: (state, { payload }) => {
+ delete state[payload.tabId];
+ },
+ },
+});
+
+export const { fetchSuccess, remove, reset, init } = queryResultSlice.actions;
+
+export const selectQueryResult = (state) => state.queryResults;
+
+export default queryResultSlice.reducer;
diff --git a/public/components/explorer/slices/query_slice.ts b/public/components/explorer/slices/query_slice.ts
new file mode 100644
index 0000000000..68677398d5
--- /dev/null
+++ b/public/components/explorer/slices/query_slice.ts
@@ -0,0 +1,72 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { createSlice } from '@reduxjs/toolkit';
+import { initialTabId } from '../../../framework/redux/store/shared_state';
+import {
+ RAW_QUERY,
+ FINAL_QUERY,
+ SELECTED_DATE_RANGE,
+ REDUX_EXPL_SLICE_QUERIES,
+ INDEX,
+ SELECTED_TIMESTAMP,
+ APP_ANALYTICS_TAB_ID_REGEX,
+} from '../../../../common/constants/explorer';
+
+const initialQueryState = {
+ [RAW_QUERY]: '',
+ [FINAL_QUERY]: '',
+ [INDEX]: '',
+ [SELECTED_TIMESTAMP]: '',
+ [SELECTED_DATE_RANGE]: ['now-15m', 'now'],
+};
+
+const appBaseQueryState = {
+ [RAW_QUERY]: '',
+ [FINAL_QUERY]: '',
+ [INDEX]: '',
+ [SELECTED_TIMESTAMP]: '',
+ [SELECTED_DATE_RANGE]: ['now-24h', 'now'],
+};
+
+const initialState = {
+ [initialTabId]: {
+ ...initialQueryState,
+ },
+};
+
+export const queriesSlice = createSlice({
+ name: REDUX_EXPL_SLICE_QUERIES,
+ initialState,
+ reducers: {
+ changeQuery: (state, { payload }) => {
+ state[payload.tabId] = {
+ ...state[payload.tabId],
+ ...payload.query,
+ };
+ },
+ changeDateRange: (state, { payload }) => {
+ state[payload.tabId] = {
+ ...state[payload.tabId],
+ ...payload.data,
+ };
+ },
+ init: (state, { payload }) => {
+ state[payload.tabId] = payload.tabId.match(APP_ANALYTICS_TAB_ID_REGEX)
+ ? appBaseQueryState
+ : initialQueryState;
+ },
+ remove: (state, { payload }) => {
+ delete state[payload.tabId];
+ },
+ },
+ extraReducers: (builder) => {},
+});
+
+export const { changeQuery, changeDateRange, remove, init } = queriesSlice.actions;
+
+export const selectQueries = (state) => state.queries;
+
+export default queriesSlice.reducer;
diff --git a/public/components/explorer/slices/query_tab_slice.ts b/public/components/explorer/slices/query_tab_slice.ts
new file mode 100644
index 0000000000..d509b21ff9
--- /dev/null
+++ b/public/components/explorer/slices/query_tab_slice.ts
@@ -0,0 +1,62 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ createSlice
+} from '@reduxjs/toolkit';
+import { initialTabId } from '../../../framework/redux/store/shared_state';
+import {
+ SELECTED_QUERY_TAB,
+ QUERY_TAB_IDS,
+ NEW_SELECTED_QUERY_TAB,
+ REDUX_EXPL_SLICE_QUERY_TABS
+} from '../../../../common/constants/explorer';
+import { assign } from 'lodash';
+
+const initialState = {
+ queryTabIds: [initialTabId],
+ selectedQueryTab: initialTabId,
+ tabNames: {}
+};
+
+export const queryTabsSlice = createSlice({
+ name: REDUX_EXPL_SLICE_QUERY_TABS,
+ initialState,
+ reducers: {
+ addTab: (state, { payload }) => {
+ state[QUERY_TAB_IDS].push(payload.tabId);
+ state[SELECTED_QUERY_TAB] = payload.tabId;
+ },
+ removeTab: (state, { payload }) => {
+ state[QUERY_TAB_IDS] = state[QUERY_TAB_IDS].filter((tabId) => {
+ return tabId !== payload.tabId;
+ });
+ if (payload[NEW_SELECTED_QUERY_TAB]) {
+ state[SELECTED_QUERY_TAB] = payload[NEW_SELECTED_QUERY_TAB];
+ }
+ },
+ updateTabName: (state, { payload }) => {
+ const newTabNames = {
+ [payload.tabId]: payload.tabName
+ };
+ assign(state.tabNames, newTabNames);
+ },
+ setSelectedQueryTab: (state, { payload }) => {
+ state[SELECTED_QUERY_TAB] = payload.tabId;
+ }
+ },
+ extraReducers: (builder) => {}
+});
+
+export const {
+ addTab,
+ removeTab,
+ setSelectedQueryTab,
+ updateTabName
+} = queryTabsSlice.actions;
+
+export const selectQueryTabs = (state) => state.explorerTabs;
+
+export default queryTabsSlice.reducer;
\ No newline at end of file
diff --git a/public/components/explorer/slices/visualization_slice.ts b/public/components/explorer/slices/visualization_slice.ts
new file mode 100644
index 0000000000..55888a4994
--- /dev/null
+++ b/public/components/explorer/slices/visualization_slice.ts
@@ -0,0 +1,32 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { createSlice } from '@reduxjs/toolkit';
+import { initialTabId } from '../../../framework/redux/store/shared_state';
+import { REDUX_EXPL_SLICE_VISUALIZATION } from '../../../../common/constants/explorer';
+
+const initialState = {
+ [initialTabId]: {},
+};
+
+export const explorerVisualizationSlice = createSlice({
+ name: REDUX_EXPL_SLICE_VISUALIZATION,
+ initialState,
+ reducers: {
+ render: (state, { payload }) => {
+ state[payload.tabId] = payload.data;
+ },
+ reset: (state, { payload }) => {
+ state[payload.tabId] = {};
+ },
+ },
+ extraReducers: (builder) => {},
+});
+
+export const { render, reset } = explorerVisualizationSlice.actions;
+
+export const selectExplorerVisualization = (state) => state.explorerVisualization;
+
+export default explorerVisualizationSlice.reducer;
diff --git a/public/components/explorer/slices/viualization_config_slice.ts b/public/components/explorer/slices/viualization_config_slice.ts
new file mode 100644
index 0000000000..bfdd94af18
--- /dev/null
+++ b/public/components/explorer/slices/viualization_config_slice.ts
@@ -0,0 +1,46 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { createSlice } from '@reduxjs/toolkit';
+import { initialTabId } from '../../../framework/redux/store/shared_state';
+import { REDUX_EXPL_SLICE_VISUALIZATION } from '../../../../common/constants/explorer';
+
+const initialState = {
+ [initialTabId]: {},
+};
+
+export const visualizationConfigSlice = createSlice({
+ name: 'explorerVizConfigs',
+ initialState,
+ reducers: {
+ change: (state, { payload }) => {
+ const { tabId, vizId, data } = payload;
+ let curVizPrevState = {};
+ if (state[tabId] && state[tabId][vizId]) {
+ curVizPrevState = { ...state[tabId][vizId] };
+ }
+ state[tabId] = {
+ ...state[tabId],
+ [vizId]: {
+ ...curVizPrevState,
+ ...data,
+ },
+ };
+ },
+ reset: (state, { payload }) => {
+ state[payload.tabId] = {};
+ },
+ init: (state, { payload }) => {
+ state[payload.tabId] = {};
+ },
+ },
+ extraReducers: (builder) => {},
+});
+
+export const { change, reset, init } = visualizationConfigSlice.actions;
+
+export const selectVisualizationConfig = (state) => state.explorerVisualizationConfig;
+
+export default visualizationConfigSlice.reducer;
diff --git a/public/components/explorer/timechart_header/__tests__/__snapshots__/timechart_header.test.tsx.snap b/public/components/explorer/timechart_header/__tests__/__snapshots__/timechart_header.test.tsx.snap
new file mode 100644
index 0000000000..af8ade96aa
--- /dev/null
+++ b/public/components/explorer/timechart_header/__tests__/__snapshots__/timechart_header.test.tsx.snap
@@ -0,0 +1,333 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Time chart header component Renders Time chart header component 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Minute
+
+
+ Hour
+
+
+ Day
+
+
+ Week
+
+
+ Month
+
+
+ Year
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/explorer/timechart_header/__tests__/timechart_header.test.tsx b/public/components/explorer/timechart_header/__tests__/timechart_header.test.tsx
new file mode 100644
index 0000000000..ba43d1a7dc
--- /dev/null
+++ b/public/components/explorer/timechart_header/__tests__/timechart_header.test.tsx
@@ -0,0 +1,34 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { TimechartHeader } from '../timechart_header';
+import { TIME_INTERVAL_OPTIONS } from '../../../../../common/constants/explorer';
+
+describe.skip('Time chart header component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders Time chart header component', async () => {
+ const onChangeInterval = jest.fn();
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
diff --git a/public/components/explorer/timechart_header/index.ts b/public/components/explorer/timechart_header/index.ts
new file mode 100644
index 0000000000..d9198de35e
--- /dev/null
+++ b/public/components/explorer/timechart_header/index.ts
@@ -0,0 +1,6 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { TimechartHeader } from './timechart_header';
diff --git a/public/components/explorer/timechart_header/timechart_header.tsx b/public/components/explorer/timechart_header/timechart_header.tsx
new file mode 100644
index 0000000000..6515630238
--- /dev/null
+++ b/public/components/explorer/timechart_header/timechart_header.tsx
@@ -0,0 +1,79 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useState, useEffect, useCallback } from 'react';
+import { EuiFlexGroup, EuiFlexItem, EuiToolTip, EuiText, EuiSelect } from '@elastic/eui';
+import { I18nProvider } from '@osd/i18n/react';
+import { i18n } from '@osd/i18n';
+import moment from 'moment';
+
+export interface TimechartHeaderProps {
+ /**
+ * Format of date to be displayed
+ */
+ dateFormat?: string;
+ /**
+ * Range of dates to be displayed
+ */
+ timeRange?: {
+ from: string;
+ to: string;
+ };
+ /**
+ * Interval Options
+ */
+ options: Array<{ text: string; value: string }>;
+ /**
+ * changes the interval
+ */
+ onChangeInterval: (interval: string) => void;
+ /**
+ * selected interval
+ */
+ stateInterval: string;
+}
+
+export function TimechartHeader({
+ options,
+ onChangeInterval
+}: TimechartHeaderProps) {
+ const [interval, setInterval] = useState(options[0].value);
+
+ const handleIntervalChange = (e: React.ChangeEvent) => {
+ setInterval(e.target.value);
+ onChangeInterval(e.target.value.length > 2 ? e.target.value.slice(5) : e.target.value);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/public/components/explorer/utils/index.tsx b/public/components/explorer/utils/index.tsx
new file mode 100644
index 0000000000..f509de965f
--- /dev/null
+++ b/public/components/explorer/utils/index.tsx
@@ -0,0 +1,15 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export {
+ getTrs,
+ getHeaders,
+ fetchSurroundingData,
+ rangeNumDocs,
+ populateDataGrid,
+ isValidTraceId,
+ formatError,
+ findAutoInterval,
+} from './utils';
diff --git a/public/components/explorer/utils/utils.tsx b/public/components/explorer/utils/utils.tsx
new file mode 100644
index 0000000000..fc29e7a2f8
--- /dev/null
+++ b/public/components/explorer/utils/utils.tsx
@@ -0,0 +1,287 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { uniqueId } from 'lodash';
+import React from 'react';
+import moment from 'moment';
+import dateMath from '@elastic/datemath';
+import { IExplorerFields, IField } from '../../../../common/types/explorer';
+import { DocViewRow, IDocType } from '../docTable';
+import { HttpStart } from '../../../../../../src/core/public';
+import PPLService from '../../../services/requests/ppl';
+import { TIME_INTERVAL_OPTIONS } from '../../../../common/constants/explorer';
+import { PPL_DATE_FORMAT, PPL_INDEX_REGEX } from '../../../../common/constants/shared';
+
+// Create Individual table rows for events datagrid and flyouts
+export const getTrs = (
+ http: HttpStart,
+ explorerFields: IField[],
+ limit: number,
+ setLimit: React.Dispatch>,
+ PAGE_SIZE: number,
+ timeStampField: any,
+ explorerFieldsFull: IExplorerFields,
+ pplService: PPLService,
+ rawQuery: string,
+ rowRefs: Array<
+ React.RefObject<{
+ closeAllFlyouts(openDocId: string): void;
+ }>
+ >,
+ setRowRefs: React.Dispatch<
+ React.SetStateAction<
+ Array<
+ React.RefObject<{
+ closeAllFlyouts(openDocId: string): void;
+ }>
+ >
+ >
+ >,
+ onFlyoutOpen: (docId: string) => void,
+ docs: any[] = [],
+ prevTrs: any[] = []
+) => {
+ if (prevTrs.length >= docs.length) return prevTrs;
+
+ // reset limit if no previous table rows
+ if (prevTrs.length === 0 && limit !== PAGE_SIZE) setLimit(PAGE_SIZE);
+ const trs = prevTrs.slice();
+
+ const upperLimit = Math.min(trs.length === 0 ? PAGE_SIZE : limit, docs.length);
+ const tempRefs = rowRefs;
+ for (let i = trs.length; i < upperLimit; i++) {
+ const docId = uniqueId('doc_view');
+ const tempRowRef = React.createRef<{
+ closeAllFlyouts(openDocId: string): void;
+ }>();
+ tempRefs.push(tempRowRef);
+ trs.push(
+
+ );
+ }
+ setRowRefs(tempRefs);
+ return trs;
+};
+
+// Create table headers for events datagrid and flyouts
+export const getHeaders = (fields: any, defaultCols: string[], isFlyout?: boolean) => {
+ let tableHeadContent = null;
+ if (!fields || fields.length === 0) {
+ tableHeadContent = (
+ <>
+ {defaultCols.map((colName: string) => {
+ return {colName} ;
+ })}
+ >
+ );
+ } else {
+ tableHeadContent = fields.map((selField: any) => {
+ return {selField.name} ;
+ });
+
+ if (!isFlyout) {
+ tableHeadContent.unshift( );
+ }
+ }
+
+ return {tableHeadContent} ;
+};
+
+// Populate Events datagrid and flyouts
+export const populateDataGrid = (
+ explorerFields: IExplorerFields,
+ header1: JSX.Element,
+ body1: JSX.Element,
+ header2: JSX.Element,
+ body2: JSX.Element
+) => {
+ return (
+ <>
+
+ {explorerFields?.queriedFields && explorerFields.queriedFields.length > 0 && (
+
+ )}
+ {explorerFields?.queriedFields &&
+ explorerFields?.queriedFields?.length > 0 &&
+ explorerFields.selectedFields?.length === 0 ? null : (
+
+ )}
+
+ >
+ );
+};
+
+/* Builds Final Query for the surrounding events
+ * -> Final Query is as follows:
+ * -> finalQuery = indexPartOfQuery + timeQueryFilter + filterPartOfQuery + sortFilter
+ *
+ * Example Query for 5 new events:
+ * -> rawQuery: source = opensearch_dashboards_sample_data_logs | where geo.src = 'US'
+ * -> indexPartOfQuery = 'source = opensearch_dashboards_sample_data_logs'
+ * -> filterPartOfQuery = '| where geo.src = 'US''
+ * -> timeQueryFilter = ' | where tiimestamp > 2022-01-16 03:26:21.326'
+ * -> sortFilter = '| sort + tiimestamp | head 5'
+ * -> finalQuery = 'source logs_test | where tiimestamp > 2022-01-16 03:26:21.326 | where geo.src = 'US' | sort + timeStampField | head 5'
+ */
+const composeFinalQuery = (
+ rawQuery: string,
+ timeStampField: string,
+ eventTime: string,
+ numDocs: number,
+ typeOfDocs: 'new' | 'old'
+) => {
+ const indexMatchArray = rawQuery.match(PPL_INDEX_REGEX);
+ if (indexMatchArray == null) {
+ throw Error('index not found in Query');
+ }
+ const indexPartOfQuery = indexMatchArray[0];
+ const filterPartOfQuery = rawQuery.replace(PPL_INDEX_REGEX, '');
+ const timeSymbol = typeOfDocs === 'new' ? '>' : '<';
+ const sortSymbol = typeOfDocs === 'new' ? '+' : '-';
+ const timeQueryFilter = ` | where ${timeStampField} ${timeSymbol} '${eventTime}'`;
+ const sortFilter = ` | sort ${sortSymbol} ${timeStampField} | head ${numDocs}`;
+
+ return indexPartOfQuery + timeQueryFilter + filterPartOfQuery + sortFilter;
+};
+
+const createTds = (
+ docs: IDocType[],
+ selectedCols: IField[],
+ getTds: (doc: IDocType, selectedCols: IField[], isFlyout: boolean) => JSX.Element[]
+) => {
+ return docs.map((doc: IDocType) => (
+ {getTds(doc, selectedCols, true).slice(1)}
+ ));
+};
+
+// fetches Surrounding events based on a timestamp
+export const fetchSurroundingData = async (
+ pplService: PPLService,
+ rawQuery: string,
+ timeStampField: string,
+ eventTime: string,
+ numDocs: number,
+ typeOfDocs: 'new' | 'old',
+ setEventsData: React.Dispatch>,
+ setIsError: React.Dispatch>,
+ setLoadingData: React.Dispatch>,
+ selectedCols: IField[],
+ getTds: (doc: IDocType, selectedCols: IField[], isFlyout: boolean) => JSX.Element[]
+) => {
+ let resultCount = 0;
+ let isErred = false;
+ const pplEventTime = moment.utc(eventTime).format(PPL_DATE_FORMAT);
+ setLoadingData(true);
+ setIsError('');
+
+ let finalQuery = '';
+ try {
+ finalQuery = composeFinalQuery(rawQuery, timeStampField, pplEventTime, numDocs, typeOfDocs);
+ } catch (error) {
+ const errorMessage = 'Issue in building surrounding data query';
+ setIsError(errorMessage);
+ isErred = true;
+ console.error(errorMessage, error);
+ setLoadingData(false);
+ return resultCount;
+ }
+
+ await pplService
+ .fetch({ query: finalQuery, format: 'jdbc' })
+ .then((res) => {
+ const resuleData = typeOfDocs == 'new' ? res.jsonData.reverse() : res.jsonData;
+ resultCount = resuleData.length;
+ setEventsData(createTds(resuleData, selectedCols, getTds));
+ })
+ .catch((error: Error) => {
+ setIsError(error.message);
+ isErred = true;
+ console.error(error);
+ })
+ .finally(() => {
+ setLoadingData(false);
+ });
+
+ if (resultCount !== numDocs && !isErred) {
+ const errorMessage =
+ resultCount !== 0
+ ? `Could only find ${resultCount} ${typeOfDocs} event${resultCount === 1 ? '' : 's'}!`
+ : `Could not find any ${typeOfDocs} event!`;
+ setIsError(errorMessage);
+ }
+
+ return resultCount;
+};
+
+// contains 0 <= value <= 10000
+export const rangeNumDocs = (value: number) => {
+ return value > 10000 ? 10000 : value < 0 ? 0 : value;
+};
+
+// check traceId Byte Size
+export const isValidTraceId = (traceId: string) => {
+ return new Blob([traceId]).size === 32;
+};
+
+export const formatError = (name: string, message: string, details: string) => {
+ return {
+ name,
+ message,
+ body: {
+ attributes: {
+ error: {
+ caused_by: {
+ type: '',
+ reason: details,
+ },
+ },
+ },
+ },
+ };
+};
+
+export const findAutoInterval = (start: string = '', end: string = '') => {
+ let minInterval = 'y';
+ if (start?.length === 0 || end?.length === 0 || start === end)
+ return ['d', [...TIME_INTERVAL_OPTIONS]];
+ const momentStart = dateMath.parse(start)!;
+ const momentEnd = dateMath.parse(end)!;
+ const diffSeconds = momentEnd.unix() - momentStart.unix();
+
+ // less than 1 second
+ if (diffSeconds <= 1) minInterval = 'ms';
+ // less than 2 minutes
+ else if (diffSeconds <= 60 * 2) minInterval = 's';
+ // less than 2 hours
+ else if (diffSeconds <= 3600 * 2) minInterval = 'm';
+ // less than 2 days
+ else if (diffSeconds <= 86400 * 2) minInterval = 'h';
+ // less than 1 month
+ else if (diffSeconds <= 86400 * 31) minInterval = 'd';
+ // less than 3 months
+ else if (diffSeconds <= 86400 * 93) minInterval = 'w';
+ // less than 1 year
+ else if (diffSeconds <= 86400 * 366) minInterval = 'M';
+
+ return [minInterval, [{ text: 'Auto', value: 'auto_' + minInterval }, ...TIME_INTERVAL_OPTIONS]];
+};
diff --git a/public/components/explorer/visualizations/__tests__/__snapshots__/datapanel.test.tsx.snap b/public/components/explorer/visualizations/__tests__/__snapshots__/datapanel.test.tsx.snap
new file mode 100644
index 0000000000..3aa9e30e6a
--- /dev/null
+++ b/public/components/explorer/visualizations/__tests__/__snapshots__/datapanel.test.tsx.snap
@@ -0,0 +1,6258 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Data panel component Renders data panel component 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Available fields
+
+
+ }
+ extraAction={
+
+ 20
+
+ }
+ id="1"
+ initialIsOpen={false}
+ isLoading={false}
+ isLoadingMessage={false}
+ paddingSize="none"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Available fields
+
+
+
+
+
+
+
+
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ agent
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ agent
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ agent
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ bytes
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ bytes
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ bytes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ clientip
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ clientip
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ clientip
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ event
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ event
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ event
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ extension
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ extension
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ extension
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ geo
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ geo
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ geo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ host
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ host
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ host
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ index
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ index
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ index
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ ip
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ ip
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ip
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ machine
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ machine
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ machine
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ memory
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ memory
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ memory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ message
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ message
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ phpmemory
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ phpmemory
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ phpmemory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ referer
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ referer
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ referer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ request
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ request
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ request
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ response
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ response
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ response
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ tags
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ tags
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ tags
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ timestamp
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ timestamp
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ timestamp
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ url
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ url
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ url
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ utc_time
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ utc_time
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ utc_time
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/explorer/visualizations/__tests__/__snapshots__/field_accordion.test.tsx.snap b/public/components/explorer/visualizations/__tests__/__snapshots__/field_accordion.test.tsx.snap
new file mode 100644
index 0000000000..3b69e89a7a
--- /dev/null
+++ b/public/components/explorer/visualizations/__tests__/__snapshots__/field_accordion.test.tsx.snap
@@ -0,0 +1,5890 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Visualization fields accordion component Renders fields accordion component 1`] = `
+
+
+
+ Available fields
+
+
+ }
+ extraAction={
+
+ 20
+
+ }
+ id="3367"
+ initialIsOpen={false}
+ isLoading={false}
+ isLoadingMessage={false}
+ paddingSize="none"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Available fields
+
+
+
+
+
+
+
+
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ agent
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ agent
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ agent
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ bytes
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ bytes
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ bytes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ clientip
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ clientip
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ clientip
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ event
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ event
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ event
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ extension
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ extension
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ extension
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ geo
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ geo
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ geo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ host
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ host
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ host
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ index
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ index
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ index
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ ip
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ ip
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ip
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ machine
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ machine
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ machine
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ memory
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ memory
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ memory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ message
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ message
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ message
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ phpmemory
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ phpmemory
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ phpmemory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ referer
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ referer
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ referer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ request
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ request
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ request
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ response
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ response
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ response
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ tags
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ tags
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ tags
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ timestamp
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ timestamp
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ timestamp
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ url
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ url
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ url
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ utc_time
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ utc_time
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ utc_time
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/explorer/visualizations/__tests__/__snapshots__/field_item.test.tsx.snap b/public/components/explorer/visualizations/__tests__/__snapshots__/field_item.test.tsx.snap
new file mode 100644
index 0000000000..f896951af5
--- /dev/null
+++ b/public/components/explorer/visualizations/__tests__/__snapshots__/field_item.test.tsx.snap
@@ -0,0 +1,288 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Visualization field item component Renders field item component 1`] = `
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ agent
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ />
+
+ }
+ className="lnsFieldItem__popoverAnchor"
+ closePopover={[Function]}
+ data-test-subj="lnsFieldListPanelField"
+ display="block"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelClassName="lnsFieldItem__fieldPanel"
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+ }
+ fieldInfoIcon={
+
+ }
+ fieldName={
+
+ agent
+
+ }
+ isActive={false}
+ onClick={[Function]}
+ onDragEnd={[Function]}
+ onDragLeave={[Function]}
+ onDragOver={[Function]}
+ onDragStart={[Function]}
+ onDrop={[Function]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ agent
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/explorer/visualizations/__tests__/__snapshots__/field_list.test.tsx.snap b/public/components/explorer/visualizations/__tests__/__snapshots__/field_list.test.tsx.snap
new file mode 100644
index 0000000000..5ffdbb49d1
--- /dev/null
+++ b/public/components/explorer/visualizations/__tests__/__snapshots__/field_list.test.tsx.snap
@@ -0,0 +1,234 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Visualization field list component Renders field list component 1`] = `
+
+
+
+
+
+
+ Available fields
+
+
+ }
+ extraAction={
+
+ 0
+
+ }
+ id="3327"
+ initialIsOpen={false}
+ isLoading={false}
+ isLoadingMessage={false}
+ paddingSize="none"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Available fields
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/explorer/visualizations/__tests__/__snapshots__/lens_field_icon.test.tsx.snap b/public/components/explorer/visualizations/__tests__/__snapshots__/lens_field_icon.test.tsx.snap
new file mode 100644
index 0000000000..d9cbea0a6e
--- /dev/null
+++ b/public/components/explorer/visualizations/__tests__/__snapshots__/lens_field_icon.test.tsx.snap
@@ -0,0 +1,55 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Visualization field icon component Renders field icon component 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/explorer/visualizations/__tests__/datapanel.test.tsx b/public/components/explorer/visualizations/__tests__/datapanel.test.tsx
new file mode 100644
index 0000000000..d6f99c3389
--- /dev/null
+++ b/public/components/explorer/visualizations/__tests__/datapanel.test.tsx
@@ -0,0 +1,45 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { DataPanel } from '../datapanel';
+import {
+ SELECTED_FIELDS,
+ AVAILABLE_FIELDS,
+ UNSELECTED_FIELDS,
+ QUERIED_FIELDS
+} from '../../../../../common/constants/explorer';
+import {
+ AVAILABLE_FIELDS as SIDEBAR_AVAILABLE_FIELDS,
+ QUERY_FIELDS
+} from '../../../../../test/event_analytics_constants';
+
+describe('Data panel component', () => {
+ configure({ adapter: new Adapter() });
+
+ const explorerFields = {
+ [SELECTED_FIELDS]: [],
+ [UNSELECTED_FIELDS]: [],
+ [AVAILABLE_FIELDS]: SIDEBAR_AVAILABLE_FIELDS,
+ [QUERIED_FIELDS]: QUERY_FIELDS
+ };
+ it('Renders data panel component', async () => {
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
\ No newline at end of file
diff --git a/public/components/explorer/visualizations/__tests__/field_accordion.test.tsx b/public/components/explorer/visualizations/__tests__/field_accordion.test.tsx
new file mode 100644
index 0000000000..d171927b39
--- /dev/null
+++ b/public/components/explorer/visualizations/__tests__/field_accordion.test.tsx
@@ -0,0 +1,36 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { FieldsAccordion } from '../fields_accordion';
+import {
+ AVAILABLE_FIELDS
+} from '../../../../../test/event_analytics_constants';
+
+describe('Visualization fields accordion component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders fields accordion component', async () => {
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
diff --git a/public/components/explorer/visualizations/__tests__/field_item.test.tsx b/public/components/explorer/visualizations/__tests__/field_item.test.tsx
new file mode 100644
index 0000000000..c5e4cd8f83
--- /dev/null
+++ b/public/components/explorer/visualizations/__tests__/field_item.test.tsx
@@ -0,0 +1,36 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { FieldItem } from '../field_item';
+import {
+ AVAILABLE_FIELDS
+} from '../../../../../test/event_analytics_constants';
+
+describe('Visualization field item component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders field item component', async () => {
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
diff --git a/public/components/explorer/visualizations/__tests__/field_list.test.tsx b/public/components/explorer/visualizations/__tests__/field_list.test.tsx
new file mode 100644
index 0000000000..15f97b5c2e
--- /dev/null
+++ b/public/components/explorer/visualizations/__tests__/field_list.test.tsx
@@ -0,0 +1,33 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { FieldList } from '../fieldList';
+import {
+ AVAILABLE_FIELDS
+} from '../../../../../test/event_analytics_constants';
+
+describe('Visualization field list component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders field list component', async () => {
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
diff --git a/public/components/explorer/visualizations/__tests__/lens_field_icon.test.tsx b/public/components/explorer/visualizations/__tests__/lens_field_icon.test.tsx
new file mode 100644
index 0000000000..bdc846feb9
--- /dev/null
+++ b/public/components/explorer/visualizations/__tests__/lens_field_icon.test.tsx
@@ -0,0 +1,29 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { LensFieldIcon } from '../lens_field_icon';
+
+describe('Visualization field icon component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders field icon component', async () => {
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
\ No newline at end of file
diff --git a/public/components/explorer/visualizations/_mixins.scss b/public/components/explorer/visualizations/_mixins.scss
new file mode 100644
index 0000000000..ae22f3905f
--- /dev/null
+++ b/public/components/explorer/visualizations/_mixins.scss
@@ -0,0 +1,54 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+// sass-lint:disable-block indentation, no-color-keywords
+
+// SASSTODO: Create this in EUI
+@mixin lnsOverflowShadowHorizontal {
+ $hideHeight: $euiScrollBarCorner * 1.25;
+ mask-image: linear-gradient(
+ to right,
+ transparentize(red, .9) 0%,
+ transparentize(red, 0) $hideHeight,
+ transparentize(red, 0) calc(100% - #{$hideHeight}),
+ transparentize(red, .9) 100%
+ );
+}
+
+// Static styles for a draggable item
+@mixin lnsDraggable {
+ @include euiSlightShadow;
+ background: lightOrDarkTheme($euiColorEmptyShade, $euiColorLightestShade);
+ border: $euiBorderWidthThin dashed transparent;
+ cursor: grab;
+}
+
+// Static styles for a drop area
+@mixin lnsDroppable {
+ border: $euiBorderWidthThin dashed $euiBorderColor;
+}
+
+// Hovering state for drag item and drop area
+@mixin lnsDragDropHover {
+ &:hover {
+ border: $euiBorderWidthThin dashed $euiColorMediumShade;
+ }
+}
+
+// Style for drop area when there's an item being dragged
+@mixin lnsDroppableActive {
+ background-color: transparentize($euiColorVis0, .9);
+}
+
+// Style for drop area while hovering with item
+@mixin lnsDroppableActiveHover {
+ background-color: transparentize($euiColorVis0, .75);
+ border: $euiBorderWidthThin dashed $euiColorVis0;
+}
+
+// Style for drop area that is not allowed for current item
+@mixin lnsDroppableNotAllowed {
+ opacity: .5;
+}
diff --git a/public/components/explorer/visualizations/_variables.scss b/public/components/explorer/visualizations/_variables.scss
new file mode 100644
index 0000000000..a4248f8142
--- /dev/null
+++ b/public/components/explorer/visualizations/_variables.scss
@@ -0,0 +1,10 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+$lnsPanelMinWidth: $euiSize * 18;
+
+// These sizes also match canvas' page thumbnails for consistency
+$lnsSuggestionHeight: 100px;
+$lnsSuggestionWidth: 150px;
diff --git a/public/components/explorer/visualizations/app.scss b/public/components/explorer/visualizations/app.scss
new file mode 100644
index 0000000000..2f01e1b8e9
--- /dev/null
+++ b/public/components/explorer/visualizations/app.scss
@@ -0,0 +1,47 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+.lnsAppWrapper {
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+}
+
+.lnsApp {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ overflow: hidden;
+}
+
+.lnsApp__header {
+ border-bottom: $euiBorderThin;
+}
+
+.lnsApp__frame {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+}
+
+.lensChartIcon__subdued {
+ fill: $euiTextSubduedColor;
+
+ // Not great, but the easiest way to fix the gray fill when stuck in a button with a fill
+ // Like when selected in a button group
+ .euiButton--fill & {
+ fill: currentColor;
+ }
+}
+
+.lensChartIcon__accent {
+ fill: $euiColorVis0;
+}
diff --git a/public/components/explorer/visualizations/config_panel/DefaultEditorControls.tsx b/public/components/explorer/visualizations/config_panel/DefaultEditorControls.tsx
new file mode 100644
index 0000000000..2e653cd1d4
--- /dev/null
+++ b/public/components/explorer/visualizations/config_panel/DefaultEditorControls.tsx
@@ -0,0 +1,58 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import {
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiButton,
+ EuiButtonEmpty,
+ EuiButtonToggle,
+ EuiToolTip,
+} from '@elastic/eui';
+
+export const DefaultEditorControls = ({
+ isInvalid,
+ isDirty,
+ onConfigUpdate,
+ onConfigDiscard,
+}: any) => {
+ return (
+
+
+
+
+ Reset
+
+
+
+ {isInvalid ? (
+
+
+ Preview
+
+
+ ) : (
+
+ Preview
+
+ )}
+
+
+
+ );
+};
diff --git a/public/components/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap b/public/components/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap
new file mode 100644
index 0000000000..319bdb8280
--- /dev/null
+++ b/public/components/explorer/visualizations/config_panel/__tests__/__snapshots__/config_panel.test.tsx.snap
@@ -0,0 +1,3666 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Config panel component Renders config panel wrapper component with fields 1`] = `
+
+
+ ,
+ "id": "setting-panel",
+ "name": "Settings",
+ },
+ ]
+ }
+ >
+
+
+
+
+
+
+ Settings
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ X-axis
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Advanced
+
+
+
+
+
+
+
+
+
+ here goes advanced setting
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Y-axis
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Select a field
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Advanced
+
+
+
+
+
+
+
+
+
+ here goes advanced setting
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Config panel component Renders empty config panel wrapper component 1`] = `
+
+
+ ,
+ "id": "setting-panel",
+ "name": "Settings",
+ },
+ ]
+ }
+ >
+
+
+
+
+
+
+ Settings
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ X-axis
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Select a field
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Advanced
+
+
+
+
+
+
+
+
+
+ here goes advanced setting
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Y-axis
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Select a field
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Advanced
+
+
+
+
+
+
+
+
+
+ here goes advanced setting
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Config panel component Renders panel item component 1`] = `
+
+
+ ,
+ "id": "setting-panel",
+ "name": "Settings",
+ },
+ ]
+ }
+ >
+
+
+
+
+
+
+ Settings
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ X-axis
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Advanced
+
+
+
+
+
+
+
+
+
+ here goes advanced setting
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Y-axis
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Select a field
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Advanced
+
+
+
+
+
+
+
+
+
+ here goes advanced setting
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/explorer/visualizations/config_panel/__tests__/config_panel.test.tsx b/public/components/explorer/visualizations/config_panel/__tests__/config_panel.test.tsx
new file mode 100644
index 0000000000..24f76212a8
--- /dev/null
+++ b/public/components/explorer/visualizations/config_panel/__tests__/config_panel.test.tsx
@@ -0,0 +1,68 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+// import { ConfigPanel } from '../config_panel';
+import {
+ SELECTED_FIELDS,
+ AVAILABLE_FIELDS,
+ UNSELECTED_FIELDS,
+ QUERIED_FIELDS,
+} from '../../../../../../common/constants/explorer';
+import {
+ AVAILABLE_FIELDS as SIDEBAR_AVAILABLE_FIELDS,
+ QUERY_FIELDS,
+} from '../../../../../../test/event_analytics_constants';
+
+describe.skip('Config panel component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders empty config panel wrapper component', async () => {
+ const wrapper = mount( );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+
+ it('Renders config panel wrapper component with fields', async () => {
+ const explorerFields = {
+ [SELECTED_FIELDS]: [],
+ [UNSELECTED_FIELDS]: [],
+ [AVAILABLE_FIELDS]: SIDEBAR_AVAILABLE_FIELDS,
+ [QUERIED_FIELDS]: QUERY_FIELDS,
+ };
+
+ const wrapper = mount( );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+
+ it('Renders panel item component', async () => {
+ const explorerFields = {
+ [SELECTED_FIELDS]: [],
+ [UNSELECTED_FIELDS]: [],
+ [AVAILABLE_FIELDS]: SIDEBAR_AVAILABLE_FIELDS,
+ [QUERIED_FIELDS]: QUERY_FIELDS,
+ };
+
+ const wrapper = mount( );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
diff --git a/public/components/explorer/visualizations/config_panel/configPanelItem.tsx b/public/components/explorer/visualizations/config_panel/configPanelItem.tsx
new file mode 100644
index 0000000000..681096a635
--- /dev/null
+++ b/public/components/explorer/visualizations/config_panel/configPanelItem.tsx
@@ -0,0 +1,42 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { uniqueId, isEmpty } from 'lodash';
+import { EuiTitle, EuiComboBox, EuiSpacer } from '@elastic/eui';
+
+export const PanelItem = ({
+ paddingTitle,
+ selectedAxis,
+ dropdownList,
+ onSelectChange,
+ isSingleSelection = false,
+}: any) => {
+ const options = dropdownList.map((item) => {
+ return {
+ ...item,
+ label: item.name,
+ };
+ });
+
+ return (
+ <>
+
+ {paddingTitle}
+
+
+
+ >
+ );
+};
diff --git a/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_availability.tsx b/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_availability.tsx
new file mode 100644
index 0000000000..21978fce9a
--- /dev/null
+++ b/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_availability.tsx
@@ -0,0 +1,194 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useCallback, useState } from 'react';
+import {
+ EuiButton,
+ EuiAccordion,
+ EuiFormRow,
+ EuiFieldNumber,
+ EuiColorPicker,
+ EuiSpacer,
+ EuiIcon,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiFieldText,
+ EuiSelect,
+ htmlIdGenerator,
+ EuiText,
+} from '@elastic/eui';
+import { isEmpty } from 'lodash';
+import { PPL_SPAN_REGEX } from '../../../../../../../common/constants/shared';
+import { AvailabilityInfoFlyout } from '../../../../../application_analytics/components/flyout_components/availability_info_flyout';
+
+export interface AvailabilityUnitType {
+ thid: string;
+ name: string;
+ color: string;
+ value: number;
+ expression: string;
+}
+
+export const ConfigAvailability = ({ visualizations, onConfigChange, vizState = {} }: any) => {
+ const [flyoutOpen, setFlyoutOpen] = useState(false);
+ const closeFlyout = () => setFlyoutOpen(false);
+ const addButtonText = '+ Add availability level';
+ const getAvailabilityUnit = () => {
+ return {
+ thid: htmlIdGenerator('avl')(),
+ name: '',
+ color: '#FC0505',
+ value: 0,
+ expression: '≥',
+ };
+ };
+
+ const expressionOptions = [
+ { value: '≥', text: '≥' },
+ { value: '≤', text: '≤' },
+ { value: '>', text: '>' },
+ { value: '<', text: '<' },
+ { value: '=', text: '=' },
+ { value: '≠', text: '≠' },
+ ];
+
+ const availabilityAccordionButton = (
+
+ Availability
+ setFlyoutOpen(true)} size="m" />
+
+ );
+
+ const hasSpanInApp =
+ visualizations.data.query.finalQuery.search(PPL_SPAN_REGEX) > 0 &&
+ visualizations.data.appData.fromApp &&
+ ['bar', 'line'].includes(visualizations.vis.id);
+
+ const handleConfigChange = useCallback(
+ (changes: any) => {
+ onConfigChange({
+ ...vizState,
+ level: changes,
+ });
+ },
+ [onConfigChange, vizState]
+ );
+
+ const handleAddAvailability = useCallback(() => {
+ let res = vizState.level;
+ if (isEmpty(vizState.level)) res = [];
+ handleConfigChange([getAvailabilityUnit(), ...res]);
+ }, [vizState, handleConfigChange]);
+
+ const handleAvailabilityChange = useCallback(
+ (thrId, thrName) => {
+ return (event: any) => {
+ handleConfigChange([
+ ...vizState.level.map((th: AvailabilityUnitType) => {
+ if (thrId !== th.thid) return th;
+ return {
+ ...th,
+ [thrName]: (thrName === 'color' ? event : event?.target?.value) || '',
+ };
+ }),
+ ]);
+ };
+ },
+ [vizState, handleConfigChange]
+ );
+
+ const handleAvailabilityDelete = useCallback(
+ (thrId) => {
+ return (event: any) => {
+ handleConfigChange([
+ ...vizState.level.filter((th: AvailabilityUnitType) => th.thid !== thrId),
+ ]);
+ };
+ },
+ [vizState, handleConfigChange]
+ );
+
+ return (
+ <>
+
+
+
+ {addButtonText}
+
+
+ {!isEmpty(vizState.level) &&
+ vizState.level.map((thr: AvailabilityUnitType) => {
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+ })}
+
+ {flyoutOpen && }
+ >
+ );
+};
diff --git a/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_chart_options.tsx b/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_chart_options.tsx
new file mode 100644
index 0000000000..db74dc66f2
--- /dev/null
+++ b/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_chart_options.tsx
@@ -0,0 +1,61 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useMemo, useCallback } from 'react';
+import { EuiAccordion, EuiSpacer } from '@elastic/eui';
+import { PanelItem } from '../../configPanelItem';
+
+export const ConfigChartOptions = ({
+ visualizations,
+ schemas,
+ vizState,
+ handleConfigChange,
+}: any) => {
+ const { data } = visualizations;
+ const { data: vizData = {}, metadata: { fields = [] } = {} } = data?.rawVizData;
+ const handleConfigurationChange = useCallback(
+ (stateFiledName) => {
+ return (changes) => {
+ handleConfigChange({
+ ...vizState,
+ [stateFiledName]: changes,
+ });
+ };
+ },
+ [handleConfigChange, vizState]
+ );
+
+ const dimensions = useMemo(() => {
+ return schemas.map((schema, index) => {
+ const DimensionComponent = schema.component || PanelItem;
+ const params = {
+ paddingTitle: schema.name,
+ advancedTitle: 'advancedTitle',
+ dropdownList: schema?.options?.map((option) => ({ name: option })) || fields,
+ onSelectChange: handleConfigurationChange(schema.mapTo),
+ isSingleSelection: schema.isSingleSelection,
+ selectedAxis: vizState[schema.mapTo],
+ ...schema.props,
+ };
+ return (
+ <>
+
+
+ >
+ );
+ });
+ }, [schemas, fields, vizState, handleConfigurationChange]);
+
+ return (
+
+ {dimensions}
+
+ );
+};
diff --git a/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_data_links.tsx b/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_data_links.tsx
new file mode 100644
index 0000000000..e183de7b8d
--- /dev/null
+++ b/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_data_links.tsx
@@ -0,0 +1,15 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { EuiAccordion, EuiButton } from '@elastic/eui';
+
+export const ConfigDataLinks = (props: any) => {
+ return (
+
+ + Add link
+
+ );
+};
diff --git a/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_gauge_options.tsx b/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_gauge_options.tsx
new file mode 100644
index 0000000000..6bfca43dd5
--- /dev/null
+++ b/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_gauge_options.tsx
@@ -0,0 +1,83 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useMemo, useCallback } from 'react';
+import { indexOf, toString } from 'lodash';
+import { EuiAccordion, EuiSpacer } from '@elastic/eui';
+import { PanelItem } from '../../configPanelItem';
+import { NUMERICAL_FIELDS } from '../../../../../../../common/constants/shared';
+
+export const ConfigGaugeValueOptions = ({
+ visualizations,
+ schemas,
+ vizState,
+ handleConfigChange,
+ sectionName,
+}: any) => {
+ const { data } = visualizations;
+ const { data: vizData = {}, metadata: { fields = [] } = {} } = data?.rawVizData;
+ const handleConfigurationChange = useCallback(
+ (stateFiledName) => {
+ return (changes) => {
+ handleConfigChange({
+ ...vizState,
+ [stateFiledName]: changes,
+ });
+ };
+ },
+ [handleConfigChange, vizState]
+ );
+
+ const dropdownLists = {
+ series: fields,
+ value: [],
+ };
+
+ if (vizState?.series && vizState?.series[0]?.type) {
+ if (indexOf(NUMERICAL_FIELDS, vizState?.series[0]?.type) > 0) {
+ dropdownLists.value = [...fields];
+ } else {
+ dropdownLists.value = [
+ ...vizData[vizState?.series[0]?.name].map((val) => ({
+ name: val,
+ type: vizState?.series[0]?.type,
+ })),
+ ];
+ }
+ }
+
+ const dimensions = useMemo(() => {
+ return schemas.map((schema, index) => {
+ const DimensionComponent = schema.component || PanelItem;
+ const params = {
+ paddingTitle: schema.name,
+ advancedTitle: 'advancedTitle',
+ dropdownList: dropdownLists[schema.mapTo].map((item) => ({ ...item })),
+ onSelectChange: handleConfigurationChange(schema.mapTo),
+ isSingleSelection: schema.isSingleSelection,
+ selectedAxis: vizState[schema.mapTo],
+ vizState,
+ ...schema.props,
+ };
+ return (
+ <>
+
+
+ >
+ );
+ });
+ }, [schemas, vizState, handleConfigurationChange, dropdownLists]);
+
+ return (
+
+ {dimensions}
+
+ );
+};
diff --git a/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_panel_options.tsx b/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_panel_options.tsx
new file mode 100644
index 0000000000..a1a6d75d98
--- /dev/null
+++ b/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_panel_options.tsx
@@ -0,0 +1,53 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useCallback } from 'react';
+import { EuiFieldText, EuiForm, EuiFormRow, EuiTextArea, EuiAccordion } from '@elastic/eui';
+
+const helpText = 'Name your visualization.';
+
+export const ConfigPanelOptions = ({ visualizations, handleConfigChange, vizState }: any) => {
+ const { dataConfig = {} } = visualizations?.data?.userConfigs;
+
+ const handleConfigurationChange = useCallback(
+ (stateFiledName) => {
+ return (changes) => {
+ handleConfigChange({
+ ...vizState,
+ [stateFiledName]: changes,
+ });
+ };
+ },
+ [handleConfigChange, vizState]
+ );
+
+ return (
+
+
+
+ handleConfigurationChange('title')(e.target.value)}
+ value={vizState?.title || ''}
+ placeholder={'Title'}
+ />
+
+
+ handleConfigurationChange('description')(e.target.value)}
+ />
+
+
+
+ );
+};
diff --git a/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_text.tsx b/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_text.tsx
new file mode 100644
index 0000000000..0fbdaaadd8
--- /dev/null
+++ b/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_text.tsx
@@ -0,0 +1,33 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useCallback } from 'react';
+import { EuiMarkdownEditor, EuiAccordion } from '@elastic/eui';
+
+export const ConfigText = ({ visualizations, schemas, vizState, handleConfigChange }) => {
+ const handleTextChange = useCallback(
+ (stateFiledName) => {
+ return (changes) => {
+ handleConfigChange({
+ ...vizState,
+ [stateFiledName]: changes,
+ });
+ };
+ },
+ [handleConfigChange, vizState]
+ );
+
+ return (
+
+
+
+ );
+};
diff --git a/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_thresholds.tsx b/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_thresholds.tsx
new file mode 100644
index 0000000000..c38e8e812b
--- /dev/null
+++ b/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_thresholds.tsx
@@ -0,0 +1,143 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useCallback } from 'react';
+import {
+ EuiButton,
+ EuiAccordion,
+ EuiFormRow,
+ EuiFieldNumber,
+ EuiColorPicker,
+ EuiSpacer,
+ EuiIcon,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiFieldText,
+ htmlIdGenerator,
+} from '@elastic/eui';
+import { isEmpty } from 'lodash';
+
+export interface ThresholdUnitType {
+ thid: string;
+ name: string;
+ color: string;
+ value: number;
+}
+
+export const ConfigThresholds = ({
+ visualizations,
+ schemas,
+ vizState = [],
+ handleConfigChange,
+ sectionName = 'Thresholds',
+}: any) => {
+ const addButtonText = '+ Add threadshold';
+ const getThresholdUnit = () => {
+ return {
+ thid: htmlIdGenerator('thr')(),
+ name: '',
+ color: '#FC0505',
+ value: 0,
+ };
+ };
+
+ const handleAddThreshold = useCallback(() => {
+ let res = vizState;
+ if (isEmpty(vizState)) res = [];
+ handleConfigChange([getThresholdUnit(), ...res]);
+ }, [vizState, handleConfigChange]);
+
+ const handleThresholdChange = useCallback(
+ (thrId, thrName) => {
+ return (event: any) => {
+ handleConfigChange([
+ ...vizState.map((th: ThresholdUnitType) => {
+ if (thrId !== th.thid) return th;
+ return {
+ ...th,
+ [thrName]: (thrName === 'color' ? event : event?.target?.value) || '',
+ };
+ }),
+ ]);
+ };
+ },
+ [vizState, handleConfigChange]
+ );
+
+ const handleThresholdDelete = useCallback(
+ (thrId) => {
+ return () => {
+ handleConfigChange([...vizState.filter((th: ThresholdUnitType) => th.thid !== thrId)]);
+ };
+ },
+ [vizState, handleConfigChange]
+ );
+
+ return (
+
+
+ {addButtonText}
+
+
+ {!isEmpty(vizState) &&
+ vizState.map((thr: ThresholdUnitType) => {
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+ })}
+
+ );
+};
diff --git a/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_value_options.tsx b/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_value_options.tsx
new file mode 100644
index 0000000000..f3b80e568b
--- /dev/null
+++ b/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_value_options.tsx
@@ -0,0 +1,65 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useMemo, useCallback } from 'react';
+import { EuiAccordion, EuiSpacer } from '@elastic/eui';
+import { PanelItem } from '../../configPanelItem';
+
+export const ConfigValueOptions = ({
+ visualizations,
+ schemas,
+ vizState,
+ handleConfigChange,
+ sectionName,
+}: any) => {
+ const { data } = visualizations;
+ const { data: vizData = {}, metadata: { fields = [] } = {} } = data?.rawVizData;
+ const handleConfigurationChange = useCallback(
+ (stateFiledName) => {
+ return (changes) => {
+ handleConfigChange({
+ ...vizState,
+ [stateFiledName]: changes,
+ });
+ };
+ },
+ [handleConfigChange, vizState]
+ );
+
+ const dimensions = useMemo(() => {
+ return schemas.map((schema, index) => {
+ const DimensionComponent = schema.component || PanelItem;
+ const params = {
+ paddingTitle: schema.name,
+ advancedTitle: 'advancedTitle',
+ dropdownList:
+ schema?.options?.map((option) => ({ name: option })) ||
+ fields.map((item) => ({ ...item })),
+ onSelectChange: handleConfigurationChange(schema.mapTo),
+ isSingleSelection: schema.isSingleSelection,
+ selectedAxis: vizState[schema.mapTo],
+ vizState,
+ ...schema.props,
+ };
+ return (
+ <>
+
+
+ >
+ );
+ });
+ }, [schemas, fields, vizState, handleConfigurationChange]);
+
+ return (
+
+ {dimensions}
+
+ );
+};
diff --git a/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_visualization_selector.tsx b/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_visualization_selector.tsx
new file mode 100644
index 0000000000..d56c3ec52f
--- /dev/null
+++ b/public/components/explorer/visualizations/config_panel/config_editor/config_controls/config_visualization_selector.tsx
@@ -0,0 +1,20 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { EuiAccordion } from '@elastic/eui';
+
+export const ConfigVisualizationSelector = ({ children }: any) => {
+ return (
+
+ {children}
+
+ );
+};
diff --git a/public/components/explorer/visualizations/config_panel/config_editor/config_controls/index.ts b/public/components/explorer/visualizations/config_panel/config_editor/config_controls/index.ts
new file mode 100644
index 0000000000..f75c9126b3
--- /dev/null
+++ b/public/components/explorer/visualizations/config_panel/config_editor/config_controls/index.ts
@@ -0,0 +1,12 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { ConfigPanelOptions } from './config_panel_options';
+export { ConfigValueOptions } from './config_value_options';
+export { ConfigChartOptions } from './config_chart_options';
+export { ConfigDataLinks } from './config_data_links';
+export { ConfigThresholds } from './config_thresholds';
+export { ConfigText } from './config_text';
+export { ConfigGaugeValueOptions } from './config_gauge_options';
diff --git a/public/components/explorer/visualizations/config_panel/config_editor/config_editor.tsx b/public/components/explorer/visualizations/config_panel/config_editor/config_editor.tsx
new file mode 100644
index 0000000000..9b15908539
--- /dev/null
+++ b/public/components/explorer/visualizations/config_panel/config_editor/config_editor.tsx
@@ -0,0 +1,27 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { PlotlyVizEditor } from '../../shared_components/plotly_viz_editor';
+
+export const ConfigEditor = ({
+ spec,
+ onConfigEditorChange,
+ setToast,
+ visualizations,
+ ...rest
+}: any) => {
+ return (
+
+ );
+};
diff --git a/public/components/explorer/visualizations/config_panel/config_editor/default_vis_editor.tsx b/public/components/explorer/visualizations/config_panel/config_editor/default_vis_editor.tsx
new file mode 100644
index 0000000000..0cbad53266
--- /dev/null
+++ b/public/components/explorer/visualizations/config_panel/config_editor/default_vis_editor.tsx
@@ -0,0 +1,49 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { EuiForm, EuiFormRow } from '@elastic/eui';
+import { ConfigPanelOptions } from './config_controls';
+
+export const VizDataPanel = ({ visualizations, onConfigChange, vizState = {}, tabProps }: any) => {
+ const handleConfigEditing = (stateFieldName) => {
+ return (changes) => {
+ onConfigChange({
+ ...vizState,
+ [stateFieldName]: changes,
+ });
+ };
+ };
+
+ const dynamicContent = tabProps.sections.map((section) => {
+ const Editor = section.editor;
+ return (
+
+
+
+ );
+ });
+
+ return (
+
+
+
+
+
+ {dynamicContent}
+
+
+ );
+};
diff --git a/public/components/explorer/visualizations/config_panel/config_panel.scss b/public/components/explorer/visualizations/config_panel/config_panel.scss
new file mode 100644
index 0000000000..2a129f430e
--- /dev/null
+++ b/public/components/explorer/visualizations/config_panel/config_panel.scss
@@ -0,0 +1,125 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+.lnsConfigPanel__addLayerBtn {
+ color: transparentize($euiColorMediumShade, .3);
+ // Remove EuiButton's default shadow to make button more subtle
+ // sass-lint:disable-block no-important
+ box-shadow: none !important;
+ border-color: $euiColorLightShade;
+}
+
+//
+// LAYOUT
+//
+
+$vis-editor-sidebar-min-width: 350px;
+
+.visEditorSidebar {
+ min-width: $vis-editor-sidebar-min-width;
+
+ // a hack for IE, issue: https://github.com/elastic/kibana/issues/66586
+ > .visEditorSidebar__formWrapper {
+ flex-basis: auto;
+ }
+}
+
+.visEditorSidebar__form {
+ @include flex-parent(1, 1, auto);
+ max-width: 100%;
+}
+
+.visEditorSidebar__config {
+ padding: $euiSizeS;
+}
+
+.visEditorSidebar__config-isHidden {
+ display: none;
+}
+
+//
+// NAVIGATION
+//
+
+.visEditorSidebar__titleContainer {
+ padding: $euiSizeS $euiSizeXL $euiSizeS $euiSizeS; // Extra padding on the right for the collapse button
+}
+
+.visEditorSidebar__indexPatternPlaceholder {
+ min-height: $euiSizeXXL;
+ border-bottom: $euiBorderThin;
+}
+
+.visEditorSidebar__nav,
+.visEditorSidebar__linkedSearch {
+ flex-grow: 0;
+}
+
+//
+// SECTIONS
+//
+
+.visEditorSidebar__section {
+ background-color: $euiColorEmptyShade;
+ padding: $euiSizeS;
+ border-radius: $euiBorderRadius;
+
+ + .visEditorSidebar__section {
+ margin-top: $euiSizeS;
+ }
+}
+
+// Collapsible section
+
+.visEditorSidebar__collapsible {
+ background-color: lightOrDarkTheme($euiPageBackgroundColor, $euiColorLightestShade);
+}
+
+.visEditorSidebar__collapsible--marginBottom {
+ margin-bottom: $euiSizeM;
+}
+
+//
+// FORMS
+//
+
+.visEditorSidebar__formRow {
+ display: flex;
+ align-items: center;
+ margin-top: $euiSizeM;
+}
+
+.visEditorSidebar__formLabel {
+ display: flex;
+ align-items: center;
+ flex: 1 1 40%;
+ padding-right: $euiSizeXS;
+}
+
+.visEditorSidebar__formControl {
+ display: flex;
+ align-items: center;
+ flex: 1 1 60%;
+}
+
+.visEditorSidebar__aggGroupAccordionButtonContent {
+ font-size: $euiFontSizeS;
+
+ span {
+ color: $euiColorDarkShade;
+ }
+}
+
+.visEditorSidebar__controls {
+ border-top: $euiBorderThin;
+ padding: $euiSizeS;
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+
+ .visEditorSidebar__autoApplyButton {
+ margin-left: $euiSizeM;
+ }
+}
\ No newline at end of file
diff --git a/public/components/explorer/visualizations/config_panel/config_panel.tsx b/public/components/explorer/visualizations/config_panel/config_panel.tsx
new file mode 100644
index 0000000000..02e7df2e88
--- /dev/null
+++ b/public/components/explorer/visualizations/config_panel/config_panel.tsx
@@ -0,0 +1,258 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import './config_panel.scss';
+
+import React, { useContext, useMemo, useState, useEffect, useCallback } from 'react';
+import { find } from 'lodash';
+import hjson from 'hjson';
+import Mustache from 'mustache';
+import {
+ EuiTabbedContent,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiSpacer,
+ EuiComboBox,
+ EuiPanel,
+ EuiIcon,
+ EuiTabbedContentTab,
+} from '@elastic/eui';
+import { reset as resetVisualizationConfig } from '../../slices/viualization_config_slice';
+import { getDefaultSpec } from '../visualization_specs/default_spec';
+import { TabContext } from '../../hooks';
+import { DefaultEditorControls } from './DefaultEditorControls';
+import { getVisType } from '../../../visualizations/charts/vis_types';
+import { ENABLED_VIS_TYPES } from '../../../../../common/constants/shared';
+
+const CONFIG_LAYOUT_TEMPLATE = `
+{
+ "layout": {},
+ "config": {
+ "scrollZoom": {{config.scrollZoom}},
+ "editable": {{config.editable}},
+ "staticPlot": {{config.staticPlot}},
+ "displayModeBar": {{config.displayModeBar}},
+ "responsive": {{config.responsive}},
+ "doubleClickDelay": {{config.doubleClickDelay}}
+ }
+}
+`;
+
+const HJSON_PARSE_OPTIONS = {
+ keepWsc: true,
+};
+
+const HJSON_STRINGIFY_OPTIONS = {
+ keepWsc: true,
+ condense: 0,
+ bracesSameLine: true,
+};
+
+interface PanelTabType {
+ id: string;
+ name: string;
+ mapTo: string;
+ editor: any;
+ section?: any;
+ content?: any;
+}
+
+export const ConfigPanel = ({ visualizations, setCurVisId, callback }: any) => {
+ const { tabId, curVisId, dispatch, changeVisualizationConfig, setToast } = useContext(
+ TabContext
+ );
+ const { data, vis } = visualizations;
+ const { userConfigs } = data;
+
+ const [vizConfigs, setVizConfigs] = useState({
+ dataConfig: {},
+ layoutConfig: userConfigs?.layoutConfig
+ ? hjson.stringify({ ...userConfigs.layoutConfig }, HJSON_STRINGIFY_OPTIONS)
+ : getDefaultSpec(),
+ availabilityConfig: {},
+ });
+
+ useEffect(() => {
+ setVizConfigs({
+ ...userConfigs,
+ layoutConfig: userConfigs?.layoutConfig
+ ? hjson.stringify({ ...userConfigs.layoutConfig }, HJSON_STRINGIFY_OPTIONS)
+ : getDefaultSpec(),
+ });
+ if (callback) {
+ callback(() => switchToAvailability());
+ }
+ }, [userConfigs, curVisId]);
+
+ const getParsedLayoutConfig = useCallback(
+ (hjsonConfig) =>
+ JSON.parse(
+ Mustache.render(CONFIG_LAYOUT_TEMPLATE, hjson.parse(hjsonConfig, HJSON_PARSE_OPTIONS))
+ ),
+ []
+ );
+
+ const handleConfigUpdate = useCallback(() => {
+ try {
+ dispatch(
+ changeVisualizationConfig({
+ tabId,
+ vizId: curVisId,
+ data: {
+ ...{
+ ...vizConfigs,
+ layoutConfig: hjson.parse(vizConfigs.layoutConfig),
+ },
+ },
+ })
+ );
+ } catch (e: any) {
+ setToast(`Invalid visualization configurations. error: ${e.message}`, 'danger');
+ }
+ }, [tabId, vizConfigs, changeVisualizationConfig, dispatch, setToast, curVisId]);
+
+ const handleConfigChange = (configSchema: string) => {
+ return (configChanges: any) => {
+ setVizConfigs((staleState) => {
+ return {
+ ...staleState,
+ [configSchema]: configChanges,
+ };
+ });
+ };
+ };
+
+ const params = useMemo(() => {
+ return {
+ dataConfig: {
+ visualizations,
+ curVisId,
+ onConfigChange: handleConfigChange('dataConfig'),
+ vizState: vizConfigs.dataConfig,
+ },
+ layoutConfig: {
+ onConfigEditorChange: handleConfigChange('layoutConfig'),
+ spec: vizConfigs.layoutConfig,
+ setToast,
+ },
+ availabilityConfig: {
+ visualizations,
+ curVisId,
+ onConfigChange: handleConfigChange('availabilityConfig'),
+ vizState: vizConfigs.availabilityConfig,
+ },
+ };
+ }, [visualizations, vizConfigs, setToast, curVisId]);
+
+ const tabs: EuiTabbedContentTab[] = useMemo(() => {
+ return vis.editorConfig.panelTabs.map((tab: PanelTabType) => {
+ const Editor = tab.editor;
+ return {
+ id: tab.id,
+ name: tab.name,
+ content: ,
+ };
+ });
+ }, [vis.editorConfig.panelTabs, params]);
+
+ const [currTabId, setCurrTabId] = useState(tabs[0].id);
+
+ const switchToAvailability = () => {
+ setCurrTabId('availability-panel');
+ };
+
+ const onTabClick = (selectedTab: EuiTabbedContentTab) => {
+ setCurrTabId(selectedTab.id);
+ };
+
+ const handleDiscardConfig = () => {
+ dispatch(
+ resetVisualizationConfig({
+ tabId,
+ })
+ );
+ };
+
+ const memorizedVisualizationTypes = useMemo(() => {
+ return ENABLED_VIS_TYPES.map((vs: string) => {
+ const visDefinition = getVisType(vs);
+ return {
+ ...visDefinition,
+ };
+ });
+ }, []);
+
+ const vizSelectableItemRenderer = (option) => {
+ const { iconType, label } = option;
+
+ return (
+
+
+
+ {label}
+
+ );
+ };
+
+ const getSelectedVisDById = useCallback(
+ (visId) => {
+ return find(memorizedVisualizationTypes, (v) => {
+ return v.id === visId;
+ });
+ },
+ [memorizedVisualizationTypes]
+ );
+
+ const vizTypeList = useMemo(() => {
+ return memorizedVisualizationTypes.filter((type) => type.id !== 'horizontal_bar');
+ }, [memorizedVisualizationTypes]);
+
+ return (
+ <>
+
+
+
+ {
+ setCurVisId(visType[0].id);
+ }}
+ fullWidth
+ renderOption={vizSelectableItemRenderer}
+ />
+
+
+
+
+ tab.id === currTabId) || tabs[0]}
+ onTabClick={onTabClick}
+ />
+
+
+
+
+
+
+ >
+ );
+};
diff --git a/public/components/explorer/visualizations/config_panel/index.ts b/public/components/explorer/visualizations/config_panel/index.ts
new file mode 100644
index 0000000000..4c1f8be6e8
--- /dev/null
+++ b/public/components/explorer/visualizations/config_panel/index.ts
@@ -0,0 +1,6 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { ConfigPanel } from './config_panel';
diff --git a/public/components/explorer/visualizations/count_distribution/__tests__/__snapshots__/count_distribution.test.tsx.snap b/public/components/explorer/visualizations/count_distribution/__tests__/__snapshots__/count_distribution.test.tsx.snap
new file mode 100644
index 0000000000..83fe02a99a
--- /dev/null
+++ b/public/components/explorer/visualizations/count_distribution/__tests__/__snapshots__/count_distribution.test.tsx.snap
@@ -0,0 +1,357 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Count distribution component Renders count distribution component with data 1`] = `
+
+
+
+
+
+
+
+`;
+
+exports[`Count distribution component Renders count distribution component with data 2`] = `
+
+
+
+
+
+
+
+`;
+
+exports[`Count distribution component Renders empty count distribution component 1`] = ` `;
diff --git a/public/components/explorer/visualizations/count_distribution/__tests__/count_distribution.test.tsx b/public/components/explorer/visualizations/count_distribution/__tests__/count_distribution.test.tsx
new file mode 100644
index 0000000000..9ae80ea7ce
--- /dev/null
+++ b/public/components/explorer/visualizations/count_distribution/__tests__/count_distribution.test.tsx
@@ -0,0 +1,43 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { CountDistribution } from '../count_distribution';
+import { SAMPLE_VISUALIZATIONS } from '../../../../../../test/event_analytics_constants';
+
+describe('Count distribution component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders empty count distribution component', async () => {
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+
+ it('Renders count distribution component with data', async () => {
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
\ No newline at end of file
diff --git a/public/components/explorer/visualizations/count_distribution/count_distribution.tsx b/public/components/explorer/visualizations/count_distribution/count_distribution.tsx
new file mode 100644
index 0000000000..683873b5f7
--- /dev/null
+++ b/public/components/explorer/visualizations/count_distribution/count_distribution.tsx
@@ -0,0 +1,51 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { LONG_CHART_COLOR } from '../../../../../common/constants/shared';
+import { Plt } from '../../../visualizations/plotly/plot';
+
+export const CountDistribution = ({ countDistribution }: any) => {
+ if (
+ !countDistribution ||
+ !countDistribution.data ||
+ !countDistribution.metadata ||
+ !countDistribution.metadata.fields
+ )
+ return null;
+
+ const {
+ data,
+ metadata: { fields },
+ } = countDistribution;
+
+ const finalData = [
+ {
+ x: [...data[fields[1].name]],
+ y: [...data[fields[0].name]],
+ type: 'bar',
+ name: fields[0],
+ orientation: 'v',
+ },
+ ];
+
+ return (
+
+ );
+};
diff --git a/public/components/explorer/visualizations/count_distribution/index.ts b/public/components/explorer/visualizations/count_distribution/index.ts
new file mode 100644
index 0000000000..7d6456ee06
--- /dev/null
+++ b/public/components/explorer/visualizations/count_distribution/index.ts
@@ -0,0 +1,6 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export * from './count_distribution';
\ No newline at end of file
diff --git a/public/components/explorer/visualizations/datapanel.scss b/public/components/explorer/visualizations/datapanel.scss
new file mode 100644
index 0000000000..9e97b10582
--- /dev/null
+++ b/public/components/explorer/visualizations/datapanel.scss
@@ -0,0 +1,41 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+.lnsInnerIndexPatternDataPanel {
+ width: 100%;
+ height: 100%;
+ padding: $euiSize $euiSize 0;
+}
+
+.lnsInnerIndexPatternDataPanel__header {
+ display: flex;
+ align-items: center;
+ margin-bottom: $euiSizeS;
+}
+
+.lnsInnerIndexPatternDataPanel__fieldItems {
+ // Quick fix for making sure the shadow and focus rings are visible outside the accordion bounds
+ padding: $euiSizeXS;
+}
+
+.lnsInnerIndexPatternDataPanel__textField {
+ @include euiFormControlLayoutPadding(1, 'right');
+ @include euiFormControlLayoutPadding(1, 'left');
+}
+
+.lnsInnerIndexPatternDataPanel__filterType {
+ font-size: $euiFontSizeS;
+ padding: $euiSizeS;
+ border-bottom: 1px solid $euiColorLightestShade;
+}
+
+.lnsInnerIndexPatternDataPanel__filterTypeInner {
+ display: flex;
+ align-items: center;
+
+ .lnsFieldListPanel__fieldIcon {
+ margin-right: $euiSizeS;
+ }
+}
diff --git a/public/components/explorer/visualizations/datapanel.tsx b/public/components/explorer/visualizations/datapanel.tsx
new file mode 100644
index 0000000000..deccff2994
--- /dev/null
+++ b/public/components/explorer/visualizations/datapanel.tsx
@@ -0,0 +1,72 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import './datapanel.scss';
+import './field_item.scss';
+import React, { useState } from 'react';
+import _ from 'lodash';
+import {
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiFormControlLayout,
+ EuiSpacer
+} from '@elastic/eui';
+import { i18n } from '@osd/i18n';
+import { FieldList } from './fieldList';
+
+export const DataPanel = (props: any) => {
+
+ const fields = props.explorerFields?.availableFields;
+
+ const [searchTerm, setSearchTerm] = useState('');
+
+ return (
+
+
+ {},
+ }}
+ >
+ {
+ setSearchTerm(e.target.value);
+ }}
+ aria-label={i18n.translate('xpack.lens.indexPatterns.filterByNameAriaLabel', {
+ defaultMessage: 'Search fields',
+ })}
+ />
+
+
+
+
+ searchTerm === '' || field.name.indexOf(searchTerm) !== -1) }
+ />
+
+
+ );
+}
\ No newline at end of file
diff --git a/public/components/explorer/visualizations/drag_drop/drag_drop.scss b/public/components/explorer/visualizations/drag_drop/drag_drop.scss
new file mode 100644
index 0000000000..cc5399d133
--- /dev/null
+++ b/public/components/explorer/visualizations/drag_drop/drag_drop.scss
@@ -0,0 +1,59 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+@import '../variables';
+@import '../mixins';
+
+.lnsDragDrop {
+ transition: background-color $euiAnimSpeedFast ease-in-out, border-color $euiAnimSpeedFast ease-in-out;
+}
+
+// Draggable item
+.lnsDragDrop-isDraggable {
+ @include lnsDraggable;
+ @include lnsDragDropHover;
+
+ // Include a possible nested button like when using FieldButton
+ > .kbnFieldButton__button {
+ cursor: grab;
+ }
+
+ &:focus {
+ @include euiFocusRing;
+ }
+}
+
+// Draggable item when it is moving
+.lnsDragDrop-isHidden {
+ opacity: 0;
+}
+
+// Drop area
+.lnsDragDrop-isDroppable {
+ @include lnsDroppable;
+}
+
+// Drop area when there's an item being dragged
+.lnsDragDrop-isDropTarget {
+ @include lnsDroppableActive;
+}
+
+// Drop area while hovering with item
+.lnsDragDrop-isActiveDropTarget {
+ @include lnsDroppableActiveHover;
+}
+
+// Drop area that is not allowed for current item
+.lnsDragDrop-isNotDroppable {
+ @include lnsDroppableNotAllowed;
+}
+
+// Drop area will be replacing existing content
+.lnsDragDrop-isReplacing {
+ &,
+ .lnsLayerPanel__triggerLink {
+ text-decoration: line-through;
+ }
+}
diff --git a/public/components/explorer/visualizations/drag_drop/drag_drop.tsx b/public/components/explorer/visualizations/drag_drop/drag_drop.tsx
new file mode 100644
index 0000000000..2d47eb1755
--- /dev/null
+++ b/public/components/explorer/visualizations/drag_drop/drag_drop.tsx
@@ -0,0 +1,249 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import './drag_drop.scss';
+
+import React, { useState, useContext } from 'react';
+import classNames from 'classnames';
+import { DragContext } from './providers';
+// import { trackUiEvent } from '../lens_ui_telemetry';
+
+type DroppableEvent = React.DragEvent;
+
+/**
+ * A function that handles a drop event.
+ */
+export type DropHandler = (item: unknown) => void;
+
+/**
+ * The base props to the DragDrop component.
+ */
+interface BaseProps {
+ /**
+ * The CSS class(es) for the root element.
+ */
+ className?: string;
+
+ /**
+ * The event handler that fires when an item
+ * is dropped onto this DragDrop component.
+ */
+ onDrop?: DropHandler;
+
+ /**
+ * The value associated with this item, if it is draggable.
+ * If this component is dragged, this will be the value of
+ * "dragging" in the root drag/drop context.
+ */
+ value?: unknown;
+
+ /**
+ * Optional comparison function to check whether a value is the dragged one
+ */
+ isValueEqual?: (value1: unknown, value2: unknown) => boolean;
+
+ /**
+ * The React element which will be passed the draggable handlers
+ */
+ children: React.ReactElement;
+
+ /**
+ * Indicates whether or not the currently dragged item
+ * can be dropped onto this component.
+ */
+ droppable?: boolean;
+
+ /**
+ * Additional class names to apply when another element is over the drop target
+ */
+ getAdditionalClassesOnEnter?: () => string;
+
+ /**
+ * The optional test subject associated with this DOM element.
+ */
+ 'data-test-subj'?: string;
+
+ /**
+ * Indicates to the user whether the currently dragged item
+ * will be moved or copied
+ */
+ dragType?: 'copy' | 'move';
+
+ /**
+ * Indicates to the user whether the drop action will
+ * replace something that is existing or add a new one
+ */
+ dropType?: 'add' | 'replace';
+}
+
+/**
+ * The props for a draggable instance of that component.
+ */
+interface DraggableProps extends BaseProps {
+ /**
+ * Indicates whether or not this component is draggable.
+ */
+ draggable: true;
+ /**
+ * The label, which should be attached to the drag event, and which will e.g.
+ * be used if the element will be dropped into a text field.
+ */
+ label: string;
+}
+
+/**
+ * The props for a non-draggable instance of that component.
+ */
+interface NonDraggableProps extends BaseProps {
+ /**
+ * Indicates whether or not this component is draggable.
+ */
+ draggable?: false;
+}
+
+type Props = DraggableProps | NonDraggableProps;
+
+/**
+ * A draggable / droppable item. Items can be both draggable and droppable at
+ * the same time.
+ *
+ * @param props
+ */
+
+export const DragDrop = (props: Props) => {
+ const { dragging, setDragging } = useContext(DragContext);
+ const { value, draggable, droppable, isValueEqual } = props;
+ return (
+
+ );
+};
+
+const DragDropInner = React.memo(function DragDropInner(
+ props: Props & {
+ dragging: unknown;
+ setDragging: (dragging: unknown) => void;
+ isDragging: boolean;
+ isNotDroppable: boolean;
+ }
+) {
+ const [state, setState] = useState({
+ isActive: false,
+ dragEnterClassNames: '',
+ });
+ const {
+ className,
+ onDrop,
+ value,
+ children,
+ droppable,
+ draggable,
+ dragging,
+ setDragging,
+ isDragging,
+ isNotDroppable,
+ dragType = 'copy',
+ dropType = 'add',
+ } = props;
+
+ const isMoveDragging = isDragging && dragType === 'move';
+
+ const classes = classNames(
+ 'lnsDragDrop',
+ {
+ 'lnsDragDrop-isDraggable': draggable,
+ 'lnsDragDrop-isDragging': isDragging,
+ 'lnsDragDrop-isHidden': isMoveDragging,
+ 'lnsDragDrop-isDroppable': !draggable,
+ 'lnsDragDrop-isDropTarget': droppable,
+ 'lnsDragDrop-isActiveDropTarget': droppable && state.isActive,
+ 'lnsDragDrop-isNotDroppable': !isMoveDragging && isNotDroppable,
+ 'lnsDragDrop-isReplacing': droppable && state.isActive && dropType === 'replace',
+ },
+ className,
+ state.dragEnterClassNames
+ );
+
+ const dragStart = (e: DroppableEvent) => {
+ // Setting stopPropgagation causes Chrome failures, so
+ // we are manually checking if we've already handled this
+ // in a nested child, and doing nothing if so...
+ if (e.dataTransfer.getData('text')) {
+ return;
+ }
+
+ // We only can reach the dragStart method if the element is draggable,
+ // so we know we have DraggableProps if we reach this code.
+ e.dataTransfer.setData('text', (props as DraggableProps).label);
+
+ // Chrome causes issues if you try to render from within a
+ // dragStart event, so we drop a setTimeout to avoid that.
+ setTimeout(() => setDragging(value));
+ };
+
+ const dragEnd = (e: DroppableEvent) => {
+ e.stopPropagation();
+ setDragging(undefined);
+ };
+
+ const dragOver = (e: DroppableEvent) => {
+ if (!droppable) {
+ return;
+ }
+
+ e.preventDefault();
+
+ // An optimization to prevent a bunch of React churn.
+ if (!state.isActive) {
+ setState({
+ ...state,
+ isActive: true,
+ dragEnterClassNames: props.getAdditionalClassesOnEnter
+ ? props.getAdditionalClassesOnEnter()
+ : '',
+ });
+ }
+ };
+
+ const dragLeave = () => {
+ setState({ ...state, isActive: false, dragEnterClassNames: '' });
+ };
+
+ const drop = (e: DroppableEvent) => {
+ e.preventDefault();
+ e.stopPropagation();
+
+ setState({ ...state, isActive: false, dragEnterClassNames: '' });
+ setDragging(undefined);
+
+ if (onDrop && droppable) {
+ // trackUiEvent('drop_total');
+ onDrop(dragging);
+ }
+ };
+
+ return React.cloneElement(children, {
+ 'data-test-subj': props['data-test-subj'] || 'lnsDragDrop',
+ className: classNames(children.props.className, classes),
+ onDragOver: dragOver,
+ onDragLeave: dragLeave,
+ onDrop: drop,
+ draggable,
+ onDragEnd: dragEnd,
+ onDragStart: dragStart,
+ });
+});
diff --git a/public/components/explorer/visualizations/drag_drop/index.ts b/public/components/explorer/visualizations/drag_drop/index.ts
new file mode 100644
index 0000000000..e2a5489cd1
--- /dev/null
+++ b/public/components/explorer/visualizations/drag_drop/index.ts
@@ -0,0 +1,7 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export * from './providers';
+export * from './drag_drop';
diff --git a/public/components/explorer/visualizations/drag_drop/providers.tsx b/public/components/explorer/visualizations/drag_drop/providers.tsx
new file mode 100644
index 0000000000..d5105277bb
--- /dev/null
+++ b/public/components/explorer/visualizations/drag_drop/providers.tsx
@@ -0,0 +1,85 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useState, useMemo } from 'react';
+
+/**
+ * The shape of the drag / drop context.
+ */
+export interface DragContextState {
+ /**
+ * The item being dragged or undefined.
+ */
+ dragging: unknown;
+
+ /**
+ * Set the item being dragged.
+ */
+ setDragging: (dragging: unknown) => void;
+}
+
+/**
+ * The drag / drop context singleton, used like so:
+ *
+ * const { dragging, setDragging } = useContext(DragContext);
+ */
+export const DragContext = React.createContext({
+ dragging: undefined,
+ setDragging: () => {},
+});
+
+/**
+ * The argument to DragDropProvider.
+ */
+export interface ProviderProps {
+ /**
+ * The item being dragged. If unspecified, the provider will
+ * behave as if it is the root provider.
+ */
+ dragging: unknown;
+
+ /**
+ * Sets the item being dragged. If unspecified, the provider
+ * will behave as if it is the root provider.
+ */
+ setDragging: (dragging: unknown) => void;
+
+ /**
+ * The React children.
+ */
+ children: React.ReactNode;
+}
+
+/**
+ * A React provider that tracks the dragging state. This should
+ * be placed at the root of any React application that supports
+ * drag / drop.
+ *
+ * @param props
+ */
+export function RootDragDropProvider({ children }: { children: React.ReactNode }) {
+ const [state, setState] = useState<{ dragging: unknown }>({
+ dragging: undefined,
+ });
+ const setDragging = useMemo(() => (dragging: unknown) => setState({ dragging }), [setState]);
+
+ return (
+
+ {children}
+
+ );
+}
+
+/**
+ * A React drag / drop provider that derives its state from a RootDragDropProvider. If
+ * part of a React application is rendered separately from the root, this provider can
+ * be used to enable drag / drop functionality within the disconnected part.
+ *
+ * @param props
+ */
+export function ChildDragDropProvider({ dragging, setDragging, children }: ProviderProps) {
+ const value = useMemo(() => ({ dragging, setDragging }), [setDragging, dragging]);
+ return {children} ;
+}
diff --git a/public/components/explorer/visualizations/drag_drop/readme.md b/public/components/explorer/visualizations/drag_drop/readme.md
new file mode 100644
index 0000000000..8d11cb6226
--- /dev/null
+++ b/public/components/explorer/visualizations/drag_drop/readme.md
@@ -0,0 +1,69 @@
+# Drag / Drop
+
+This is a simple drag / drop mechanism that plays nice with React.
+
+We aren't using EUI or another library, due to the fact that Lens visualizations and datasources may or may not be written in React. Even visualizations which are written in React will end up having their own ReactDOM.render call, and in that sense will be a standalone React application. We want to enable drag / drop across React and native DOM boundaries.
+
+## Getting started
+
+First, place a RootDragDropProvider at the root of your application.
+
+```js
+
+ ... your app here ...
+
+```
+
+If you have a child React application (e.g. a visualization), you will need to pass the drag / drop context down into it. This can be obtained like so:
+
+```js
+const context = useContext(DragContext);
+```
+
+In your child application, place a `ChildDragDropProvider` at the root of that, and spread the context into it:
+
+```js
+
+ ... your child app here ...
+
+```
+
+This enables your child application to share the same drag / drop context as the root application.
+
+## Dragging
+
+An item can be both draggable and droppable at the same time, but for simplicity's sake, we'll treat these two cases separately.
+
+To enable dragging an item, use `DragDrop` with both a `draggable` and a `value` attribute.
+
+```js
+
+ {fields.map(f => (
+
+ {f.name}
+
+ ))}
+
+```
+
+## Dropping
+
+To enable dropping, use `DragDrop` with both a `droppable` attribute and an `onDrop` handler attribute. Droppable should only be set to true if there is an item being dragged, and if a drop of the dragged item is supported.
+
+```js
+const { dragging } = useContext(DragContext);
+
+return (
+ onChange([...items, item])}
+ >
+ {items.map(x => {x.name}
)}
+
+);
+```
+
+## Limitations
+
+Currently this is a very simple drag / drop mechanism. We don't support reordering out of the box, though it could probably be built on top of this solution without modification of the core.
diff --git a/public/components/explorer/visualizations/fieldList.tsx b/public/components/explorer/visualizations/fieldList.tsx
new file mode 100644
index 0000000000..0375cd680c
--- /dev/null
+++ b/public/components/explorer/visualizations/fieldList.tsx
@@ -0,0 +1,35 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { FieldsAccordion } from './fields_accordion';
+
+export const FieldList = (
+ {
+ fields,
+ id
+ }: any
+) => {
+
+ return (
+
+ );
+};
\ No newline at end of file
diff --git a/public/components/explorer/visualizations/field_item.scss b/public/components/explorer/visualizations/field_item.scss
new file mode 100644
index 0000000000..670884bb9d
--- /dev/null
+++ b/public/components/explorer/visualizations/field_item.scss
@@ -0,0 +1,53 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+.lnsFieldItem {
+ .lnsFieldItem__infoIcon {
+ visibility: hidden;
+ opacity: 0;
+ }
+
+ &:hover:not([class*='isActive']) {
+ cursor: grab;
+
+ .lnsFieldItem__infoIcon {
+ visibility: visible;
+ opacity: 1;
+ transition: opacity $euiAnimSpeedFast ease-in-out 1s;
+ }
+ }
+}
+
+.lnsFieldItem--missing {
+ background: lightOrDarkTheme(transparentize($euiColorMediumShade, .9), $euiColorEmptyShade);
+ color: $euiColorDarkShade;
+}
+
+.lnsFieldItem__topValue {
+ margin-bottom: $euiSizeS;
+
+ &:last-of-type {
+ margin-bottom: 0;
+ }
+}
+
+.lnsFieldItem__topValueProgress {
+ background-color: $euiColorLightestShade;
+
+ // sass-lint:disable-block no-vendor-prefixes
+ &::-webkit-progress-bar {
+ background-color: $euiColorLightestShade;
+ }
+}
+
+.lnsFieldItem__fieldPanel {
+ min-width: 260px;
+ max-width: 300px;
+}
+
+.lnsFieldItem__buttonGroup {
+ // Enforce lowercase for buttons or else some browsers inherit all caps from flyout title
+ text-transform: none;
+}
diff --git a/public/components/explorer/visualizations/field_item.tsx b/public/components/explorer/visualizations/field_item.tsx
new file mode 100644
index 0000000000..0405b3df0d
--- /dev/null
+++ b/public/components/explorer/visualizations/field_item.tsx
@@ -0,0 +1,108 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import './field_item.scss';
+
+import React, { useState } from 'react';
+import {
+ EuiIconTip,
+ EuiPopover
+} from '@elastic/eui';
+import { i18n } from '@osd/i18n';
+import { EuiHighlight } from '@elastic/eui';
+import { FieldButton } from '../../common/field_button';
+import { DragDrop } from './drag_drop';
+import { LensFieldIcon } from './lens_field_icon';
+
+import { debouncedComponent } from '../../common/debounced_component';
+
+function wrapOnDot(str?: string) {
+ // u200B is a non-width white-space character, which allows
+ // the browser to efficiently word-wrap right after the dot
+ // without us having to draw a lot of extra DOM elements, etc
+ return str ? str.replace(/\./g, '.\u200B') : '';
+}
+
+export const InnerFieldItem = function InnerFieldItem(props: any) {
+ const {
+ field,
+ highlight,
+ exists,
+ hideDetails,
+ } = props;
+
+ const [infoIsOpen, setOpen] = useState(false);
+
+ function togglePopover() {}
+
+ const lensFieldIcon = ;
+ const lensInfoIcon = (
+
+ );
+ return (
+ ('.application') || undefined}
+ button={
+
+
+ {wrapOnDot(field.name)}
+
+ }
+ fieldInfoIcon={lensInfoIcon}
+ />
+
+ }
+ isOpen={infoIsOpen}
+ closePopover={() => setOpen(false)}
+ anchorPosition="rightUp"
+ panelClassName="lnsFieldItem__fieldPanel"
+ >
+
+ );
+};
+
+export const FieldItem = debouncedComponent(InnerFieldItem);
diff --git a/public/components/explorer/visualizations/field_list.scss b/public/components/explorer/visualizations/field_list.scss
new file mode 100644
index 0000000000..33faa8dfe7
--- /dev/null
+++ b/public/components/explorer/visualizations/field_list.scss
@@ -0,0 +1,25 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * 1. Don't cut off the shadow of the field items
+ */
+
+.lnsIndexPatternFieldList {
+ @include euiOverflowShadow;
+ @include euiScrollBar;
+ margin-left: -$euiSize; /* 1 */
+ position: relative;
+ flex-grow: 1;
+ overflow: auto;
+}
+
+.lnsIndexPatternFieldList__accordionContainer {
+ padding-top: $euiSizeS;
+ position: absolute;
+ top: 0;
+ left: $euiSize; /* 1 */
+ right: $euiSizeXS; /* 1 */
+}
diff --git a/public/components/explorer/visualizations/fields_accordion.tsx b/public/components/explorer/visualizations/fields_accordion.tsx
new file mode 100644
index 0000000000..955558d3d7
--- /dev/null
+++ b/public/components/explorer/visualizations/fields_accordion.tsx
@@ -0,0 +1,75 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import './datapanel.scss';
+import React, { memo, useCallback } from 'react';
+import { i18n } from '@osd/i18n';
+import {
+ EuiText,
+ EuiNotificationBadge,
+ EuiSpacer,
+ EuiAccordion,
+ EuiLoadingSpinner,
+ EuiIconTip,
+} from '@elastic/eui';
+import { FieldItem } from './field_item';
+
+export const InnerFieldsAccordion = function InnerFieldsAccordion({
+ id,
+ label,
+ isFiltered,
+ paginatedFields,
+ showExistenceFetchError,
+}: any) {
+ const renderField = useCallback(
+ (field) => (
+
+ ),
+ []
+ );
+
+ return (
+
+ {label}
+
+ }
+ extraAction={
+ showExistenceFetchError ? (
+
+ ) : true ? (
+
+ {paginatedFields?.length}
+
+ ) : (
+
+ )
+ }
+ >
+
+
+ {paginatedFields && paginatedFields.map(renderField)}
+
+
+ );
+};
+
+export const FieldsAccordion = memo(InnerFieldsAccordion);
diff --git a/public/components/explorer/visualizations/frame_layout.scss b/public/components/explorer/visualizations/frame_layout.scss
new file mode 100644
index 0000000000..8d07d5a0a9
--- /dev/null
+++ b/public/components/explorer/visualizations/frame_layout.scss
@@ -0,0 +1,66 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+$lnsPanelMinWidth: $euiSize * 18;
+
+// These sizes also match canvas' page thumbnails for consistency
+$lnsSuggestionHeight: 100px;
+$lnsSuggestionWidth: 150px;
+
+.lnsFrameLayout {
+ padding: 0;
+ // position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ overflow: hidden;
+ flex-direction: column;
+}
+
+.lnsFrameLayout__pageContent {
+ display: flex;
+ overflow: hidden;
+ flex-grow: 1;
+}
+
+.lnsFrameLayout__pageBody {
+ @include euiScrollBar;
+ min-width: $lnsPanelMinWidth + $euiSizeXL;
+ max-height: 100%;
+ overflow: hidden auto;
+ // Leave out bottom padding so the suggestions scrollbar stays flush to window edge
+ // Leave out left padding so the left sidebar's focus states are visible outside of content bounds
+ // This also means needing to add same amount of margin to page content and suggestion items
+ padding: $euiSize $euiSize 0;
+
+ &:first-child {
+ padding-left: $euiSize;
+ }
+}
+
+.lnsFrameLayout__sidebar {
+ margin: 0 16px 0;
+ flex: 1 0 18%;
+ min-width: $lnsPanelMinWidth + $euiSize;
+ display: flex;
+ flex-direction: column;
+ position: relative;
+}
+
+.lnsFrameLayout__sidebar--right {
+ flex-basis: 25%;
+ background-color: lightOrDarkTheme($euiColorLightestShade, $euiColorInk);
+ min-width: $lnsPanelMinWidth + $euiSizeXL;
+ max-width: $euiFormMaxWidth + $euiSizeXXL;
+ max-height: 100%;
+
+ .lnsConfigPanel {
+ @include euiScrollBar;
+ padding: $euiSize 0 $euiSize $euiSize;
+ overflow-x: hidden;
+ overflow-y: scroll;
+ }
+}
diff --git a/public/components/explorer/visualizations/frame_layout.tsx b/public/components/explorer/visualizations/frame_layout.tsx
new file mode 100644
index 0000000000..86781b213f
--- /dev/null
+++ b/public/components/explorer/visualizations/frame_layout.tsx
@@ -0,0 +1,31 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import './frame_layout.scss';
+
+import React from 'react';
+import { EuiPage, EuiPageSideBar, EuiPageBody } from '@elastic/eui';
+
+export interface FrameLayoutProps {
+ dataPanel: React.ReactNode;
+ configPanel?: React.ReactNode;
+ suggestionsPanel?: React.ReactNode;
+ workspacePanel?: React.ReactNode;
+}
+
+export function FrameLayout(props: FrameLayoutProps) {
+ return (
+
+
+
+ {props.workspacePanel}
+
+
+ {props.configPanel}
+
+
+
+ );
+}
diff --git a/public/components/explorer/visualizations/index.tsx b/public/components/explorer/visualizations/index.tsx
new file mode 100644
index 0000000000..6ae2a57041
--- /dev/null
+++ b/public/components/explorer/visualizations/index.tsx
@@ -0,0 +1,85 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import './app.scss';
+
+import _ from 'lodash';
+
+import React from 'react';
+import { EuiResizableContainer } from '@elastic/eui';
+import { SELECTED_TIMESTAMP } from '../../../../common/constants/explorer';
+import { IField, IQuery, IVisualizationContainerProps } from '../../../../common/types/explorer';
+import { WorkspacePanel } from './workspace_panel';
+import { ConfigPanel } from './config_panel';
+import { Sidebar } from '../sidebar';
+
+interface IExplorerVisualizationsProps {
+ query: IQuery;
+ curVisId: string;
+ setCurVisId: (visId: string) => void;
+ explorerVis: any;
+ explorerFields: IField[];
+ explorerData: any;
+ handleAddField: (field: IField) => void;
+ handleRemoveField: (field: IField) => void;
+ visualizations: IVisualizationContainerProps;
+ handleOverrideTimestamp: (field: IField) => void;
+ callback?: any;
+}
+
+export const ExplorerVisualizations = ({
+ query,
+ curVisId,
+ setCurVisId,
+ explorerVis,
+ explorerFields,
+ explorerData,
+ handleAddField,
+ handleRemoveField,
+ visualizations,
+ handleOverrideTimestamp,
+ callback,
+}: IExplorerVisualizationsProps) => {
+ return (
+
+ {(EuiResizablePanel, EuiResizableButton) => (
+ <>
+
+
+ handleAddField(field)}
+ handleRemoveField={(field: IField) => handleRemoveField(field)}
+ isFieldToggleButtonDisabled={true}
+ />
+
+
+
+
+
+
+
+
+
+
+ >
+ )}
+
+ );
+};
diff --git a/public/components/explorer/visualizations/lens_field_icon.tsx b/public/components/explorer/visualizations/lens_field_icon.tsx
new file mode 100644
index 0000000000..59c947bce4
--- /dev/null
+++ b/public/components/explorer/visualizations/lens_field_icon.tsx
@@ -0,0 +1,20 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { FieldIcon } from '../../common/field_icon';
+export function LensFieldIcon({ type, ...rest }) {
+ return (
+
+ );
+}
+
+export function normalizeOperationDataType(type) {
+ return type === 'document' ? 'number' : type;
+}
diff --git a/public/components/explorer/visualizations/shared_components/__tests__/__snapshots__/shared_components.test.tsx.snap b/public/components/explorer/visualizations/shared_components/__tests__/__snapshots__/shared_components.test.tsx.snap
new file mode 100644
index 0000000000..7fc0731ee6
--- /dev/null
+++ b/public/components/explorer/visualizations/shared_components/__tests__/__snapshots__/shared_components.test.tsx.snap
@@ -0,0 +1,198 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Shared components Renders empty placeholder component 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No results found
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Shared components Renders tool bar button component 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ testing
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/explorer/visualizations/shared_components/__tests__/shared_components.test.tsx b/public/components/explorer/visualizations/shared_components/__tests__/shared_components.test.tsx
new file mode 100644
index 0000000000..89fd64289a
--- /dev/null
+++ b/public/components/explorer/visualizations/shared_components/__tests__/shared_components.test.tsx
@@ -0,0 +1,43 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { EmptyPlaceholder } from '../empty_placeholder';
+import { LensIconChartBar } from '../../../../visualizations/assets/chart_bar';
+import { ToolbarButton } from '../toolbar_button';
+
+describe('Shared components', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders empty placeholder component', async () => {
+ const wrapper = mount( );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+
+ it('Renders tool bar button component', async () => {
+ const handleClick = jest.fn();
+ const WrappedComponent = () => testing
;
+
+ const wrapper = mount(
+
+
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
diff --git a/public/components/explorer/visualizations/shared_components/empty_placeholder.tsx b/public/components/explorer/visualizations/shared_components/empty_placeholder.tsx
new file mode 100644
index 0000000000..30e316aced
--- /dev/null
+++ b/public/components/explorer/visualizations/shared_components/empty_placeholder.tsx
@@ -0,0 +1,23 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { EuiIcon, EuiText, IconType, EuiSpacer } from '@elastic/eui';
+import { FormattedMessage } from '@osd/i18n/react';
+
+export const EmptyPlaceholder = (props: {icon: string}) => (
+ <>
+
+
+
+
+
+
+
+ >
+);
diff --git a/public/components/explorer/visualizations/shared_components/index.ts b/public/components/explorer/visualizations/shared_components/index.ts
new file mode 100644
index 0000000000..dfbd82f359
--- /dev/null
+++ b/public/components/explorer/visualizations/shared_components/index.ts
@@ -0,0 +1,8 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export * from './empty_placeholder';
+export { ToolbarPopoverProps, ToolbarPopover } from './toolbar_popover';
+export { ToolbarButtonProps, ToolbarButton } from './toolbar_button';
diff --git a/public/components/explorer/visualizations/shared_components/plotly_viz_editor/index.tsx b/public/components/explorer/visualizations/shared_components/plotly_viz_editor/index.tsx
new file mode 100644
index 0000000000..1238af2fed
--- /dev/null
+++ b/public/components/explorer/visualizations/shared_components/plotly_viz_editor/index.tsx
@@ -0,0 +1 @@
+export { PlotlyVizEditor } from './plotly_viz_editor';
diff --git a/public/components/explorer/visualizations/shared_components/plotly_viz_editor/plotly_actions.tsx b/public/components/explorer/visualizations/shared_components/plotly_viz_editor/plotly_actions.tsx
new file mode 100644
index 0000000000..e918d7b74d
--- /dev/null
+++ b/public/components/explorer/visualizations/shared_components/plotly_viz_editor/plotly_actions.tsx
@@ -0,0 +1,77 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Modifications Copyright OpenSearch Contributors. See
+ * GitHub history for details.
+ */
+
+import React, { useState, useCallback } from 'react';
+import { EuiButtonIcon, EuiContextMenuPanel, EuiContextMenuItem, EuiPopover } from '@elastic/eui';
+import { FormattedMessage } from '@osd/i18n/react';
+
+interface PlotlyEditorActionsMenuProps {
+ formatHJson(): void;
+}
+
+function PlotlyEditorActionsMenu({ formatHJson }: PlotlyEditorActionsMenuProps) {
+ const [isPopoverOpen, setIsPopoverOpen] = useState(false);
+
+ const onButtonClick = useCallback(() => setIsPopoverOpen((isOpen) => !isOpen), []);
+ const onHJsonCLick = useCallback(() => {
+ formatHJson();
+ setIsPopoverOpen(false);
+ }, [formatHJson]);
+
+ const closePopover = useCallback(() => setIsPopoverOpen(false), []);
+
+ const button = ;
+
+ const items = [
+
+
+ ,
+ ];
+
+ return (
+
+ );
+}
+
+export { PlotlyEditorActionsMenu };
diff --git a/public/components/explorer/visualizations/shared_components/plotly_viz_editor/plotly_editor.scss b/public/components/explorer/visualizations/shared_components/plotly_viz_editor/plotly_editor.scss
new file mode 100644
index 0000000000..709aaa2030
--- /dev/null
+++ b/public/components/explorer/visualizations/shared_components/plotly_viz_editor/plotly_editor.scss
@@ -0,0 +1,22 @@
+.visEditor--vega {
+ .visEditorSidebar__config {
+ padding: 0;
+ }
+}
+
+.vgaEditor {
+ @include euiBreakpoint('xs', 's', 'm') {
+ @include euiScrollBar;
+ max-height: $euiSize * 15;
+ overflow-y: auto;
+ }
+}
+
+.vgaEditor__aceEditorActions {
+ position: absolute;
+ z-index: $euiZLevel1;
+ top: $euiSizeS;
+ // Adjust for sidebar collapse button
+ right: $euiSizeXXL;
+ line-height: 1;
+}
diff --git a/public/components/explorer/visualizations/shared_components/plotly_viz_editor/plotly_vis.scss b/public/components/explorer/visualizations/shared_components/plotly_viz_editor/plotly_vis.scss
new file mode 100644
index 0000000000..12108c7ba3
--- /dev/null
+++ b/public/components/explorer/visualizations/shared_components/plotly_viz_editor/plotly_vis.scss
@@ -0,0 +1,146 @@
+.vgaVis {
+ display: flex;
+ flex: 1 1 100%;
+ position: relative;
+ // flex-direction determined by js
+}
+
+.vgaVis__view {
+ z-index: 0;
+ flex: 1 1 100%;
+
+ display: block;
+ max-width: 100%;
+ max-height: 100%;
+ width: 100%;
+ height: 100%;
+
+ // BUG #23514: Make sure Vega doesn't display the controls in two places
+ .vega-bindings {
+ // sass-lint:disable no-important
+ display: none !important;
+ }
+}
+
+.vgaVis__controls {
+ @include euiFontSizeS;
+ display: flex;
+
+ &:not(:empty) {
+ padding: $euiSizeS 0; // Adding a little bit of padding helps with the unnecessary scrollbars
+ }
+
+ &.vgaVis__controls--column {
+ flex-direction: column;
+ }
+
+ &.vgaVis__controls--row {
+ flex-direction: row;
+
+ > .vega-bind {
+ flex-grow: 1;
+ }
+ }
+
+ > .vega-bind {
+ .vega-bind-name {
+ display: inline-block;
+ width: $euiSizeM * 10 - $euiSize;
+ }
+
+ input[type='range'] {
+ width: $euiSizeM * 10;
+ display: inline-block;
+ vertical-align: middle;
+ }
+
+ label {
+ margin: 0 0 0 $euiSizeS;
+ }
+
+ select {
+ max-width: $euiSize * 10;
+ }
+
+ .vega-bind-radio label {
+ margin: 0 $euiSizeS 0 $euiSizeXS;
+ }
+ }
+}
+
+// Messages
+
+.vgaVis__messages {
+ position: absolute;
+ top: 0;
+ width: 100%;
+ margin: auto;
+ opacity: .8;
+ z-index: 1;
+ list-style: none;
+}
+
+.vgaVis__message {
+ margin: $euiSizeS;
+
+ .vgaVis__messageCode {
+ white-space: pre-wrap;
+ padding: $euiSizeS;
+ }
+}
+
+.vgaVis__message--warn .vgaVis__messageCode {
+ $calculatedBackgroundColor: tintOrShade($euiColorWarning, 90%, 70%);
+ background-color: $calculatedBackgroundColor;
+ color: makeHighContrastColor($euiColorWarning, $calculatedBackgroundColor);
+}
+
+.vgaVis__message--err .vgaVis__messageCode {
+ $calculateBackgroundColor: tintOrShade($euiColorDanger, 90%, 70%);
+ background-color: $calculateBackgroundColor;
+ color: makeHighContrastColor($euiColorDanger, $calculateBackgroundColor);
+}
+
+
+// Style tooltip popup (gets created dynamically at the top level if dashboard has a Vega vis)
+// Adapted from https://github.com/vega/vega-tooltip
+
+.vgaVis__tooltip {
+ max-width: 100%;
+ position: fixed;
+
+ h2 {
+ margin-bottom: $euiSizeS;
+ }
+
+ td {
+ @include euiTextTruncate;
+ padding-top: $euiSizeXS;
+ padding-bottom: $euiSizeXS;
+
+ &.key {
+ color: $euiColorMediumShade;
+ max-width: $euiSize * 10;
+ text-align: right;
+ padding-right: $euiSizeXS;
+ }
+
+ &.value {
+ max-width: $euiSizeL * 10;
+ text-align: left;
+ }
+ }
+
+
+ @media only screen and (max-width: map-get($euiBreakpoints, 'm')) {
+ td {
+ &.key {
+ max-width: $euiSize * 6;
+ }
+
+ &.value {
+ max-width: $euiSize * 10;
+ }
+ }
+ }
+}
diff --git a/public/components/explorer/visualizations/shared_components/plotly_viz_editor/plotly_viz_editor.tsx b/public/components/explorer/visualizations/shared_components/plotly_viz_editor/plotly_viz_editor.tsx
new file mode 100644
index 0000000000..f16c7b69e8
--- /dev/null
+++ b/public/components/explorer/visualizations/shared_components/plotly_viz_editor/plotly_viz_editor.tsx
@@ -0,0 +1,101 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Modifications Copyright OpenSearch Contributors. See
+ * GitHub history for details.
+ */
+
+import './plotly_vis.scss';
+import './plotly_editor.scss';
+
+import React, { useCallback } from 'react';
+import { EuiCodeEditor } from '@elastic/eui';
+import compactStringify from 'json-stringify-pretty-compact';
+import hjson from 'hjson';
+import 'brace/mode/hjson';
+import { PlotlyEditorActionsMenu } from './plotly_actions';
+
+const aceOptions = {
+ maxLines: Infinity,
+ highlightActiveLine: false,
+ showPrintMargin: false,
+ tabSize: 2,
+ useSoftTabs: true,
+ wrap: true,
+};
+
+const hjsonStringifyOptions = {
+ bracesSameLine: true,
+ keepWsc: true,
+};
+
+function PlotlyVizEditor({ spec, onVizConfigChange, setToast, vizState, userConfigs = {} }: any) {
+ const formatHJson = useCallback(
+ () => onVizConfigChange(format(spec, hjson.stringify, hjsonStringifyOptions)),
+ [onVizConfigChange, spec]
+ );
+
+ const format = (
+ value: string,
+ stringify: typeof hjson.stringify | typeof compactStringify,
+ options?: any
+ ) => {
+ try {
+ const formattedSpec = hjson.parse(value, { legacyRoot: false, keepWsc: true });
+ return stringify(formattedSpec, options);
+ } catch (err) {
+ // This is a common case - user tries to format an invalid HJSON text
+ setToast(`Error formatting spec: '${err.message}`, 'danger');
+
+ return value;
+ }
+ };
+
+ return (
+
+
{
+ onVizConfigChange(config);
+ }}
+ value={spec}
+ setOptions={aceOptions}
+ isReadOnly={false}
+ />
+
+
+ );
+}
+
+export { PlotlyVizEditor };
diff --git a/public/components/explorer/visualizations/shared_components/toolbar_button.scss b/public/components/explorer/visualizations/shared_components/toolbar_button.scss
new file mode 100644
index 0000000000..621cb9293d
--- /dev/null
+++ b/public/components/explorer/visualizations/shared_components/toolbar_button.scss
@@ -0,0 +1,65 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+.lnsToolbarButton {
+ line-height: $euiButtonHeight; // Keeps alignment of text and chart icon
+ background-color: $euiColorEmptyShade;
+
+ // Some toolbar buttons are just icons, but EuiButton comes with margin and min-width that need to be removed
+ min-width: 0;
+
+ &[class*='--text'] {
+ // Lighten the border color for all states
+ border-color: $euiBorderColor !important; // sass-lint:disable-line no-important
+ }
+
+ &[class*='isDisabled'] {
+ // There is a popover `pointer-events: none` that messes with the not-allowed cursor
+ pointer-events: initial;
+ }
+
+ .lnsToolbarButton__text > svg {
+ margin-top: -1px; // Just some weird alignment issue when icon is the child not the `iconType`
+ }
+
+ .lnsToolbarButton__text:empty {
+ margin: 0;
+ }
+
+ // Toolbar buttons don't look good with centered text when fullWidth
+ &[class*='fullWidth'] {
+ text-align: left;
+
+ .lnsToolbarButton__content {
+ justify-content: space-between;
+ }
+ }
+
+}
+
+.lnsToolbarButton--groupLeft {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+
+.lnsToolbarButton--groupCenter {
+ border-radius: 0;
+ border-left: none;
+}
+
+.lnsToolbarButton--groupRight {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ border-left: none;
+}
+
+.lnsToolbarButton--bold {
+ font-weight: $euiFontWeightBold;
+}
+
+.lnsToolbarButton--s {
+ box-shadow: none !important; // sass-lint:disable-line no-important
+ font-size: $euiFontSizeS;
+}
diff --git a/public/components/explorer/visualizations/shared_components/toolbar_button.tsx b/public/components/explorer/visualizations/shared_components/toolbar_button.tsx
new file mode 100644
index 0000000000..99d0aca643
--- /dev/null
+++ b/public/components/explorer/visualizations/shared_components/toolbar_button.tsx
@@ -0,0 +1,73 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import './toolbar_button.scss';
+import React from 'react';
+import classNames from 'classnames';
+import { EuiButton, PropsOf, EuiButtonProps } from '@elastic/eui';
+
+const groupPositionToClassMap = {
+ none: null,
+ left: 'lnsToolbarButton--groupLeft',
+ center: 'lnsToolbarButton--groupCenter',
+ right: 'lnsToolbarButton--groupRight',
+};
+
+export type ToolbarButtonProps = PropsOf & {
+ /**
+ * Determines prominence
+ */
+ fontWeight?: 'normal' | 'bold';
+ /**
+ * Smaller buttons also remove extra shadow for less prominence
+ */
+ size?: EuiButtonProps['size'];
+ /**
+ * Determines if the button will have a down arrow or not
+ */
+ hasArrow?: boolean;
+ /**
+ * Adjusts the borders for groupings
+ */
+ groupPosition?: 'none' | 'left' | 'center' | 'right';
+ dataTestSubj?: string;
+};
+
+export const ToolbarButton: React.FunctionComponent = ({
+ children,
+ className,
+ fontWeight = 'normal',
+ size = 's',
+ hasArrow = true,
+ groupPosition = 'none',
+ dataTestSubj = '',
+ ...rest
+}) => {
+ const classes = classNames(
+ 'lnsToolbarButton',
+ groupPositionToClassMap[groupPosition],
+ [`lnsToolbarButton--${fontWeight}`, `lnsToolbarButton--${size}`],
+ className
+ );
+ return (
+
+ {children}
+
+ );
+};
diff --git a/public/components/explorer/visualizations/visualization_specs/default.data.spec.hjson b/public/components/explorer/visualizations/visualization_specs/default.data.spec.hjson
new file mode 100644
index 0000000000..eb3c8a0ced
--- /dev/null
+++ b/public/components/explorer/visualizations/visualization_specs/default.data.spec.hjson
@@ -0,0 +1,4 @@
+{
+ /* data configurations */
+ data: {}
+}
\ No newline at end of file
diff --git a/public/components/explorer/visualizations/visualization_specs/default.layout.spec.hjson b/public/components/explorer/visualizations/visualization_specs/default.layout.spec.hjson
new file mode 100644
index 0000000000..f2bb3702d9
--- /dev/null
+++ b/public/components/explorer/visualizations/visualization_specs/default.layout.spec.hjson
@@ -0,0 +1,11 @@
+{
+ /* layout configurations */
+ layout: {
+ /* configuration options can be found: https://plotly.com/javascript/reference/layout/ */
+ }
+
+ /* figure configurations */
+ config: {
+ /* configuration options can be found: https://plotly.com/javascript/configuration-options/ */
+ }
+}
\ No newline at end of file
diff --git a/public/components/explorer/visualizations/visualization_specs/default_spec.ts b/public/components/explorer/visualizations/visualization_specs/default_spec.ts
new file mode 100644
index 0000000000..310f6613fd
--- /dev/null
+++ b/public/components/explorer/visualizations/visualization_specs/default_spec.ts
@@ -0,0 +1,10 @@
+// @ts-ignore
+
+import hjson from 'hjson';
+import defaultLayoutSpec from '!!raw-loader!./default.layout.spec.hjson';
+import defaultDataSpec from '!!raw-loader!./default.data.spec.hjson';
+
+export const getDefaultSpec = (type = 'layout') => {
+ if (type === 'data') return defaultDataSpec;
+ return defaultLayoutSpec;
+};
diff --git a/public/components/explorer/visualizations/workspace_panel/chart_switch.scss b/public/components/explorer/visualizations/workspace_panel/chart_switch.scss
new file mode 100644
index 0000000000..4c90496cdb
--- /dev/null
+++ b/public/components/explorer/visualizations/workspace_panel/chart_switch.scss
@@ -0,0 +1,27 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+.lnsChartSwitch__header {
+ > * {
+ display: flex;
+ align-items: center;
+ }
+}
+
+.lnsChartSwitch__summaryIcon {
+ margin-right: $euiSizeS;
+ transform: translateY(-1px);
+ color: $euiTextSubduedColor;
+}
+
+// Targeting img as this won't target normal EuiIcon's only the custom svgs's
+img.lnsChartSwitch__chartIcon { // sass-lint:disable-line no-qualifying-elements
+ // The large icons aren't square so max out the width to fill the height
+ width: 100%;
+}
+
+.lnsChartSwitch__search {
+ width: 4 * $euiSizeXXL;
+}
\ No newline at end of file
diff --git a/public/components/explorer/visualizations/workspace_panel/chart_switch.tsx b/public/components/explorer/visualizations/workspace_panel/chart_switch.tsx
new file mode 100644
index 0000000000..4d96e88df1
--- /dev/null
+++ b/public/components/explorer/visualizations/workspace_panel/chart_switch.tsx
@@ -0,0 +1,114 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import './chart_switch.scss';
+
+import React, { useState } from 'react';
+import { i18n } from '@osd/i18n';
+import {
+ EuiPopover,
+ EuiPopoverTitle,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiKeyPadMenu,
+ EuiKeyPadMenuItem,
+ EuiIcon,
+} from '@elastic/eui';
+import { ToolbarButton } from '../shared_components/toolbar_button';
+import { getPlotlyCategory } from '../../../visualizations/charts/shared/shared_configs';
+
+function VisualizationSummary(vis: any) {
+ return (
+ <>
+
+ {vis.label}
+ >
+ );
+}
+
+const VIS_CATEGORY = getPlotlyCategory('list');
+
+export const ChartSwitch = ({ setVis, vis, visualizationTypes }: any) => {
+ const [flyoutOpen, setFlyoutOpen] = useState(false);
+
+ const popoverWrappedSwitch = (
+ setFlyoutOpen(!flyoutOpen)}
+ data-test-subj="lnsChartSwitchPopover"
+ fontWeight="bold"
+ >
+
+
+ }
+ isOpen={flyoutOpen}
+ closePopover={() => setFlyoutOpen(false)}
+ anchorPosition="downLeft"
+ >
+ {VIS_CATEGORY.map((vis_category) => {
+ return (
+ <>
+
+
+
+ {i18n.translate('xpack.lens.configPanel.chartType', {
+ defaultMessage: `${vis_category}`,
+ })}
+
+
+
+
+ {visualizationTypes
+ .filter((v) => vis_category === v.category)
+ .map((v) => (
+ {v.label}}
+ title={v.fullLabel}
+ role="menuitem"
+ data-test-subj={`lnsChartSwitchPopover_${v.id}`}
+ onClick={() => {
+ setVis(v.id);
+ setFlyoutOpen(false);
+ }}
+ betaBadgeLabel={
+ v.selection.dataLoss !== 'nothing'
+ ? i18n.translate('xpack.lens.chartSwitch.dataLossLabel', {
+ defaultMessage: 'Data loss',
+ })
+ : undefined
+ }
+ betaBadgeTooltipContent={
+ v.selection.dataLoss !== 'nothing'
+ ? i18n.translate('xpack.lens.chartSwitch.dataLossDescription', {
+ defaultMessage:
+ 'Switching to this chart will lose some of the configuration',
+ })
+ : undefined
+ }
+ betaBadgeIconType={v.selection.dataLoss !== 'nothing' ? 'alert' : undefined}
+ >
+
+
+ ))}
+
+ >
+ );
+ })}
+
+ );
+
+ return {popoverWrappedSwitch}
;
+};
diff --git a/public/components/explorer/visualizations/workspace_panel/index.ts b/public/components/explorer/visualizations/workspace_panel/index.ts
new file mode 100644
index 0000000000..f8ed02d091
--- /dev/null
+++ b/public/components/explorer/visualizations/workspace_panel/index.ts
@@ -0,0 +1,6 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { WorkspacePanel } from './workspace_panel';
diff --git a/public/components/explorer/visualizations/workspace_panel/workspace_panel.scss b/public/components/explorer/visualizations/workspace_panel/workspace_panel.scss
new file mode 100644
index 0000000000..36f5d15c25
--- /dev/null
+++ b/public/components/explorer/visualizations/workspace_panel/workspace_panel.scss
@@ -0,0 +1,9 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+
+.ws__header-dark {
+ background-color: transparent;
+}
\ No newline at end of file
diff --git a/public/components/explorer/visualizations/workspace_panel/workspace_panel.tsx b/public/components/explorer/visualizations/workspace_panel/workspace_panel.tsx
new file mode 100644
index 0000000000..9934e4f271
--- /dev/null
+++ b/public/components/explorer/visualizations/workspace_panel/workspace_panel.tsx
@@ -0,0 +1,73 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import './workspace_panel.scss';
+
+import React, { useState, useMemo } from 'react';
+import { isEmpty } from 'lodash';
+import { EuiPanel, EuiFlexGroup, EuiFlexItem, EuiSwitch, EuiSpacer } from '@elastic/eui';
+import { Visualization } from '../../../visualizations/visualization';
+import { DataTable } from '../../../visualizations/charts/data_table/data_table';
+import { uiSettingsService } from '../../../../../common/utils';
+
+interface IWorkSpacePanel {
+ curVisId: string;
+ setCurVisId: any;
+ visualizations: any;
+}
+
+export function WorkspacePanel({ visualizations }: IWorkSpacePanel) {
+ const [isTableViewOn, setIsTableViewOn] = useState(false);
+ const VisualizationPanel = useMemo(() => {
+ return ;
+ }, [visualizations]);
+
+ return (
+ <>
+
+
+
+
+
+
+ {
+ setIsTableViewOn((staleState) => !staleState);
+ }}
+ aria-describedby="table view switcher"
+ compressed
+ />
+
+
+
+
+
+
+
+ {isTableViewOn ? : VisualizationPanel}
+
+
+
+ >
+ );
+}
diff --git a/public/components/index.tsx b/public/components/index.tsx
new file mode 100644
index 0000000000..267cb6b5d6
--- /dev/null
+++ b/public/components/index.tsx
@@ -0,0 +1,34 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import ReactDOM from 'react-dom';
+import { AppMountParameters, CoreStart } from '../../../../src/core/public';
+import { AppPluginStartDependencies } from '../types';
+import { App } from './app';
+
+export const Observability = (
+ CoreStartProp: CoreStart,
+ DepsStart: AppPluginStartDependencies,
+ AppMountParametersProp: AppMountParameters,
+ pplService: any,
+ dslService: any,
+ savedObjects: any,
+ timestampUtils: any
+) => {
+ ReactDOM.render(
+ ,
+ AppMountParametersProp.element
+ );
+
+ return () => ReactDOM.unmountComponentAtNode(AppMountParametersProp.element);
+};
diff --git a/public/components/notebooks/components/__tests__/__snapshots__/note_table.test.tsx.snap b/public/components/notebooks/components/__tests__/__snapshots__/note_table.test.tsx.snap
new file mode 100644
index 0000000000..10647b7868
--- /dev/null
+++ b/public/components/notebooks/components/__tests__/__snapshots__/note_table.test.tsx.snap
@@ -0,0 +1,1139 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` spec renders the component 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Invalid date
+
+
+
+
+
+ Invalid date
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Invalid date
+
+
+
+
+
+ Invalid date
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Invalid date
+
+
+
+
+
+ Invalid date
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Invalid date
+
+
+
+
+
+ Invalid date
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Invalid date
+
+
+
+
+
+ Invalid date
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Rows per page
+ :
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[` spec renders the empty component 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+ No notebooks
+
+
+
+
+ Use notebooks to create post-mortem reports, build live infrastructure
+
+ reports, or foster explorative collaborations with data.
+
+
+
+
+
+
+
+
+
+
+ Create notebook
+
+
+
+
+
+
+
+
+ Add samples
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap b/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap
new file mode 100644
index 0000000000..d184baf151
--- /dev/null
+++ b/public/components/notebooks/components/__tests__/__snapshots__/notebook.test.tsx.snap
@@ -0,0 +1,611 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` spec renders the component 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Paragraph actions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Notebook actions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Created
+
+
+ Invalid date
+
+
+
+
+
+
+
+
+
+
+
+ No paragraphs
+
+
+ Add a paragraph to compose your document or story. Notebooks now support two types of input:
+
+
+
+
+
+
+
+
+
+
+
+ Code block
+
+
+
+ Write contents directly using markdown, SQL or PPL.
+
+
+
+
+
+
+
+
+
+
+
+ Visualization
+
+
+
+ Import OpenSearch Dashboards or Observability visualizations to the notes.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[` spec renders the component 2`] = `null`;
+
+exports[` spec renders the empty component 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Paragraph actions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Notebook actions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Created
+
+
+ Invalid date
+
+
+
+
+
+
+
+
+
+
+
+ No paragraphs
+
+
+ Add a paragraph to compose your document or story. Notebooks now support two types of input:
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Code block
+
+
+
+ Write contents directly using markdown, SQL or PPL.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Visualization
+
+
+
+ Import OpenSearch Dashboards or Observability visualizations to the notes.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/notebooks/components/__tests__/note_table.test.tsx b/public/components/notebooks/components/__tests__/note_table.test.tsx
new file mode 100644
index 0000000000..70eb5fe30a
--- /dev/null
+++ b/public/components/notebooks/components/__tests__/note_table.test.tsx
@@ -0,0 +1,84 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { fireEvent, render } from '@testing-library/react';
+import { configure, mount, shallow } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { NoteTable } from '../note_table';
+
+describe(' spec', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders the empty component', () => {
+ const fetchNotebooks = jest.fn();
+ const addSampleNotebooks = jest.fn();
+ const createNotebook = jest.fn();
+ const renameNotebook = jest.fn();
+ const cloneNotebook = jest.fn();
+ const deleteNotebook = jest.fn();
+ const setBreadcrumbs = jest.fn();
+ const setToast = jest.fn();
+ const utils = render(
+
+ );
+ expect(utils.container.firstChild).toMatchSnapshot();
+ });
+
+ it('renders the component', () => {
+ const fetchNotebooks = jest.fn();
+ const addSampleNotebooks = jest.fn();
+ const createNotebook = jest.fn();
+ const renameNotebook = jest.fn();
+ const cloneNotebook = jest.fn();
+ const deleteNotebook = jest.fn();
+ const setBreadcrumbs = jest.fn();
+ const setToast = jest.fn();
+ const notebooks = Array.from({ length: 5 }, (v, k) => ({
+ path: `path-${k}`,
+ id: `id-${k}`,
+ dateCreated: 'date-created',
+ dateModified: 'date-modified',
+ }));
+ const utils = render(
+
+ );
+ expect(utils.container.firstChild).toMatchSnapshot();
+
+ utils.getByText('Actions').click();
+ utils.getByText('Add samples').click();
+ utils.getAllByLabelText('Select this row')[0].click();
+ utils.getByText('Actions').click();
+ utils.getByText('Delete').click();
+ utils.getByText('Cancel').click();
+ utils.getAllByLabelText('Select this row')[0].click();
+ utils.getByText('Actions').click();
+ utils.getByText('Rename').click();
+ });
+});
diff --git a/public/components/notebooks/components/__tests__/notebook.test.tsx b/public/components/notebooks/components/__tests__/notebook.test.tsx
new file mode 100644
index 0000000000..eaabb3654a
--- /dev/null
+++ b/public/components/notebooks/components/__tests__/notebook.test.tsx
@@ -0,0 +1,120 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { fireEvent, render, waitFor } from '@testing-library/react';
+import { configure, mount, shallow } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import PPLService from '../../../../services/requests/ppl';
+import React from 'react';
+import { HttpResponse } from '../../../../../../../src/core/public';
+import httpClientMock from '../../../../../test/__mocks__/httpClientMock';
+import { sampleNotebook1 } from '../helpers/__tests__/sampleDefaultNotebooks';
+import { Notebook } from '../notebook';
+
+jest.mock('../../../../../../../src/plugins/embeddable/public', () => ({
+ ViewMode: {
+ EDIT: 'edit',
+ VIEW: 'view',
+ },
+}));
+
+// @ts-ignore
+global.fetch = jest.fn(() =>
+ Promise.resolve({
+ json: () =>
+ Promise.resolve({
+ status: {
+ statuses: [{ id: 'plugin:reportsDashboards' }],
+ },
+ }),
+ })
+);
+
+describe(' spec', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders the empty component', async () => {
+ const pplService = new PPLService(httpClientMock);
+ const setBreadcrumbs = jest.fn();
+ const renameNotebook = jest.fn();
+ const cloneNotebook = jest.fn();
+ const deleteNotebook = jest.fn();
+ const setToast = jest.fn();
+ const location = jest.fn();
+ const history = jest.fn() as any;
+ history.replace = jest.fn();
+ const utils = render(
+
+ );
+ expect(utils.container.firstChild).toMatchSnapshot();
+ utils.getByText('Add code block').click();
+ utils.getByText('Add visualization').click();
+ });
+
+ it('renders the component', async () => {
+ const pplService = new PPLService(httpClientMock);
+ const setBreadcrumbs = jest.fn();
+ const renameNotebook = jest.fn();
+ const cloneNotebook = jest.fn();
+ const deleteNotebook = jest.fn();
+ const setToast = jest.fn();
+ const location = jest.fn();
+ const history = jest.fn() as any;
+ history.replace = jest.fn();
+ httpClientMock.get = jest.fn(() =>
+ Promise.resolve(({
+ ...sampleNotebook1,
+ path: sampleNotebook1.name,
+ visualizations: [
+ {
+ id: 'oiuccXwBYVazWqOO1e06',
+ name: 'Flight Count by Origin',
+ query:
+ 'source=opensearch_dashboards_sample_data_flights | fields Carrier,FlightDelayMin | stats sum(FlightDelayMin) as delays by Carrier',
+ type: 'bar',
+ timeField: 'timestamp',
+ },
+ ],
+ savedVisualizations: Array.from({ length: 5 }, (v, k) => ({
+ label: `vis-${k}`,
+ key: `vis-${k}`,
+ })),
+ } as unknown) as HttpResponse)
+ );
+ const utils = render(
+
+ );
+
+ await waitFor(() => {
+ expect(utils.container.firstChild).toMatchSnapshot();
+ });
+ });
+});
diff --git a/public/components/notebooks/components/helpers/__tests__/__snapshots__/modal_containers.test.tsx.snap b/public/components/notebooks/components/helpers/__tests__/__snapshots__/modal_containers.test.tsx.snap
new file mode 100644
index 0000000000..5ed44ca009
--- /dev/null
+++ b/public/components/notebooks/components/helpers/__tests__/__snapshots__/modal_containers.test.tsx.snap
@@ -0,0 +1,118 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`modal_containers spec render delete notebooks modal 1`] = `
+
+
+
+
+ title
+
+
+
+
+ message
+
+
+ The action cannot be undone.
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+ Delete
+
+
+
+
+`;
+
+exports[`modal_containers spec render get clone modal 1`] = `""`;
+
+exports[`modal_containers spec render get custom modal 1`] = `
+
+
+
+
+ title
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+ Confirm
+
+
+
+
+`;
+
+exports[`modal_containers spec render get delete modal 1`] = `""`;
+
+exports[`modal_containers spec render get delete modal 2`] = `""`;
+
+exports[`modal_containers spec render get sample notebooks modal 1`] = `""`;
diff --git a/public/components/notebooks/components/helpers/__tests__/default_parser.test.tsx b/public/components/notebooks/components/helpers/__tests__/default_parser.test.tsx
new file mode 100644
index 0000000000..3c03a3d5b9
--- /dev/null
+++ b/public/components/notebooks/components/helpers/__tests__/default_parser.test.tsx
@@ -0,0 +1,97 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { defaultParagraphParser } from '../default_parser';
+import {
+ sampleNotebook1,
+ sampleNotebook2,
+ sampleNotebook3,
+ sampleNotebook4,
+ sampleNotebook5,
+ sampleParsedParagraghs1,
+ sampleParsedParagraghs2,
+} from './sampleDefaultNotebooks';
+
+// Perfect schema
+describe('Testing default backend parser function with perfect schema', () => {
+ test('defaultParagraphParserTest1', (done) => {
+ const parsedParagraphs1 = defaultParagraphParser(sampleNotebook1.paragraphs);
+ const parsedParagraphs2 = defaultParagraphParser(sampleNotebook2.paragraphs);
+ const parsedParagraphs3 = defaultParagraphParser([]);
+ expect(parsedParagraphs1).toEqual(sampleParsedParagraghs1);
+ expect(parsedParagraphs2).toEqual(sampleParsedParagraghs2);
+ expect(parsedParagraphs3).toEqual([]);
+ done();
+ });
+
+ it('returns parsed paragraphs', () => {
+ const MockVis = sampleNotebook1.paragraphs[2].input.inputText;
+
+ const parsedPara = defaultParagraphParser(
+ Array.from({ length: 5 }, (v, k) => {
+ const isVisualization = k % 2 === 0;
+ return {
+ id: `paragraph-${k}`,
+ input: {
+ inputText: isVisualization ? MockVis : `text-${k}`,
+ inputType: isVisualization ? 'VISUALIZATION' : 'MARKDOWN',
+ },
+ output: [
+ {
+ result: isVisualization ? '' : `text-${k}`,
+ outputType: isVisualization ? 'VISUALIZATION' : 'MARKDOWN',
+ execution_time: '0s',
+ },
+ ],
+ };
+ })
+ );
+
+ const expected = Array.from({ length: 5 }, (v, k) => {
+ const isVisualization = k % 2 === 0;
+ return {
+ uniqueId: `paragraph-${k}`,
+ isRunning: false,
+ inQueue: false,
+ isSelected: false,
+ isInputHidden: false,
+ isOutputHidden: false,
+ showAddPara: false,
+ isVizualisation: isVisualization,
+ vizObjectInput: isVisualization ? MockVis : '',
+ id: k + 1,
+ inp: isVisualization ? MockVis : `text-${k}`,
+ lang: isVisualization ? 'text/x-' : 'text/x-md',
+ editorLanguage: isVisualization ? '' : 'md',
+ typeOut: isVisualization ? ['VISUALIZATION'] : ['MARKDOWN'],
+ out: isVisualization ? [''] : [`text-${k}`],
+ isInputExpanded: false,
+ isOutputStale: false,
+ paraRef: undefined,
+ paraDivRef: undefined,
+ visStartTime: isVisualization ? '2020-07-21T18:37:44.710Z' : undefined,
+ visEndTime: isVisualization ? '2020-08-20T18:37:44.710Z' : undefined,
+ visSavedObjId: isVisualization ? '935afa20-e0cd-11e7-9d07-1398ccfcefa3' : undefined,
+ };
+ });
+ expect(parsedPara).toEqual(expected);
+ });
+});
+
+// Issue in schema
+describe('Testing default backend parser function with wrong schema', () => {
+ test('defaultParagraphParserTest2', (done) => {
+ expect(() => {
+ const parsedParagraphs1 = defaultParagraphParser(sampleNotebook3.paragraphs);
+ }).toThrow(Error);
+ expect(() => {
+ const parsedParagraphs2 = defaultParagraphParser(sampleNotebook4.paragraphs);
+ }).toThrow(Error);
+ expect(() => {
+ const parsedParagraphs3 = defaultParagraphParser(sampleNotebook5.paragraphs);
+ }).toThrow(Error);
+ done();
+ });
+});
diff --git a/public/components/notebooks/components/helpers/__tests__/legacy_route_helpers.test.ts b/public/components/notebooks/components/helpers/__tests__/legacy_route_helpers.test.ts
new file mode 100644
index 0000000000..c4d1a78554
--- /dev/null
+++ b/public/components/notebooks/components/helpers/__tests__/legacy_route_helpers.test.ts
@@ -0,0 +1,35 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { RedirectProps } from 'react-router-dom';
+import { convertLegacyNotebooksUrl } from '../legacy_route_helpers';
+
+describe('Test legacy route helpers', () => {
+ it('converts legacy notebooks url', () => {
+ const locations = [
+ {
+ pathname: '/app/notebooks-dashboards',
+ search: '',
+ hash: '#/GQ5icXwBJCegTOBKO4Um',
+ },
+ {
+ pathname: '/app/notebooks-dashboards',
+ search: '?view=view_both',
+ hash: '#/clPiPXwBEM7l9gC0xTpA',
+ },
+ {
+ pathname: '/testBasePath/app/notebooks-dashboards',
+ search: '?view=output_only&security_tenant=global',
+ hash: `#/GQ5icXwBJCegTOBKO4Um?_g=(time:(from:'2021-10-15T20:25:09.556Z',to:'2021-10-15T20:55:09.556Z'))`,
+ },
+ ] as Location[];
+ const expected = [
+ '/app/observability-dashboards#/notebooks/GQ5icXwBJCegTOBKO4Um',
+ '/app/observability-dashboards#/notebooks/clPiPXwBEM7l9gC0xTpA?view=view_both',
+ `/testBasePath/app/observability-dashboards#/notebooks/GQ5icXwBJCegTOBKO4Um?_g=(time:(from:'2021-10-15T20:25:09.556Z',to:'2021-10-15T20:55:09.556Z'))&view=output_only&security_tenant=global`,
+ ] as RedirectProps['to'][];
+ expect(locations.map((location) => convertLegacyNotebooksUrl(location))).toEqual(expected);
+ });
+});
diff --git a/public/components/notebooks/components/helpers/__tests__/modal_containers.test.tsx b/public/components/notebooks/components/helpers/__tests__/modal_containers.test.tsx
new file mode 100644
index 0000000000..c0c982a9bd
--- /dev/null
+++ b/public/components/notebooks/components/helpers/__tests__/modal_containers.test.tsx
@@ -0,0 +1,98 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { fireEvent, render } from '@testing-library/react';
+import { configure, mount, shallow } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import {
+ DeleteNotebookModal,
+ getCloneModal,
+ getCustomModal,
+ getDeleteModal,
+ getSampleNotebooksModal,
+} from '../modal_containers';
+
+describe('modal_containers spec', () => {
+ configure({ adapter: new Adapter() });
+
+ it('render get custom modal', () => {
+ const runModal = jest.fn();
+ const closeModal = jest.fn();
+ const wrapper = shallow(
+ getCustomModal(
+ runModal,
+ closeModal,
+ 'label',
+ 'title',
+ 'Cancel',
+ 'Confirm',
+ 'mock-path',
+ 'help text'
+ )
+ );
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it('render get clone modal', () => {
+ const onCancel = jest.fn();
+ const onConfirm = jest.fn();
+ const wrapper = shallow(getCloneModal(onCancel, onConfirm));
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it('render get sample notebooks modal', () => {
+ const onCancel = jest.fn();
+ const onConfirm = jest.fn();
+ const wrapper = shallow(getSampleNotebooksModal(onCancel, onConfirm));
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it('render get delete modal', () => {
+ const onCancel = jest.fn();
+ const onConfirm = jest.fn();
+ const wrapper = shallow(
+ getDeleteModal(onCancel, onConfirm, 'Delete', 'Delete message', 'Confirm message')
+ );
+ expect(wrapper).toMatchSnapshot();
+
+ const noConfirmMessageWrapper = shallow(
+ getDeleteModal(onCancel, onConfirm, 'Delete', 'Delete message')
+ );
+ expect(noConfirmMessageWrapper).toMatchSnapshot();
+ });
+
+ it('render delete notebooks modal', () => {
+ const onCancel = jest.fn();
+ const onConfirm = jest.fn();
+ const wrapper = shallow(
+
+ );
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it('checks delete notebooks modal', () => {
+ const onCancel = jest.fn();
+ const onConfirm = jest.fn();
+ const utils = render(
+
+ );
+ fireEvent.change(utils.getAllByTestId('delete-notebook-modal-input')[0], {
+ target: { value: 'delete' },
+ });
+ fireEvent.click(utils.getAllByTestId('delete-notebook-modal-delete-button')[0]);
+ expect(onConfirm).toBeCalled();
+ });
+});
diff --git a/public/components/notebooks/components/helpers/__tests__/reporting_context_menu_helper.test.tsx b/public/components/notebooks/components/helpers/__tests__/reporting_context_menu_helper.test.tsx
new file mode 100644
index 0000000000..90b951df20
--- /dev/null
+++ b/public/components/notebooks/components/helpers/__tests__/reporting_context_menu_helper.test.tsx
@@ -0,0 +1,139 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ contextMenuCreateReportDefinition,
+ contextMenuViewReports,
+ generateInContextReport
+} from '../reporting_context_menu_helper';
+
+describe('reporting_context_menu_helper tests', () => {
+ test('contextMenuViewReports will redirect', () => {
+ const savedLocation = window.location;
+ // @ts-ignore
+ delete window.location;
+
+ window.location = {
+ ...savedLocation,
+ assign: jest.fn(),
+ };
+ contextMenuViewReports();
+ expect(window.location.assign).toBeCalledWith('reports-dashboards#/');
+ window.location = savedLocation;
+ });
+
+ test('contextMenuCreateReportDefinition', () => {
+ const savedLocation = window.location;
+ // @ts-ignore
+ delete window.location;
+
+ window.location = {
+ ...savedLocation,
+ assign: jest.fn(),
+ };
+ contextMenuCreateReportDefinition('https://mock-base.uri/mock-base-path');
+ expect(window.location.assign).toBeCalledWith(
+ 'reports-dashboards#/create?previous=notebook:mock-base-path?timeFrom=0?timeTo=0'
+ );
+ window.location = savedLocation;
+ });
+
+ function generateReport(
+ status: number,
+ filename: string,
+ tenant: string,
+ setToast: (...args: any[]) => void,
+ toggleReportingLoadingModal: (toggle: boolean) => void
+ ) {
+ const fileFormat = filename.match(/\.([^.]+)$/)?.[1] || 'pdf';
+ // @ts-ignore
+ global.fetch = jest.fn(() =>
+ Promise.resolve({
+ status,
+ json: () => Promise.resolve({ filename, fileFormat, data: 'test-data' }),
+ text: () => Promise.resolve({ tenant }),
+ })
+ );
+ const props = { setToast };
+ return generateInContextReport(fileFormat, props, toggleReportingLoadingModal);
+ }
+
+ it('generates csv for private tenant', async () => {
+ const setToast = jest.fn();
+ const toggleReportingLoadingModal = jest.fn();
+ await generateReport(200, 'test.csv', '__user__', setToast, toggleReportingLoadingModal);
+ expect(toggleReportingLoadingModal).toBeCalledWith(true);
+ expect(setToast).toBeCalledWith('Successfully generated report.', 'success');
+ });
+
+ it('generates pdf for global tenant', async () => {
+ const setToast = jest.fn();
+ const toggleReportingLoadingModal = jest.fn();
+ await generateReport(200, 'test.pdf', '', setToast, toggleReportingLoadingModal);
+ expect(toggleReportingLoadingModal).toBeCalledWith(true);
+ expect(setToast).toBeCalledWith('Successfully generated report.', 'success');
+ });
+
+ it('generates png for custom tenant', async () => {
+ const setToast = jest.fn();
+ const toggleReportingLoadingModal = jest.fn();
+ await generateReport(200, 'test.png', 'custom_tenant', setToast, toggleReportingLoadingModal);
+ expect(toggleReportingLoadingModal).toBeCalledWith(true);
+ expect(setToast).toBeCalledWith('Successfully generated report.', 'success');
+ });
+
+ it('generates png for custom tenant', async () => {
+ const setToast = jest.fn();
+ const toggleReportingLoadingModal = jest.fn();
+ await generateReport(200, 'test.png', 'custom_tenant', setToast, toggleReportingLoadingModal);
+ expect(toggleReportingLoadingModal).toBeCalledWith(true);
+ expect(setToast).toBeCalledWith('Successfully generated report.', 'success');
+ });
+
+ it('handles 404 error', async () => {
+ const setToast = jest.fn();
+ const toggleReportingLoadingModal = jest.fn();
+ await generateReport(404, 'test.png', 'custom_tenant', setToast, toggleReportingLoadingModal);
+ expect(toggleReportingLoadingModal).toBeCalledWith(true);
+ expect(setToast).toBeCalledWith(
+ 'Download error',
+ 'danger',
+ 'There was an error generating this report.'
+ );
+ });
+
+ it('handles permission error', async () => {
+ const setToast = jest.fn();
+ const toggleReportingLoadingModal = jest.fn();
+ await generateReport(403, 'test.png', 'custom_tenant', setToast, toggleReportingLoadingModal);
+ expect(toggleReportingLoadingModal).toBeCalledWith(true);
+ expect(setToast).toBeCalledWith(
+ 'Error generating report,',
+ 'danger',
+ 'Insufficient permissions. Reach out to your OpenSearch Dashboards administrator.'
+ );
+ });
+
+ it('handles timeout error', async () => {
+ const setToast = jest.fn();
+ const toggleReportingLoadingModal = jest.fn();
+ await generateReport(503, 'test.png', 'custom_tenant', setToast, toggleReportingLoadingModal);
+ expect(toggleReportingLoadingModal).toBeCalledWith(true);
+ expect(setToast).toBeCalledWith(
+ 'Error generating report.',
+ 'danger',
+ 'Timed out generating on-demand report from notebook. Try again later.'
+ );
+ });
+
+ it('handles tenant errors', async () => {
+ global.fetch = jest.fn(() => Promise.reject({ status: 500 }));
+ const setToast = jest.fn();
+ const toggleReportingLoadingModal = jest.fn();
+ await generateInContextReport('csv', { setToast }, toggleReportingLoadingModal);
+ expect(toggleReportingLoadingModal).toBeCalledWith(true);
+ expect(setToast).toBeCalledWith('Tenant error', 'danger', 'Failed to get user tenant.');
+ });
+});
diff --git a/public/components/notebooks/components/helpers/__tests__/sampleDefaultNotebooks.tsx b/public/components/notebooks/components/helpers/__tests__/sampleDefaultNotebooks.tsx
new file mode 100644
index 0000000000..17e077ed52
--- /dev/null
+++ b/public/components/notebooks/components/helpers/__tests__/sampleDefaultNotebooks.tsx
@@ -0,0 +1,354 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+// Sample notebook with all input and output
+export const sampleNotebook1 = {
+ id: 'note_5f4b9eed-5898-4b39-ba6c-755c0fadd84e',
+ dateCreated: '2020-08-20T18:00:59.845Z',
+ name: 'test 1',
+ dateModified: '2020-08-20T18:37:56.844Z',
+ pluginVersion: '7.9.0',
+ backend: 'Default',
+ paragraphs: [
+ {
+ output: [{ result: '# Type your input here', outputType: 'MARKDOWN', execution_time: '0s' }],
+ input: { inputText: '# Type your input here', inputType: 'MARKDOWN' },
+ dateCreated: '2020-08-20T18:00:59.845Z',
+ dateModified: '2020-08-20T18:00:59.845Z',
+ id: 'paragraph_1a710988-ec19-4caa-83cc-38eb609427d1',
+ },
+ {
+ output: [{ result: '# add code here\n', outputType: 'MARKDOWN', execution_time: '0s' }],
+ input: { inputText: '# add code here\n', inputType: 'MARKDOWN' },
+ dateCreated: '2020-08-20T18:01:07.662Z',
+ dateModified: '2020-08-20T18:01:18.295Z',
+ id: 'paragraph_c3107b15-da7d-4836-aef4-0996abbc8ab2',
+ },
+ {
+ output: [{ result: '', outputType: 'VISUALIZATION', execution_time: '0s' }],
+ input: {
+ inputText:
+ '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}',
+ inputType: 'VISUALIZATION',
+ },
+ dateCreated: '2020-08-20T18:37:44.809Z',
+ dateModified: '2020-08-20T18:37:56.844Z',
+ id: 'paragraph_6d3237a9-6486-4f93-aa25-0a1c838faabd',
+ },
+ {
+ output: [
+ {
+ result:
+ '{"schema":[{"name":"FlightNum","type":"keyword"},{"name":"Origin","type":"keyword"},{"name":"OriginLocation","type":"geo_point"},{"name":"DestLocation","type":"geo_point"},{"name":"FlightDelay","type":"boolean"},{"name":"DistanceMiles","type":"float"},{"name":"FlightTimeMin","type":"float"},{"name":"OriginWeather","type":"keyword"},{"name":"dayOfWeek","type":"integer"},{"name":"AvgTicketPrice","type":"float"},{"name":"Carrier","type":"keyword"},{"name":"FlightDelayMin","type":"integer"},{"name":"OriginRegion","type":"keyword"},{"name":"DestAirportID","type":"keyword"},{"name":"FlightDelayType","type":"keyword"},{"name":"timestamp","type":"timestamp"},{"name":"Dest","type":"keyword"},{"name":"FlightTimeHour","type":"keyword"},{"name":"Cancelled","type":"boolean"},{"name":"DistanceKilometers","type":"float"},{"name":"OriginCityName","type":"keyword"},{"name":"DestWeather","type":"keyword"},{"name":"OriginCountry","type":"keyword"},{"name":"DestCountry","type":"keyword"},{"name":"DestRegion","type":"keyword"},{"name":"DestCityName","type":"keyword"},{"name":"OriginAirportID","type":"keyword"}],"datarows":[["9HY9SWR","Frankfurt am Main Airport",{"lat":50.033333,"lon":8.570556},{"lat":-33.94609833,"lon":151.177002},false,10247.856,1030.7704,"Sunny",0,841.2656,"OpenSearch Dashboards Airlines",0,"DE-HE","SYD","No Delay","2021-11-01 00:00:00","Sydney Kingsford Smith International Airport","17.179506930998397",false,16492.326,"Frankfurt am Main","Rain","DE","AU","SE-BD","Sydney","FRA"],["X98CCZO","Cape Town International Airport",{"lat":-33.96480179,"lon":18.60169983},{"lat":45.505299,"lon":12.3519},false,5482.6064,464.3895,"Clear",0,882.98267,"Logstash Airways",0,"SE-BD","VE05","No Delay","2021-11-01 18:27:00","Venice Marco Polo Airport","7.73982468459836",false,8823.4,"Cape Town","Sunny","ZA","IT","IT-34","Venice","CPT"]],"total":2,"size":2,"status":200}',
+ outputType: 'QUERY',
+ execution_time: '0s',
+ },
+ ],
+ input: {
+ inputText: '%sql select * from opensearch_dashboards_sample_data_flights limit 2',
+ inputType: 'QUERY',
+ },
+ dateCreated: '2020-08-20T18:37:44.809Z',
+ dateModified: '2020-08-20T18:37:56.844Z',
+ id: 'paragraph_f1b2db55-8704-4822-a8ff-6445fe1fa10c',
+ },
+ ],
+};
+
+// Parsed Output of sample notebook1
+export const sampleParsedParagraghs1 = [
+ {
+ uniqueId: 'paragraph_1a710988-ec19-4caa-83cc-38eb609427d1',
+ isRunning: false,
+ inQueue: false,
+ isSelected: false,
+ isInputHidden: false,
+ isOutputHidden: false,
+ showAddPara: false,
+ isVizualisation: false,
+ vizObjectInput: '',
+ id: 1,
+ inp: '# Type your input here',
+ isInputExpanded: false,
+ isOutputStale: false,
+ paraDivRef: undefined,
+ paraRef: undefined,
+ visEndTime: undefined,
+ visSavedObjId: undefined,
+ visStartTime: undefined,
+ lang: 'text/x-md',
+ editorLanguage: 'md',
+ typeOut: ['MARKDOWN'],
+ out: ['# Type your input here'],
+ },
+ {
+ uniqueId: 'paragraph_c3107b15-da7d-4836-aef4-0996abbc8ab2',
+ isRunning: false,
+ inQueue: false,
+ isSelected: false,
+ isInputHidden: false,
+ isOutputHidden: false,
+ showAddPara: false,
+ isVizualisation: false,
+ vizObjectInput: '',
+ id: 2,
+ inp: '# add code here\n',
+ isInputExpanded: false,
+ isOutputStale: false,
+ paraDivRef: undefined,
+ paraRef: undefined,
+ visEndTime: undefined,
+ visSavedObjId: undefined,
+ visStartTime: undefined,
+ lang: 'text/x-md',
+ editorLanguage: 'md',
+ typeOut: ['MARKDOWN'],
+ out: ['# add code here\n'],
+ },
+ {
+ uniqueId: 'paragraph_6d3237a9-6486-4f93-aa25-0a1c838faabd',
+ isRunning: false,
+ inQueue: false,
+ isSelected: false,
+ isInputHidden: false,
+ isOutputHidden: false,
+ showAddPara: false,
+ isVizualisation: true,
+ vizObjectInput:
+ '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}',
+ id: 3,
+ inp: '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}',
+ lang: 'text/x-',
+ isInputExpanded: false,
+ isOutputStale: false,
+ paraDivRef: undefined,
+ paraRef: undefined,
+ visEndTime: '2020-08-20T18:37:44.710Z',
+ visSavedObjId: '935afa20-e0cd-11e7-9d07-1398ccfcefa3',
+ visStartTime: '2020-07-21T18:37:44.710Z',
+ editorLanguage: '',
+ typeOut: ['VISUALIZATION'],
+ out: [''],
+ },
+ {
+ uniqueId: 'paragraph_f1b2db55-8704-4822-a8ff-6445fe1fa10c',
+ isRunning: false,
+ inQueue: false,
+ isSelected: false,
+ isInputHidden: false,
+ isOutputHidden: false,
+ showAddPara: false,
+ isVizualisation: false,
+ vizObjectInput: '',
+ id: 4,
+ inp: `%sql select * from opensearch_dashboards_sample_data_flights limit 2`,
+ isInputExpanded: false,
+ isOutputStale: false,
+ paraDivRef: undefined,
+ paraRef: undefined,
+ visEndTime: undefined,
+ visSavedObjId: undefined,
+ visStartTime: undefined,
+ lang: 'text/x-',
+ editorLanguage: '',
+ typeOut: ['QUERY'],
+ out: [
+ '{"schema":[{"name":"FlightNum","type":"keyword"},{"name":"Origin","type":"keyword"},{"name":"OriginLocation","type":"geo_point"},{"name":"DestLocation","type":"geo_point"},{"name":"FlightDelay","type":"boolean"},{"name":"DistanceMiles","type":"float"},{"name":"FlightTimeMin","type":"float"},{"name":"OriginWeather","type":"keyword"},{"name":"dayOfWeek","type":"integer"},{"name":"AvgTicketPrice","type":"float"},{"name":"Carrier","type":"keyword"},{"name":"FlightDelayMin","type":"integer"},{"name":"OriginRegion","type":"keyword"},{"name":"DestAirportID","type":"keyword"},{"name":"FlightDelayType","type":"keyword"},{"name":"timestamp","type":"timestamp"},{"name":"Dest","type":"keyword"},{"name":"FlightTimeHour","type":"keyword"},{"name":"Cancelled","type":"boolean"},{"name":"DistanceKilometers","type":"float"},{"name":"OriginCityName","type":"keyword"},{"name":"DestWeather","type":"keyword"},{"name":"OriginCountry","type":"keyword"},{"name":"DestCountry","type":"keyword"},{"name":"DestRegion","type":"keyword"},{"name":"DestCityName","type":"keyword"},{"name":"OriginAirportID","type":"keyword"}],"datarows":[["9HY9SWR","Frankfurt am Main Airport",{"lat":50.033333,"lon":8.570556},{"lat":-33.94609833,"lon":151.177002},false,10247.856,1030.7704,"Sunny",0,841.2656,"OpenSearch Dashboards Airlines",0,"DE-HE","SYD","No Delay","2021-11-01 00:00:00","Sydney Kingsford Smith International Airport","17.179506930998397",false,16492.326,"Frankfurt am Main","Rain","DE","AU","SE-BD","Sydney","FRA"],["X98CCZO","Cape Town International Airport",{"lat":-33.96480179,"lon":18.60169983},{"lat":45.505299,"lon":12.3519},false,5482.6064,464.3895,"Clear",0,882.98267,"Logstash Airways",0,"SE-BD","VE05","No Delay","2021-11-01 18:27:00","Venice Marco Polo Airport","7.73982468459836",false,8823.4,"Cape Town","Sunny","ZA","IT","IT-34","Venice","CPT"]],"total":2,"size":2,"status":200}',
+ ],
+ },
+];
+
+// Sample notebook with all input and cleared outputs
+export const sampleNotebook2 = {
+ id: 'note_5f4b9eed-5898-4b39-ba6c-755c0fadd84e',
+ dateCreated: '2020-08-20T18:00:59.845Z',
+ name: 'test 1',
+ dateModified: '2020-08-20T19:13:06.509Z',
+ pluginVersion: '7.9.0',
+ backend: 'Default',
+ paragraphs: [
+ {
+ output: [
+ {
+ result:
+ '# Type no output here\n* Sample link: [link](https://opensearch.org/)\n* ~~Strike~~, **Bold**, __Italic__',
+ outputType: 'MARKDOWN',
+ execution_time: '0s',
+ },
+ ],
+ input: {
+ inputText:
+ '# Type no output here\n* Sample link: [link](https://opensearch.org/)\n* ~~Strike~~, **Bold**, __Italic__',
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: '2020-08-20T18:00:59.845Z',
+ dateModified: '2020-08-20T19:13:06.509Z',
+ id: 'paragraph_1a710988-ec19-4caa-83cc-38eb609427d1',
+ },
+ {
+ output: [],
+ input: { inputText: '# no output here\n', inputType: 'MARKDOWN' },
+ dateCreated: '2020-08-20T18:01:07.662Z',
+ dateModified: '2020-08-20T19:09:19.210Z',
+ id: 'paragraph_c3107b15-da7d-4836-aef4-0996abbc8ab2',
+ },
+ {
+ output: [],
+ input: {
+ inputText:
+ '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}',
+ inputType: 'VISUALIZATION',
+ },
+ dateCreated: '2020-08-20T18:37:44.809Z',
+ dateModified: '2020-08-20T18:37:56.844Z',
+ id: 'paragraph_6d3237a9-6486-4f93-aa25-0a1c838faabd',
+ },
+ ],
+};
+
+// Parsed Output of sample notebook2
+export const sampleParsedParagraghs2 = [
+ {
+ uniqueId: 'paragraph_1a710988-ec19-4caa-83cc-38eb609427d1',
+ isRunning: false,
+ inQueue: false,
+ isSelected: false,
+ isInputHidden: false,
+ isOutputHidden: false,
+ showAddPara: false,
+ isVizualisation: false,
+ vizObjectInput: '',
+ id: 1,
+ inp: '# Type no output here\n* Sample link: [link](https://opensearch.org/)\n* ~~Strike~~, **Bold**, __Italic__',
+ lang: 'text/x-md',
+ isInputExpanded: false,
+ isOutputStale: false,
+ paraDivRef: undefined,
+ paraRef: undefined,
+ visEndTime: undefined,
+ visSavedObjId: undefined,
+ visStartTime: undefined,
+ editorLanguage: 'md',
+ typeOut: ['MARKDOWN'],
+ out: [
+ '# Type no output here\n* Sample link: [link](https://opensearch.org/)\n* ~~Strike~~, **Bold**, __Italic__',
+ ],
+ },
+ {
+ uniqueId: 'paragraph_c3107b15-da7d-4836-aef4-0996abbc8ab2',
+ isRunning: false,
+ inQueue: false,
+ isSelected: false,
+ isInputHidden: false,
+ isOutputHidden: false,
+ showAddPara: false,
+ isVizualisation: false,
+ vizObjectInput: '',
+ id: 2,
+ inp: '# no output here\n',
+ isInputExpanded: false,
+ isOutputStale: false,
+ paraDivRef: undefined,
+ paraRef: undefined,
+ visEndTime: undefined,
+ visSavedObjId: undefined,
+ visStartTime: undefined,
+ lang: 'text/x-md',
+ editorLanguage: 'md',
+ typeOut: [],
+ out: [],
+ },
+ {
+ uniqueId: 'paragraph_6d3237a9-6486-4f93-aa25-0a1c838faabd',
+ isRunning: false,
+ inQueue: false,
+ isSelected: false,
+ isInputHidden: false,
+ isOutputHidden: false,
+ showAddPara: false,
+ isVizualisation: true,
+ vizObjectInput:
+ '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}',
+ id: 3,
+ inp: '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}',
+ lang: 'text/x-',
+ isInputExpanded: false,
+ isOutputStale: false,
+ paraDivRef: undefined,
+ paraRef: undefined,
+ visEndTime: '2020-08-20T18:37:44.710Z',
+ visSavedObjId: '935afa20-e0cd-11e7-9d07-1398ccfcefa3',
+ visStartTime: '2020-07-21T18:37:44.710Z',
+ editorLanguage: '',
+ typeOut: [],
+ out: [],
+ },
+];
+
+// Sample notebook with no input
+export const sampleNotebook3 = {
+ id: 'note_5f4b9eed-5898-4b39-ba6c-755c0fadd84e',
+ dateCreated: '2020-08-20T18:00:59.845Z',
+ name: 'test 1',
+ dateModified: '2020-08-20T19:13:06.509Z',
+ pluginVersion: '7.9.0',
+ backend: 'Default',
+ paragraphs: [
+ {
+ output: [
+ {
+ result:
+ '# Type no output here\n* Sample link: [link](https://opensearch.org/)\n* ~~Strike~~, **Bold**, __Italic__',
+ outputType: 'MARKDOWN',
+ execution_time: '0s',
+ },
+ ],
+ dateCreated: '2020-08-20T18:00:59.845Z',
+ dateModified: '2020-08-20T19:13:06.509Z',
+ id: 'paragraph_1a710988-ec19-4caa-83cc-38eb609427d1',
+ },
+ ],
+};
+
+// Sample notebook with no paragraph id
+export const sampleNotebook4 = {
+ id: 'note_5f4b9eed-5898-4b39-ba6c-755c0fadd84e',
+ dateCreated: '2020-08-20T18:00:59.845Z',
+ name: 'test 1',
+ dateModified: '2020-08-20T19:13:06.509Z',
+ pluginVersion: '7.9.0',
+ backend: 'Default',
+ paragraphs: [
+ {
+ output: [
+ {
+ result:
+ '# Type no output here\n* Sample link: [link](https://opensearch.org/)\n* ~~Strike~~, **Bold**, __Italic__',
+ outputType: 'MARKDOWN',
+ execution_time: '0s',
+ },
+ ],
+ dateCreated: '2020-08-20T18:00:59.845Z',
+ dateModified: '2020-08-20T19:13:06.509Z',
+ },
+ ],
+};
+
+// Sample notebook with no input and output
+export const sampleNotebook5 = {
+ id: 'note_5f4b9eed-5898-4b39-ba6c-755c0fadd84e',
+ dateCreated: '2020-08-20T18:00:59.845Z',
+ name: 'test 1',
+ dateModified: '2020-08-20T19:13:06.509Z',
+ pluginVersion: '7.9.0',
+ backend: 'Default',
+ paragraphs: [
+ {
+ dateCreated: '2020-08-20T18:00:59.845Z',
+ dateModified: '2020-08-20T19:13:06.509Z',
+ id: 'paragraph_c3107b15-da7d-4836-aef4-0996abbc8ab2',
+ },
+ ],
+};
diff --git a/public/components/notebooks/components/helpers/__tests__/sampleZeppelinNotebooks.tsx b/public/components/notebooks/components/helpers/__tests__/sampleZeppelinNotebooks.tsx
new file mode 100644
index 0000000000..db07da1c51
--- /dev/null
+++ b/public/components/notebooks/components/helpers/__tests__/sampleZeppelinNotebooks.tsx
@@ -0,0 +1,359 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+// Sample notebook with all input and output
+export const sampleNotebook1 = {
+ paragraphs: [
+ {
+ text:
+ "%md \n\n### Hi Everyone\n* Here's a demo on **OpenSearch Dashboards Notebooks**\n* You may use the top left buttons to play around with notebooks and Paragraphs",
+ user: 'anonymous',
+ dateUpdated: '2020-08-20 21:15:04.590',
+ config: {},
+ settings: { params: {}, forms: {} },
+ results: {
+ code: 'SUCCESS',
+ msg: [
+ {
+ type: 'HTML',
+ data:
+ '\n
Hi Everyone \n
\nHere’s a demo on OpenSearch Dashboards Notebooks \nYou may use the top left buttons to play around with notebooks and Paragraphs \n \n\n
',
+ },
+ ],
+ },
+ apps: [],
+ runtimeInfos: {},
+ progressUpdateIntervalMs: 500,
+ jobName: 'paragraph_1597958104590_901298942',
+ id: 'paragraph_1596519508360_932236116',
+ dateCreated: '2020-08-20 21:15:04.590',
+ status: 'READY',
+ },
+ {
+ title: 'VISUALIZATION',
+ text:
+ '%sh #vizobject:{"viewMode":"view","panels":{"1":{"gridData":{"x":15,"y":0,"w":20,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"06cf9c40-9ee8-11e7-8711-e7a007dcef99"}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"iab4eaba1-e32b-11ea-aac8-99f209533253","timeRange":{"to":"2020-08-20T21:25:28.538Z","from":"2020-07-21T21:25:28.538Z"},"title":"embed_viz_iab4eaba1-e32b-11ea-aac8-99f209533253","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}',
+ user: 'anonymous',
+ dateUpdated: '2020-08-20 21:25:28.588',
+ config: {},
+ settings: { params: {}, forms: {} },
+ apps: [],
+ runtimeInfos: {},
+ progressUpdateIntervalMs: 500,
+ jobName: 'paragraph_1597958728587_1310320520',
+ id: 'paragraph_1597958728587_1310320520',
+ dateCreated: '2020-08-20 21:25:28.587',
+ status: 'READY',
+ },
+ ],
+ name: 'Embed Vizualization',
+ id: '2FJH8PW8K',
+ defaultInterpreterGroup: 'spark',
+ version: '0.9.0-preview2',
+ noteParams: {},
+ noteForms: {},
+ angularObjects: {},
+ config: { isZeppelinNotebookCronEnable: false },
+ info: {},
+};
+
+// Parsed Output of sample notebook1
+export const sampleParsedParagraghs1 = [
+ {
+ uniqueId: 'paragraph_1596519508360_932236116',
+ isRunning: false,
+ inQueue: false,
+ ishovered: false,
+ isSelected: false,
+ isInputHidden: false,
+ isOutputHidden: false,
+ showAddPara: false,
+ isVizualisation: false,
+ vizObjectInput: '',
+ id: 1,
+ inp:
+ "%md \n\n### Hi Everyone\n* Here's a demo on **OpenSearch Dashboards Notebooks**\n* You may use the top left buttons to play around with notebooks and Paragraphs",
+ lang: 'text/x-',
+ editorLanguage: '',
+ typeOut: ['HTML'],
+ out: [
+ '\n
Hi Everyone \n
\nHere’s a demo on OpenSearch Dashboards Notebooks \nYou may use the top left buttons to play around with notebooks and Paragraphs \n \n\n
',
+ ],
+ },
+ {
+ uniqueId: 'paragraph_1597958728587_1310320520',
+ isRunning: false,
+ inQueue: false,
+ ishovered: false,
+ isSelected: false,
+ isInputHidden: false,
+ isOutputHidden: false,
+ showAddPara: false,
+ isVizualisation: true,
+ vizObjectInput:
+ '{"viewMode":"view","panels":{"1":{"gridData":{"x":15,"y":0,"w":20,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"06cf9c40-9ee8-11e7-8711-e7a007dcef99"}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"iab4eaba1-e32b-11ea-aac8-99f209533253","timeRange":{"to":"2020-08-20T21:25:28.538Z","from":"2020-07-21T21:25:28.538Z"},"title":"embed_viz_iab4eaba1-e32b-11ea-aac8-99f209533253","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}',
+ id: 2,
+ inp:
+ '%sh #vizobject:{"viewMode":"view","panels":{"1":{"gridData":{"x":15,"y":0,"w":20,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"06cf9c40-9ee8-11e7-8711-e7a007dcef99"}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"iab4eaba1-e32b-11ea-aac8-99f209533253","timeRange":{"to":"2020-08-20T21:25:28.538Z","from":"2020-07-21T21:25:28.538Z"},"title":"embed_viz_iab4eaba1-e32b-11ea-aac8-99f209533253","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}',
+ lang: 'text/x-',
+ editorLanguage: '',
+ typeOut: [],
+ out: [],
+ },
+];
+
+// Sample notebook with all input and cleared outputs
+export const sampleNotebook2 = {
+ paragraphs: [
+ {
+ text:
+ "%md \n\n### Hi Everyone\n* Here's a demo on **OpenSearch Dashboards Notebooks**\n* You may use the top left buttons to play around with notebooks and Paragraphs",
+ user: 'anonymous',
+ dateUpdated: '2020-08-20 21:15:04.590',
+ config: {},
+ settings: { params: {}, forms: {} },
+ apps: [],
+ runtimeInfos: {},
+ progressUpdateIntervalMs: 500,
+ jobName: 'paragraph_1597958104590_901298942',
+ id: 'paragraph_1596519508360_932236116',
+ dateCreated: '2020-08-20 21:15:04.590',
+ status: 'READY',
+ },
+ {
+ title: 'Paragraph inserted',
+ text: '%md\n\n## Greetings!\n* Yay! you may import and export me ',
+ user: 'anonymous',
+ dateUpdated: '2020-08-20 21:15:04.590',
+ config: {},
+ settings: { params: {}, forms: {} },
+ apps: [],
+ runtimeInfos: {},
+ progressUpdateIntervalMs: 500,
+ jobName: 'paragraph_1597958104590_1715920734',
+ id: 'paragraph_1596742076640_674206137',
+ dateCreated: '2020-08-20 21:15:04.590',
+ status: 'READY',
+ },
+ {
+ title: 'Paragraph inserted',
+ text:
+ "%md\n\n### Let's use Visualization API with dashboard container to embed Visualizations in notebooks\n2. **Unpin** the container to *edit the size* or *delete it*\n3. **Refresh** the container after *date is changed*",
+ user: 'anonymous',
+ dateUpdated: '2020-08-20 21:15:04.590',
+ config: {},
+ settings: { params: {}, forms: {} },
+ apps: [],
+ runtimeInfos: {},
+ progressUpdateIntervalMs: 500,
+ jobName: 'paragraph_1597958104590_931410594',
+ id: 'paragraph_1596524302932_2112910756',
+ dateCreated: '2020-08-20 21:15:04.590',
+ status: 'READY',
+ },
+ {
+ title: 'VISUALIZATION',
+ text:
+ '%sh #vizobject:{"viewMode":"view","panels":{"1":{"gridData":{"x":15,"y":0,"w":20,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"06cf9c40-9ee8-11e7-8711-e7a007dcef99"}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"iab4eaba1-e32b-11ea-aac8-99f209533253","timeRange":{"to":"2020-08-20T21:25:28.538Z","from":"2020-07-21T21:25:28.538Z"},"title":"embed_viz_iab4eaba1-e32b-11ea-aac8-99f209533253","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}',
+ user: 'anonymous',
+ dateUpdated: '2020-08-20 21:25:28.588',
+ config: {},
+ settings: { params: {}, forms: {} },
+ apps: [],
+ runtimeInfos: {},
+ progressUpdateIntervalMs: 500,
+ jobName: 'paragraph_1597958728587_1310320520',
+ id: 'paragraph_1597958728587_1310320520',
+ dateCreated: '2020-08-20 21:25:28.587',
+ status: 'READY',
+ },
+ ],
+ name: 'Embed Vizualization',
+ id: '2FJH8PW8K',
+ defaultInterpreterGroup: 'spark',
+ version: '0.9.0-preview2',
+ noteParams: {},
+ noteForms: {},
+ angularObjects: {},
+ config: { isZeppelinNotebookCronEnable: false },
+ info: {},
+};
+
+// Parsed Output of sample notebook2
+export const sampleParsedParagraghs2 = [
+ {
+ uniqueId: 'paragraph_1596519508360_932236116',
+ isRunning: false,
+ inQueue: false,
+ ishovered: false,
+ isSelected: false,
+ isInputHidden: false,
+ isOutputHidden: false,
+ showAddPara: false,
+ isVizualisation: false,
+ vizObjectInput: '',
+ id: 1,
+ inp:
+ "%md \n\n### Hi Everyone\n* Here's a demo on **OpenSearch Dashboards Notebooks**\n* You may use the top left buttons to play around with notebooks and Paragraphs",
+ lang: 'text/x-',
+ editorLanguage: '',
+ typeOut: [],
+ out: [],
+ },
+ {
+ uniqueId: 'paragraph_1596742076640_674206137',
+ isRunning: false,
+ inQueue: false,
+ ishovered: false,
+ isSelected: false,
+ isInputHidden: false,
+ isOutputHidden: false,
+ showAddPara: false,
+ isVizualisation: false,
+ vizObjectInput: '',
+ id: 2,
+ inp: '%md\n\n## Greetings!\n* Yay! you may import and export me ',
+ lang: 'text/x-md',
+ editorLanguage: 'md',
+ typeOut: [],
+ out: [],
+ },
+ {
+ uniqueId: 'paragraph_1596524302932_2112910756',
+ isRunning: false,
+ inQueue: false,
+ ishovered: false,
+ isSelected: false,
+ isInputHidden: false,
+ isOutputHidden: false,
+ showAddPara: false,
+ isVizualisation: false,
+ vizObjectInput: '',
+ id: 3,
+ inp:
+ "%md\n\n### Let's use Visualization API with dashboard container to embed Visualizations in notebooks\n2. **Unpin** the container to *edit the size* or *delete it*\n3. **Refresh** the container after *date is changed*",
+ lang: 'text/x-md',
+ editorLanguage: 'md',
+ typeOut: [],
+ out: [],
+ },
+ {
+ uniqueId: 'paragraph_1597958728587_1310320520',
+ isRunning: false,
+ inQueue: false,
+ ishovered: false,
+ isSelected: false,
+ isInputHidden: false,
+ isOutputHidden: false,
+ showAddPara: false,
+ isVizualisation: true,
+ vizObjectInput:
+ '{"viewMode":"view","panels":{"1":{"gridData":{"x":15,"y":0,"w":20,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"06cf9c40-9ee8-11e7-8711-e7a007dcef99"}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"iab4eaba1-e32b-11ea-aac8-99f209533253","timeRange":{"to":"2020-08-20T21:25:28.538Z","from":"2020-07-21T21:25:28.538Z"},"title":"embed_viz_iab4eaba1-e32b-11ea-aac8-99f209533253","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}',
+ id: 4,
+ inp:
+ '%sh #vizobject:{"viewMode":"view","panels":{"1":{"gridData":{"x":15,"y":0,"w":20,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"06cf9c40-9ee8-11e7-8711-e7a007dcef99"}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"iab4eaba1-e32b-11ea-aac8-99f209533253","timeRange":{"to":"2020-08-20T21:25:28.538Z","from":"2020-07-21T21:25:28.538Z"},"title":"embed_viz_iab4eaba1-e32b-11ea-aac8-99f209533253","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}',
+ lang: 'text/x-',
+ editorLanguage: '',
+ typeOut: [],
+ out: [],
+ },
+];
+
+// Sample notebook with no paragraph Id
+export const sampleNotebook3 = {
+ paragraphs: [
+ {
+ text:
+ "%md \n\n### Hi Everyone\n* Here's a demo on **OpenSearch Dashboards Notebooks**\n* You may use the top left buttons to play around with notebooks and Paragraphs",
+ user: 'anonymous',
+ dateUpdated: '2020-08-20 21:15:04.590',
+ config: {},
+ settings: { params: {}, forms: {} },
+ results: {
+ code: 'SUCCESS',
+ msg: [
+ {
+ type: 'HTML',
+ data:
+ '\n
Hi Everyone \n
\nHere’s a demo on OpenSearch Dashboards Notebooks \nYou may use the top left buttons to play around with notebooks and Paragraphs \n \n\n
',
+ },
+ ],
+ },
+ apps: [],
+ runtimeInfos: {},
+ progressUpdateIntervalMs: 500,
+ jobName: 'paragraph_1597958104590_901298942',
+ dateCreated: '2020-08-20 21:15:04.590',
+ status: 'READY',
+ },
+ ],
+ name: 'Embed Vizualization',
+ id: '2FJH8PW8K',
+ defaultInterpreterGroup: 'spark',
+ version: '0.9.0-preview2',
+ noteParams: {},
+ noteForms: {},
+ angularObjects: {},
+ config: { isZeppelinNotebookCronEnable: false },
+ info: {},
+};
+
+// Sample notebook with no VISUALIZAITON title
+export const sampleNotebook4 = {
+ paragraphs: [
+ {
+ text:
+ '%sh #vizobject:{"viewMode":"view","panels":{"1":{"gridData":{"x":15,"y":0,"w":20,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"06cf9c40-9ee8-11e7-8711-e7a007dcef99"}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"iab4eaba1-e32b-11ea-aac8-99f209533253","timeRange":{"to":"2020-08-20T21:25:28.538Z","from":"2020-07-21T21:25:28.538Z"},"title":"embed_viz_iab4eaba1-e32b-11ea-aac8-99f209533253","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}',
+ user: 'anonymous',
+ dateUpdated: '2020-08-20 21:25:28.588',
+ config: {},
+ settings: { params: {}, forms: {} },
+ apps: [],
+ runtimeInfos: {},
+ progressUpdateIntervalMs: 500,
+ jobName: 'paragraph_1597958728587_1310320520',
+ id: 'paragraph_1597958728587_1310320520',
+ dateCreated: '2020-08-20 21:25:28.587',
+ status: 'READY',
+ },
+ ],
+ name: 'Embed Vizualization',
+ id: '2FJH8PW8K',
+ defaultInterpreterGroup: 'spark',
+ version: '0.9.0-preview2',
+ noteParams: {},
+ noteForms: {},
+ angularObjects: {},
+ config: { isZeppelinNotebookCronEnable: false },
+ info: {},
+};
+
+// Sample notebook with no input and output
+export const sampleNotebook5 = {
+ paragraphs: [
+ {
+ user: 'anonymous',
+ dateUpdated: '2020-08-20 21:25:28.588',
+ config: {},
+ settings: { params: {}, forms: {} },
+ apps: [],
+ runtimeInfos: {},
+ progressUpdateIntervalMs: 500,
+ jobName: 'paragraph_1597958728587_1310320520',
+ id: 'paragraph_1597958728587_1310320520',
+ dateCreated: '2020-08-20 21:25:28.587',
+ status: 'READY',
+ },
+ ],
+ name: 'Embed Vizualization',
+ id: '2FJH8PW8K',
+ defaultInterpreterGroup: 'spark',
+ version: '0.9.0-preview2',
+ noteParams: {},
+ noteForms: {},
+ angularObjects: {},
+ config: { isZeppelinNotebookCronEnable: false },
+ info: {},
+};
diff --git a/public/components/notebooks/components/helpers/__tests__/zeppelin_parser.test.tsx b/public/components/notebooks/components/helpers/__tests__/zeppelin_parser.test.tsx
new file mode 100644
index 0000000000..df6542620e
--- /dev/null
+++ b/public/components/notebooks/components/helpers/__tests__/zeppelin_parser.test.tsx
@@ -0,0 +1,44 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { zeppelinParagraphParser } from '../zeppelin_parser';
+import {
+ sampleNotebook1,
+ sampleNotebook2,
+ sampleNotebook3,
+ sampleNotebook4,
+ sampleNotebook5,
+ sampleParsedParagraghs1,
+ sampleParsedParagraghs2,
+} from './sampleZeppelinNotebooks';
+
+// Perfect schema
+describe('Testing Zeppelin backend parser function with perfect schema', () => {
+ test('zeppelinParagraphParserTest1', async (done) => {
+ const parsedParagraphs1 = zeppelinParagraphParser(sampleNotebook1.paragraphs);
+ const parsedParagraphs2 = zeppelinParagraphParser(sampleNotebook2.paragraphs);
+ const parsedParagraphs3 = zeppelinParagraphParser([]);
+ expect(parsedParagraphs1).toEqual(sampleParsedParagraghs1);
+ expect(parsedParagraphs2).toEqual(sampleParsedParagraghs2);
+ expect(parsedParagraphs3).toEqual([]);
+ done();
+ });
+});
+
+// Issue in schema
+describe('Testing default backend parser function with wrong schema', () => {
+ test('zeppelinParagraphParserTest2', async (done) => {
+ expect(() => {
+ const parsedParagraphs1 = zeppelinParagraphParser(sampleNotebook3.paragraphs);
+ }).toThrow(Error);
+ expect(() => {
+ const parsedParagraphs2 = zeppelinParagraphParser(sampleNotebook4.paragraphs);
+ }).toThrow(Error);
+ expect(() => {
+ const parsedParagraphs3 = zeppelinParagraphParser(sampleNotebook5.paragraphs);
+ }).toThrow(Error);
+ done();
+ });
+});
diff --git a/public/components/notebooks/components/helpers/custom_modals/__tests__/__snapshots__/custom_input_modal.test.tsx.snap b/public/components/notebooks/components/helpers/custom_modals/__tests__/__snapshots__/custom_input_modal.test.tsx.snap
new file mode 100644
index 0000000000..69461a2540
--- /dev/null
+++ b/public/components/notebooks/components/helpers/custom_modals/__tests__/__snapshots__/custom_input_modal.test.tsx.snap
@@ -0,0 +1,101 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` spec renders the component 1`] = `
+
+
+
+
+ title
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+ Confirm
+
+
+
+
+`;
+
+exports[` spec renders the component 2`] = `
+
+
+
+
+ title
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+ Confirm
+
+
+
+
+`;
diff --git a/public/components/notebooks/components/helpers/custom_modals/__tests__/__snapshots__/reporting_loading_modal.test.tsx.snap b/public/components/notebooks/components/helpers/custom_modals/__tests__/__snapshots__/reporting_loading_modal.test.tsx.snap
new file mode 100644
index 0000000000..08ff025232
--- /dev/null
+++ b/public/components/notebooks/components/helpers/custom_modals/__tests__/__snapshots__/reporting_loading_modal.test.tsx.snap
@@ -0,0 +1,3 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` spec renders the component 1`] = `
`;
diff --git a/public/components/notebooks/components/helpers/custom_modals/__tests__/custom_input_modal.test.tsx b/public/components/notebooks/components/helpers/custom_modals/__tests__/custom_input_modal.test.tsx
new file mode 100644
index 0000000000..452696ed8f
--- /dev/null
+++ b/public/components/notebooks/components/helpers/custom_modals/__tests__/custom_input_modal.test.tsx
@@ -0,0 +1,68 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { fireEvent, render } from '@testing-library/react';
+import { configure, shallow } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { CustomInputModal } from '../custom_input_modal';
+
+describe(' spec', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders the component', () => {
+ const runModal = jest.fn();
+ const closeModal = jest.fn();
+ const wrapper = shallow(
+
+ );
+ expect(wrapper).toMatchSnapshot();
+
+ const emptyNameWrapper = shallow(
+
+ );
+ expect(emptyNameWrapper).toMatchSnapshot();
+ });
+
+ it('clicks buttons', () => {
+ const runModal = jest.fn();
+ const closeModal = jest.fn();
+ const utils = render(
+
+ );
+ fireEvent.change(utils.getByTestId('custom-input-modal-input'), {
+ target: { value: 'test-name' },
+ });
+ utils.getByTestId('custom-input-modal-confirm-button').click();
+ expect(runModal).toBeCalledWith('test-name');
+ });
+});
diff --git a/public/components/notebooks/components/helpers/custom_modals/__tests__/reporting_loading_modal.test.tsx b/public/components/notebooks/components/helpers/custom_modals/__tests__/reporting_loading_modal.test.tsx
new file mode 100644
index 0000000000..abfd4e5a06
--- /dev/null
+++ b/public/components/notebooks/components/helpers/custom_modals/__tests__/reporting_loading_modal.test.tsx
@@ -0,0 +1,22 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { fireEvent, render } from '@testing-library/react';
+import { configure, mount, shallow } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { GenerateReportLoadingModal } from '../reporting_loading_modal';
+
+describe(' spec', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders the component', () => {
+ const setShowLoading = jest.fn();
+ const utils = render( );
+ expect(utils.container.firstChild).toMatchSnapshot();
+ utils.getByTestId('reporting-loading-modal-close-button').click();
+ expect(setShowLoading).toBeCalledWith(false);
+ });
+});
diff --git a/public/components/notebooks/components/helpers/custom_modals/custom_input_modal.tsx b/public/components/notebooks/components/helpers/custom_modals/custom_input_modal.tsx
new file mode 100644
index 0000000000..5c11986490
--- /dev/null
+++ b/public/components/notebooks/components/helpers/custom_modals/custom_input_modal.tsx
@@ -0,0 +1,83 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useState } from 'react';
+import {
+ EuiButtonEmpty,
+ EuiForm,
+ EuiModal,
+ EuiModalBody,
+ EuiModalFooter,
+ EuiModalHeader,
+ EuiModalHeaderTitle,
+ EuiOverlayMask,
+ EuiFormRow,
+ EuiFieldText,
+ EuiButton,
+} from '@elastic/eui';
+
+/*
+ * "CustomInputModalProps" component is used to create a modal with an input filed
+ *
+ * Props taken in as params are:
+ * runModal - function to fetch input field value and trigger closing modal
+ * closeModal - function to trigger closing modal
+ * titletxt - string as header for title of modal
+ * labelTxt - string as header for input field
+ * btn1txt - string as content to fill "close button"
+ * btn2txt - string as content to fill "confirm button"
+ * openNoteName - Default input value for the field
+ */
+type CustomInputModalProps = {
+ runModal: (value: string) => void;
+ closeModal: (
+ event?: React.KeyboardEvent | React.MouseEvent
+ ) => void;
+ labelTxt: string;
+ titletxt: string;
+ btn1txt: string;
+ btn2txt: string;
+ openNoteName: string;
+ helpText: string;
+};
+
+export const CustomInputModal = (props: CustomInputModalProps) => {
+ const { runModal, closeModal, labelTxt, titletxt, btn1txt, btn2txt, openNoteName, helpText } = props;
+ const [value, setValue] = useState(openNoteName || ''); // sets input value
+
+ const onChange = (e: React.ChangeEvent) => {
+ setValue(e.target.value);
+ };
+
+ return (
+
+
+
+ {titletxt}
+
+
+
+
+
+ onChange(e)}
+ />
+
+
+
+
+
+ {btn1txt}
+ runModal(value)} fill>
+ {btn2txt}
+
+
+
+
+ );
+};
diff --git a/public/components/notebooks/components/helpers/custom_modals/reporting_loading_modal.tsx b/public/components/notebooks/components/helpers/custom_modals/reporting_loading_modal.tsx
new file mode 100644
index 0000000000..97de6788d1
--- /dev/null
+++ b/public/components/notebooks/components/helpers/custom_modals/reporting_loading_modal.tsx
@@ -0,0 +1,70 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ EuiOverlayMask,
+ EuiModal,
+ EuiModalHeader,
+ EuiTitle,
+ EuiText,
+ EuiModalBody,
+ EuiSpacer,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiLoadingSpinner,
+ EuiButton
+} from "@elastic/eui";
+import React from "react";
+
+export function GenerateReportLoadingModal(props: { setShowLoading: any; }) {
+ const {
+ setShowLoading
+ } = props;
+
+ const closeModal = () => {
+ setShowLoading(false);
+ };
+
+ return (
+
+
+
+
+
+
+ Generating report
+
+
+
+
+ Preparing your file for download.
+ You can close this dialog while we continue in the background.
+
+
+
+
+
+
+
+
+
+
+ Close
+
+
+
+
+
+
+
+ );
+};
\ No newline at end of file
diff --git a/public/components/notebooks/components/helpers/default_parser.tsx b/public/components/notebooks/components/helpers/default_parser.tsx
new file mode 100644
index 0000000000..c38dad3cd5
--- /dev/null
+++ b/public/components/notebooks/components/helpers/default_parser.tsx
@@ -0,0 +1,119 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { ParaType } from '../../../../../common/types/notebooks';
+
+// Get the type of output and result in a default notebook paragraph
+// Param: Default Backend Paragraph
+const parseOutput = (paraObject: any) => {
+ try {
+ let outputType = [];
+ let result = [];
+ paraObject.output.map((output: { outputType: string; result: string }) => {
+ outputType.push(output.outputType);
+ result.push(output.result);
+ });
+ return {
+ outputType: outputType,
+ outputData: result,
+ };
+ } catch (error) {
+ return {
+ outputType: [],
+ outputData: [],
+ };
+ }
+};
+
+// Get the coding language by type of paragraph
+// Param: Default Backend Paragraph
+const parseInputType = (paraObject: any) => {
+ try {
+ if (paraObject.input.inputType === 'MARKDOWN') {
+ return 'md';
+ } else {
+ return '';
+ }
+ } catch (error) {
+ throw new Error('Parsing Input Issue ' + error);
+ }
+};
+
+// Get the visualization by type of paragraph
+// Param: Default Backend Paragraph
+const parseVisualization = (paraObject: any) => {
+ try {
+ if (paraObject.input.inputType.includes('VISUALIZATION')) {
+ let vizContent = paraObject.input.inputText;
+ const startDate = new Date();
+ startDate.setDate(startDate.getDate() - 30);
+ let visStartTime = startDate.toISOString();
+ let visEndTime = new Date().toISOString();
+ let visSavedObjId = '';
+ if (vizContent !== '') {
+ const { panels, timeRange } = JSON.parse(vizContent);
+ visStartTime = timeRange.from;
+ visEndTime = timeRange.to;
+ visSavedObjId = panels['1'].explicitInput.savedObjectId;
+ }
+ return {
+ isViz: true,
+ VizObject: vizContent,
+ visStartTime,
+ visEndTime,
+ visSavedObjId,
+ };
+ } else {
+ return {
+ isViz: false,
+ VizObject: '',
+ };
+ }
+ } catch (error) {
+ throw new Error('Parsing Input Issue ' + error);
+ }
+};
+
+// Placeholder for default parser
+// Param: Default Backend Paragraph
+export const defaultParagraphParser = (defaultBackendParagraphs: any) => {
+ let parsedPara: Array = [];
+ try {
+ defaultBackendParagraphs.map((paraObject: any, index: number) => {
+ const codeLanguage = parseInputType(paraObject);
+ const vizParams = parseVisualization(paraObject);
+ const message = parseOutput(paraObject);
+
+ let tempPara: ParaType = {
+ uniqueId: paraObject.id,
+ isRunning: false,
+ inQueue: false,
+ isSelected: false,
+ isInputHidden: false,
+ isOutputHidden: false,
+ showAddPara: false,
+ isVizualisation: vizParams.isViz,
+ vizObjectInput: vizParams.VizObject,
+ id: index + 1,
+ inp: paraObject.input.inputText || '',
+ lang: 'text/x-' + codeLanguage,
+ editorLanguage: codeLanguage,
+ typeOut: message.outputType,
+ out: message.outputData,
+ isInputExpanded: false,
+ isOutputStale: false,
+ paraRef: undefined,
+ paraDivRef: undefined,
+ visStartTime: vizParams.visStartTime,
+ visEndTime: vizParams.visEndTime,
+ visSavedObjId: vizParams.visSavedObjId,
+ };
+ parsedPara.push(tempPara);
+ });
+ return parsedPara;
+ } catch (error) {
+ throw new Error('Parsing Paragraph Issue ' + error);
+ }
+};
diff --git a/public/components/notebooks/components/helpers/download_json.tsx b/public/components/notebooks/components/helpers/download_json.tsx
new file mode 100644
index 0000000000..53128ac354
--- /dev/null
+++ b/public/components/notebooks/components/helpers/download_json.tsx
@@ -0,0 +1,14 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+// Helper function to create download object
+export function onDownload(content: any, fileName: string) {
+ let dataUri =
+ 'data:application/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(content));
+ let downloadElement = document.createElement('a');
+ downloadElement.setAttribute('href', dataUri);
+ downloadElement.setAttribute('download', fileName);
+ downloadElement.click();
+}
diff --git a/public/components/notebooks/components/helpers/legacy_route_helpers.ts b/public/components/notebooks/components/helpers/legacy_route_helpers.ts
new file mode 100644
index 0000000000..8bda04cc59
--- /dev/null
+++ b/public/components/notebooks/components/helpers/legacy_route_helpers.ts
@@ -0,0 +1,14 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { observabilityID } from "../../../../../common/constants/shared";
+
+export const convertLegacyNotebooksUrl = (location: Location)=> {
+ const pathname = location.pathname.replace('notebooks-dashboards', observabilityID);
+ const hash = `#/notebooks${location.hash.replace(/^#/, '')}${
+ location.hash.includes('?') ? location.search.replace(/^\?/, '&') : location.search
+ }`;
+ return pathname + hash;
+};
diff --git a/public/components/notebooks/components/helpers/modal_containers.tsx b/public/components/notebooks/components/helpers/modal_containers.tsx
new file mode 100644
index 0000000000..53448012d8
--- /dev/null
+++ b/public/components/notebooks/components/helpers/modal_containers.tsx
@@ -0,0 +1,183 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useState } from 'react';
+import {
+ EuiOverlayMask,
+ EuiConfirmModal,
+ EuiButton,
+ EuiButtonEmpty,
+ EuiFieldText,
+ EuiForm,
+ EuiFormRow,
+ EuiModal,
+ EuiModalBody,
+ EuiModalFooter,
+ EuiModalHeader,
+ EuiModalHeaderTitle,
+ EuiText,
+ EuiSpacer
+} from '@elastic/eui';
+import { CustomInputModal } from './custom_modals/custom_input_modal';
+
+/* The file contains helper functions for modal layouts
+ * getCustomModal - returns modal with input field
+ * getCloneModal - returns a confirm-modal with clone option
+ * getDeleteModal - returns a confirm-modal with delete option
+ */
+
+export const getCustomModal = (
+ runModal: (value: string) => void,
+ closeModal: (
+ event?: React.KeyboardEvent | React.MouseEvent
+ ) => void,
+ labelTxt: string,
+ titletxt: string,
+ btn1txt: string,
+ btn2txt: string,
+ openNoteName?: string,
+ helpText?: string,
+) => {
+ return (
+
+ );
+};
+
+export const getCloneModal = (
+ onCancel: (
+ event?: React.KeyboardEvent | React.MouseEvent
+ ) => void,
+ onConfirm: (event?: React.MouseEvent) => void
+) => {
+ return (
+
+
+ Do you want to clone this notebook?
+
+
+ );
+};
+
+export const getSampleNotebooksModal = (
+ onCancel: (
+ event?: React.KeyboardEvent | React.MouseEvent
+ ) => void,
+ onConfirm: (event?: React.MouseEvent) => void
+) => {
+ return (
+
+
+ Do you want to add sample notebooks? This will also add Dashboards sample flights and logs data if they have not been added.
+
+
+ );
+};
+
+export const getDeleteModal = (
+ onCancel: (
+ event?: React.KeyboardEvent | React.MouseEvent
+ ) => void,
+ onConfirm: (event?: React.MouseEvent) => void,
+ title: string,
+ message: string,
+ confirmMessage?: string,
+) => {
+ return (
+
+
+ {message}
+
+
+ );
+};
+
+export const DeleteNotebookModal = ({
+ onCancel,
+ onConfirm,
+ title,
+ message,
+}: {
+ onCancel: (
+ event?: React.KeyboardEvent | React.MouseEvent
+ ) => void;
+ onConfirm: (event?: React.MouseEvent) => void;
+ title: string;
+ message: string;
+}) => {
+ const [value, setValue] = useState('');
+ const onChange = (e: React.ChangeEvent) => {
+ setValue(e.target.value);
+ };
+ return (
+
+
+
+ {title}
+
+
+
+ {message}
+ The action cannot be undone.
+
+
+
+ onChange(e)}
+ />
+
+
+
+
+
+ Cancel
+ onConfirm()}
+ color="danger"
+ fill
+ disabled={value !== 'delete'}
+ >
+ Delete
+
+
+
+
+ );
+};
diff --git a/public/components/notebooks/components/helpers/reporting_context_menu_helper.tsx b/public/components/notebooks/components/helpers/reporting_context_menu_helper.tsx
new file mode 100644
index 0000000000..a174da65b8
--- /dev/null
+++ b/public/components/notebooks/components/helpers/reporting_context_menu_helper.tsx
@@ -0,0 +1,236 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { parse } from "url";
+
+const getReportSourceURL = (baseURI: string) => {
+ return baseURI.substr(baseURI.lastIndexOf('/') + 1, baseURI.length);
+}
+
+export const readDataReportToFile = async (
+ stream: string,
+ fileFormat: string,
+ fileName: string
+) => {
+ const blob = new Blob([stream]);
+ const url = URL.createObjectURL(blob);
+ let link = document.createElement('a');
+ link.setAttribute('href', url);
+ link.setAttribute('download', fileName);
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+};
+
+const getFileFormatPrefix = (fileFormat: string) => {
+ var fileFormatPrefix = 'data:' + fileFormat + ';base64,';
+ return fileFormatPrefix;
+};
+
+const readStreamToFile = async (
+ stream: string,
+ fileFormat: string,
+ fileName: string
+) => {
+ let link = document.createElement('a');
+ if (fileName.includes('csv')) {
+ readDataReportToFile(stream, fileFormat, fileName);
+ return;
+ }
+ let fileFormatPrefix = getFileFormatPrefix(fileFormat);
+ let url = fileFormatPrefix + stream;
+ if (typeof link.download !== 'string') {
+ window.open(url, '_blank');
+ return;
+ }
+ link.download = fileName;
+ link.href = url;
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+};
+
+async function getTenantInfoIfExists() {
+ const res = await fetch(`../api/v1/multitenancy/tenant`, {
+ headers: {
+ 'Content-Type': 'application/json',
+ 'osd-xsrf': 'true',
+ accept: '*/*',
+ 'accept-language': 'en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7,zh-TW;q=0.6',
+ pragma: 'no-cache',
+ 'sec-fetch-dest': 'empty',
+ 'sec-fetch-mode': 'cors',
+ 'sec-fetch-site': 'same-origin',
+ },
+ method: 'GET',
+ referrerPolicy: 'strict-origin-when-cross-origin',
+ mode: 'cors',
+ credentials: 'include',
+ })
+ .then((response) => {
+ if (response.status === 404) {
+ // endpoint doesn't exist, security plugin is not enabled.
+ return undefined;
+ } else {
+ return response.text();
+ }
+ })
+ .then((tenant) => {
+ if (tenant === '') {
+ tenant = 'global';
+ } else if (tenant === '__user__') {
+ tenant = 'private';
+ }
+ return tenant;
+ });
+
+ return res;
+}
+
+function addTenantToURL(url, userRequestedTenant) {
+ // build fake url from relative url
+ const fakeUrl = `http://opensearch.com${url}`;
+ const tenantKey = 'security_tenant';
+ const tenantKeyAndValue =
+ tenantKey + '=' + encodeURIComponent(userRequestedTenant);
+
+ const { pathname, search } = parse(fakeUrl);
+ const queryDelimiter = !search ? '?' : '&';
+ // The url parser returns null if the search is empty. Change that to an empty
+ // string so that we can use it to build the values later
+ if (search && search.toLowerCase().indexOf(tenantKey) > -1) {
+ // If we for some reason already have a tenant in the URL we skip any updates
+ return url;
+ }
+
+ // A helper for finding the part in the string that we want to extend/replace
+ const valueToReplace = pathname + (search || '');
+ const replaceWith = valueToReplace + queryDelimiter + tenantKeyAndValue;
+
+ return url.replace(valueToReplace, replaceWith);
+}
+
+export const generateInContextReport = async (
+ fileFormat: string,
+ props: any,
+ toggleReportingLoadingModal: any,
+ rest = {}
+) => {
+ toggleReportingLoadingModal(true);
+ let baseUrl =
+ location.pathname +
+ location.hash.replace(/\?view=(view_both|input_only|output_only)/, '') +
+ '?view=output_only';
+ // Add selected tenant info to url
+ try {
+ const tenant = await getTenantInfoIfExists();
+ if (tenant) {
+ baseUrl = addTenantToURL(baseUrl, tenant)
+ }
+ } catch (error) {
+ props.setToast(
+ 'Tenant error',
+ 'danger',
+ 'Failed to get user tenant.'
+ );
+ console.log(`failed to get user tenant: ${error}`);
+ }
+
+ const reportSource = 'Notebook';
+ const contextMenuOnDemandReport = {
+ query_url: baseUrl,
+ time_from: 0, // no time range for notebook reports
+ time_to: 0,
+ report_definition: {
+ report_params: {
+ report_name: 'In-context ' + document.getElementById('notebookTitle')?.innerText,
+ report_source: reportSource,
+ description: 'In-context report download',
+ core_params: {
+ base_url: baseUrl,
+ report_format: fileFormat,
+ time_duration: 'PT30M', // time duration can be hard-coded
+ ...rest,
+ },
+ },
+ delivery: {
+ configIds: [],
+ title: '',
+ textDescription: '',
+ htmlDescription: '',
+ },
+ trigger: {
+ trigger_type: 'On demand',
+ },
+ },
+ };
+ fetch(
+ '../api/reporting/generateReport',
+ {
+ headers: {
+ 'Content-Type': 'application/json',
+ 'osd-xsrf': 'true',
+ accept: '*/*',
+ 'accept-language': 'en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7,zh-TW;q=0.6',
+ pragma: 'no-cache',
+ 'sec-fetch-dest': 'empty',
+ 'sec-fetch-mode': 'cors',
+ 'sec-fetch-site': 'same-origin',
+ },
+ method: 'POST',
+ body: JSON.stringify(contextMenuOnDemandReport),
+ referrerPolicy: 'strict-origin-when-cross-origin',
+ mode: 'cors',
+ credentials: 'include',
+ }
+ )
+ .then((response) => {
+ toggleReportingLoadingModal(false);
+ if (response.status === 200) {
+ // success toast
+ props.setToast('Successfully generated report.', 'success');
+ } else {
+ if (response.status === 403) {
+ // permissions failure toast
+ props.setToast(
+ 'Error generating report,',
+ 'danger',
+ 'Insufficient permissions. Reach out to your OpenSearch Dashboards administrator.'
+ );
+ } else if (response.status === 503) {
+ // timeout failure
+ props.setToast(
+ 'Error generating report.',
+ 'danger',
+ 'Timed out generating on-demand report from notebook. Try again later.'
+ );
+ } else {
+ // generic failure
+ props.setToast(
+ 'Download error',
+ 'danger',
+ 'There was an error generating this report.'
+ );
+ }
+ }
+ return response.json();
+ })
+ .then(async (data) => {
+ await readStreamToFile(data.data, fileFormat, data.filename);
+ })
+}
+
+export const contextMenuCreateReportDefinition = (baseURI: string) => {
+ const reportSourceId = getReportSourceURL(baseURI);
+ let reportSource = 'notebook:';
+
+ reportSource += reportSourceId.toString();
+ window.location.assign(
+ `reports-dashboards#/create?previous=${reportSource}?timeFrom=0?timeTo=0`
+ );
+};
+
+export const contextMenuViewReports = () =>
+ window.location.assign('reports-dashboards#/');
diff --git a/public/components/notebooks/components/helpers/zeppelin_parser.tsx b/public/components/notebooks/components/helpers/zeppelin_parser.tsx
new file mode 100644
index 0000000000..f2293c3a72
--- /dev/null
+++ b/public/components/notebooks/components/helpers/zeppelin_parser.tsx
@@ -0,0 +1,149 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/* This file contains parsing functions
+ * These functions have to be changed based on backend configuration
+ * If backend changes the incoming paragraph structures may change, so parsing adapts to it
+ */
+
+import { ParaType } from '../../../common';
+
+const visualizationPrefix = '%sh #vizobject:';
+const observabilityVisualizationPrefix = '%sh #observabilityviz:';
+
+const langSupport = {
+ '%sh': 'shell',
+ '%md': 'md',
+ '%python': 'python',
+ '%opensearchsql': 'sql',
+ '%elasticsearch': 'json',
+};
+
+// Get the coding language from a Zeppelin paragraph input
+// Param: textHeader-> header on a Zeppelin paragraph example "%md"
+const parseCodeLanguage = (textHeader: string) => {
+ const codeLanguage = langSupport[textHeader];
+ return codeLanguage || '';
+};
+
+// Get the type of output message from a Zeppelin paragraph
+// Param: Zeppelin Paragraph
+const parseMessage = (paraObject: any) => {
+ try {
+ let mtype = [];
+ let mdata = [];
+ paraObject.results.msg.map((msg: { type: string; data: string }) => {
+ mtype.push(msg.type);
+ mdata.push(msg.data);
+ });
+ return {
+ outputType: mtype,
+ outputData: mdata,
+ };
+ } catch (error) {
+ return {
+ outputType: [],
+ outputData: [],
+ };
+ }
+};
+
+// Get the type of output message from a Zeppelin paragraph
+// Param: Zeppelin Paragraph
+const parseText = (paraObject: any) => {
+ if ('text' in paraObject) {
+ return paraObject.text;
+ } else {
+ throw new Error('Input text parse issue');
+ }
+};
+
+// Get the visualization from a Zeppelin Paragraph input
+// All Visualizations in Zeppelin are stored as shell comment -> "%sh #vizobject:"
+// TODO: This is a workaround need to look for better solutions
+// Param: Zeppelin Paragraph
+const parseVisualization = (paraObject: any) => {
+ let vizContent = '';
+ if (
+ paraObject.hasOwnProperty('text') &&
+ paraObject.text.substring(0, 15) === visualizationPrefix
+ ) {
+ if (paraObject.title !== 'VISUALIZATION') {
+ throw new Error('Visualization parse issue');
+ }
+ vizContent = paraObject.text.substring(15);
+ return {
+ isViz: true,
+ VizObject: vizContent,
+ };
+ }
+
+ if (
+ paraObject.hasOwnProperty('text') &&
+ paraObject.text.substring(0, 22) === observabilityVisualizationPrefix
+ ) {
+ if (paraObject.title !== 'OBSERVABILITY_VISUALIZATION') {
+ throw new Error('Visualization parse issue');
+ }
+ vizContent = paraObject.text.substring(22);
+ return {
+ isViz: true,
+ VizObject: vizContent,
+ };
+ }
+
+ return {
+ isViz: false,
+ VizObject: vizContent,
+ };
+};
+
+// This parser is used to get paragraph id
+// Param: Zeppelin Paragraph
+const parseId = (paraObject: any) => {
+ if ('id' in paraObject) {
+ return paraObject.id;
+ } else {
+ throw new Error('Id not found in paragraph');
+ }
+};
+
+// This parser helps to convert Zeppelin paragraphs to a common ParaType format
+// This parsing makes any backend notebook compatible with notebooks plugin
+export const zeppelinParagraphParser = (zeppelinBackendParagraphs: any) => {
+ let parsedPara: Array = [];
+ try {
+ zeppelinBackendParagraphs.map((paraObject: ParaType, index: number) => {
+ const paragraphId = parseId(paraObject);
+ const vizParams = parseVisualization(paraObject);
+ const inputParam = parseText(paraObject);
+ const codeLanguage = parseCodeLanguage(inputParam.split('\n')[0].split('.')[0]);
+ const message = parseMessage(paraObject);
+
+ let tempPara = {
+ uniqueId: paragraphId,
+ isRunning: false,
+ inQueue: false,
+ ishovered: false,
+ isSelected: false,
+ isInputHidden: false,
+ isOutputHidden: false,
+ showAddPara: false,
+ isVizualisation: vizParams.isViz,
+ vizObjectInput: vizParams.VizObject,
+ id: index + 1,
+ inp: inputParam,
+ lang: 'text/x-' + codeLanguage,
+ editorLanguage: codeLanguage,
+ typeOut: message.outputType,
+ out: message.outputData,
+ };
+ parsedPara.push(tempPara);
+ });
+ return parsedPara;
+ } catch (error) {
+ throw new Error('Parsing Paragraph Issue ' + error);
+ }
+};
diff --git a/public/components/notebooks/components/main.tsx b/public/components/notebooks/components/main.tsx
new file mode 100644
index 0000000000..9ba18c8e7b
--- /dev/null
+++ b/public/components/notebooks/components/main.tsx
@@ -0,0 +1,354 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable no-console */
+
+import { EuiGlobalToastList, EuiLink } from '@elastic/eui';
+import { Toast } from '@elastic/eui/src/components/toast/global_toast_list';
+import React, { ReactChild } from 'react';
+// eslint-disable-next-line @osd/eslint/module_migration
+import { Route, Switch } from 'react-router';
+import { HashRouter, RouteComponentProps } from 'react-router-dom';
+import PPLService from '../../../services/requests/ppl';
+import { ChromeBreadcrumb, CoreStart } from '../../../../../../src/core/public';
+import { DashboardStart } from '../../../../../../src/plugins/dashboard/public';
+import {
+ NOTEBOOKS_API_PREFIX,
+ NOTEBOOKS_DOCUMENTATION_URL,
+} from '../../../../common/constants/notebooks';
+import { ObservabilitySideBar } from '../../common/side_nav';
+import { Notebook } from './notebook';
+import { NoteTable } from './note_table';
+
+/*
+ * "Main" component renders the whole Notebooks as a single page application
+ *
+ * Props taken in as params are:
+ * DashboardContainerByValueRenderer: Dashboard container renderer for visualization
+ * http object: for making API requests
+ *
+ * Cell component of nteract used as a container for paragraphs in notebook UI.
+ * https://components.nteract.io/#cell
+ */
+
+type MainProps = RouteComponentProps & {
+ DashboardContainerByValueRenderer: DashboardStart['DashboardContainerByValueRenderer'];
+ http: CoreStart['http'];
+ pplService: PPLService;
+ notifications: CoreStart['notifications'];
+ parentBreadcrumb: ChromeBreadcrumb;
+ setBreadcrumbs: (newBreadcrumbs: ChromeBreadcrumb[]) => void;
+};
+
+interface MainState {
+ data: NotebookType[];
+ openedNotebook: NotebookType | undefined;
+ toasts: Toast[];
+ loading: boolean;
+}
+
+export interface NotebookType {
+ path: string;
+ id: string;
+ dateCreated: string;
+ dateModified: string;
+}
+
+export class Main extends React.Component {
+ constructor(props: Readonly) {
+ super(props);
+ this.state = {
+ data: [],
+ openedNotebook: undefined,
+ toasts: [],
+ loading: false,
+ };
+ }
+
+ setToast = (title: string, color = 'success', text?: ReactChild) => {
+ if (!text) text = '';
+ this.setState((prevState) => ({
+ toasts: [
+ ...prevState.toasts,
+ {
+ id: new Date().toISOString(),
+ title,
+ text,
+ color,
+ } as Toast,
+ ],
+ }));
+ };
+
+ // Fetches path and id for all stored notebooks
+ fetchNotebooks = () => {
+ return this.props.http
+ .get(`${NOTEBOOKS_API_PREFIX}/`)
+ .then((res) => this.setState(res))
+ .catch((err) => {
+ console.error('Issue in fetching the notebooks', err.body.message);
+ });
+ };
+
+ // Creates a new notebook
+ createNotebook = (newNoteName: string) => {
+ if (newNoteName.length >= 50 || newNoteName.length === 0) {
+ this.setToast('Invalid notebook name', 'danger');
+ return;
+ }
+ const newNoteObject = {
+ name: newNoteName,
+ };
+
+ return this.props.http
+ .post(`${NOTEBOOKS_API_PREFIX}/note`, {
+ body: JSON.stringify(newNoteObject),
+ })
+ .then(async (res) => {
+ this.setToast(`Notebook "${newNoteName}" successfully created!`);
+ window.location.assign(`#/notebooks/${res}`);
+ })
+ .catch((err) => {
+ this.setToast(
+ 'Please ask your administrator to enable Notebooks for you.',
+ 'danger',
+
+ Documentation
+
+ );
+ console.error(err);
+ });
+ };
+
+ // Renames an existing notebook
+ renameNotebook = (editedNoteName: string, editedNoteID: string) => {
+ if (editedNoteName.length >= 50 || editedNoteName.length === 0) {
+ this.setToast('Invalid notebook name', 'danger');
+ return;
+ }
+ const renameNoteObject = {
+ name: editedNoteName,
+ noteId: editedNoteID,
+ };
+
+ return this.props.http
+ .put(`${NOTEBOOKS_API_PREFIX}/note/rename`, {
+ body: JSON.stringify(renameNoteObject),
+ })
+ .then((res) => {
+ this.setState((prevState) => {
+ const newData = [...prevState.data];
+ const renamedNotebook = newData.find((notebook) => notebook.id === editedNoteID);
+ if (renamedNotebook) renamedNotebook.path = editedNoteName;
+ return { data: newData };
+ });
+ this.setToast(`Notebook successfully renamed into "${editedNoteName}"`);
+ })
+ .catch((err) => {
+ this.setToast(
+ 'Error renaming notebook, please make sure you have the correct permission.',
+ 'danger'
+ );
+ console.error(err.body.message);
+ });
+ };
+
+ // Clones an existing notebook, return new notebook's id
+ cloneNotebook = (clonedNoteName: string, clonedNoteID: string): Promise => {
+ if (clonedNoteName.length >= 50 || clonedNoteName.length === 0) {
+ this.setToast('Invalid notebook name', 'danger');
+ return Promise.reject();
+ }
+ const cloneNoteObject = {
+ name: clonedNoteName,
+ noteId: clonedNoteID,
+ };
+
+ return this.props.http
+ .post(`${NOTEBOOKS_API_PREFIX}/note/clone`, {
+ body: JSON.stringify(cloneNoteObject),
+ })
+ .then((res) => {
+ this.setState((prevState) => ({
+ data: [
+ ...prevState.data,
+ {
+ path: clonedNoteName,
+ id: res.body.id,
+ dateCreated: res.body.dateCreated,
+ dateModified: res.body.dateModified,
+ },
+ ],
+ }));
+ this.setToast(`Notebook "${clonedNoteName}" successfully created!`);
+ return res.body.id;
+ })
+ .catch((err) => {
+ this.setToast(
+ 'Error cloning notebook, please make sure you have the correct permission.',
+ 'danger'
+ );
+ console.error(err.body.message);
+ });
+ };
+
+ // Deletes existing notebooks
+ deleteNotebook = (notebookList: string[], toastMessage?: string) => {
+ return this.props.http
+ .delete(`${NOTEBOOKS_API_PREFIX}/note/${notebookList.join(',')}`)
+ .then((res) => {
+ this.setState((prevState) => ({
+ data: prevState.data.filter((notebook) => !notebookList.includes(notebook.id)),
+ }));
+ const message =
+ toastMessage || `Notebook${notebookList.length > 1 ? 's' : ''} successfully deleted!`;
+ this.setToast(message);
+ return res;
+ })
+ .catch((err) => {
+ this.setToast(
+ 'Error deleting notebook, please make sure you have the correct permission.',
+ 'danger'
+ );
+ console.error(err.body.message);
+ });
+ };
+
+ addSampleNotebooks = async () => {
+ try {
+ this.setState({ loading: true });
+ const flights = await this.props.http
+ .get('../api/saved_objects/_find', {
+ query: {
+ type: 'index-pattern',
+ search_fields: 'title',
+ search: 'opensearch_dashboards_sample_data_flights',
+ },
+ })
+ .then((resp) => resp.total === 0);
+ const logs = await this.props.http
+ .get('../api/saved_objects/_find', {
+ query: {
+ type: 'index-pattern',
+ search_fields: 'title',
+ search: 'opensearch_dashboards_sample_data_logs',
+ },
+ })
+ .then((resp) => resp.total === 0);
+ if (flights || logs) this.setToast('Adding sample data. This can take some time.');
+ await Promise.all([
+ flights ? this.props.http.post('../api/sample_data/flights') : Promise.resolve(),
+ logs ? this.props.http.post('../api/sample_data/logs') : Promise.resolve(),
+ ]);
+ const visIds: string[] = [];
+ await this.props.http
+ .get('../api/saved_objects/_find', {
+ query: {
+ type: 'visualization',
+ search_fields: 'title',
+ search: '[Logs] Response Codes Over Time + Annotations',
+ },
+ })
+ .then((resp) => visIds.push(resp.saved_objects[0].id));
+ await this.props.http
+ .get('../api/saved_objects/_find', {
+ query: {
+ type: 'visualization',
+ search_fields: 'title',
+ search: '[Logs] Unique Visitors vs. Average Bytes',
+ },
+ })
+ .then((resp) => visIds.push(resp.saved_objects[0].id));
+ await this.props.http
+ .get('../api/saved_objects/_find', {
+ query: {
+ type: 'visualization',
+ search_fields: 'title',
+ search: '[Flights] Flight Count and Average Ticket Price',
+ },
+ })
+ .then((resp) => visIds.push(resp.saved_objects[0].id));
+ await this.props.http
+ .post(`${NOTEBOOKS_API_PREFIX}/note/addSampleNotebooks`, {
+ body: JSON.stringify({ visIds }),
+ })
+ .then((res) => {
+ const newData = res.body.map((notebook: any) => ({
+ path: notebook.name,
+ id: notebook.id,
+ dateCreated: notebook.dateCreated,
+ dateModified: notebook.dateModified,
+ }));
+ this.setState((prevState) => ({
+ data: [...prevState.data, ...newData],
+ }));
+ });
+ this.setToast(`Sample notebooks successfully added.`);
+ } catch (err: any) {
+ this.setToast('Error adding sample notebooks.', 'danger');
+ console.error(err.body.message);
+ } finally {
+ this.setState({ loading: false });
+ }
+ };
+
+ render() {
+ return (
+
+ <>
+ {
+ this.setState({
+ toasts: this.state.toasts.filter((toast) => toast.id !== removedToast.id),
+ });
+ }}
+ toastLifeTimeMs={6000}
+ />
+
+ (
+
+ )}
+ />
+ (
+
+
+
+ )}
+ />
+
+ >
+
+ );
+ }
+}
diff --git a/public/components/notebooks/components/note_table.tsx b/public/components/notebooks/components/note_table.tsx
new file mode 100644
index 0000000000..d7ba77625f
--- /dev/null
+++ b/public/components/notebooks/components/note_table.tsx
@@ -0,0 +1,393 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ EuiButton,
+ EuiContextMenuItem,
+ EuiContextMenuPanel,
+ EuiFieldSearch,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiHorizontalRule,
+ EuiInMemoryTable,
+ EuiLink,
+ EuiOverlayMask,
+ EuiPage,
+ EuiPageBody,
+ EuiPageContent,
+ EuiPageContentHeader,
+ EuiPageContentHeaderSection,
+ EuiPageHeader,
+ EuiPageHeaderSection,
+ EuiPopover,
+ EuiSpacer,
+ EuiTableFieldDataColumnType,
+ EuiText,
+ EuiTitle,
+} from '@elastic/eui';
+import _ from 'lodash';
+import moment from 'moment';
+import React, { ReactElement, useEffect, useState } from 'react';
+import { ChromeBreadcrumb } from '../../../../../../src/core/public';
+import {
+ CREATE_NOTE_MESSAGE,
+ NOTEBOOKS_DOCUMENTATION_URL,
+} from '../../../../common/constants/notebooks';
+import { UI_DATE_FORMAT } from '../../../../common/constants/shared';
+import {
+ DeleteNotebookModal,
+ getCustomModal,
+ getSampleNotebooksModal,
+} from './helpers/modal_containers';
+import { NotebookType } from './main';
+import { pageStyles } from '../../../../common/constants/shared';
+
+interface NoteTableProps {
+ loading: boolean;
+ fetchNotebooks: () => void;
+ addSampleNotebooks: () => void;
+ notebooks: NotebookType[];
+ createNotebook: (newNoteName: string) => void;
+ renameNotebook: (newNoteName: string, noteId: string) => void;
+ cloneNotebook: (newNoteName: string, noteId: string) => void;
+ deleteNotebook: (noteList: string[], toastMessage?: string) => void;
+ parentBreadcrumb: ChromeBreadcrumb;
+ setBreadcrumbs: (newBreadcrumbs: ChromeBreadcrumb[]) => void;
+ setToast: (title: string, color?: string, text?: string) => void;
+}
+
+export function NoteTable(props: NoteTableProps) {
+ const [isModalVisible, setIsModalVisible] = useState(false); // Modal Toggle
+ const [modalLayout, setModalLayout] = useState( ); // Modal Layout
+ const [isActionsPopoverOpen, setIsActionsPopoverOpen] = useState(false);
+ const [selectedNotebooks, setSelectedNotebooks] = useState([]);
+ const [searchQuery, setSearchQuery] = useState('');
+ const { notebooks, createNotebook, renameNotebook, cloneNotebook, deleteNotebook } = props;
+
+ useEffect(() => {
+ props.setBreadcrumbs([
+ props.parentBreadcrumb,
+ {
+ text: 'Notebooks',
+ href: '#/notebooks',
+ },
+ ]);
+ props.fetchNotebooks();
+ }, []);
+
+ const closeModal = () => {
+ setIsModalVisible(false);
+ };
+ const showModal = () => {
+ setIsModalVisible(true);
+ };
+
+ const onCreate = async (newNoteName: string) => {
+ createNotebook(newNoteName);
+ closeModal();
+ };
+
+ const onRename = async (newNoteName: string) => {
+ renameNotebook(newNoteName, selectedNotebooks[0].id);
+ closeModal();
+ };
+
+ const onClone = async (newName: string) => {
+ cloneNotebook(newName, selectedNotebooks[0].id);
+ closeModal();
+ };
+
+ const onDelete = async () => {
+ const toastMessage = `Notebook${
+ selectedNotebooks.length > 1 ? 's' : ' "' + selectedNotebooks[0].path + '"'
+ } successfully deleted!`;
+ await deleteNotebook(
+ selectedNotebooks.map((note) => note.id),
+ toastMessage
+ );
+ closeModal();
+ };
+
+ const createNote = () => {
+ setModalLayout(
+ getCustomModal(
+ onCreate,
+ closeModal,
+ 'Name',
+ 'Create notebook',
+ 'Cancel',
+ 'Create',
+ undefined,
+ CREATE_NOTE_MESSAGE
+ )
+ );
+ showModal();
+ };
+
+ const renameNote = () => {
+ setModalLayout(
+ getCustomModal(
+ onRename,
+ closeModal,
+ 'Name',
+ 'Rename notebook',
+ 'Cancel',
+ 'Rename',
+ selectedNotebooks[0].path,
+ CREATE_NOTE_MESSAGE
+ )
+ );
+ showModal();
+ };
+
+ const cloneNote = () => {
+ setModalLayout(
+ getCustomModal(
+ onClone,
+ closeModal,
+ 'Name',
+ 'Duplicate notebook',
+ 'Cancel',
+ 'Duplicate',
+ selectedNotebooks[0].path + ' (copy)',
+ CREATE_NOTE_MESSAGE
+ )
+ );
+ showModal();
+ };
+
+ const deleteNote = () => {
+ const notebookString = `notebook${selectedNotebooks.length > 1 ? 's' : ''}`;
+ setModalLayout(
+
+ );
+ showModal();
+ };
+
+ const addSampleNotebooks = async () => {
+ setModalLayout(
+ getSampleNotebooksModal(closeModal, async () => {
+ closeModal();
+ await props.addSampleNotebooks();
+ })
+ );
+ showModal();
+ };
+
+ const popoverButton = (
+ setIsActionsPopoverOpen(!isActionsPopoverOpen)}
+ >
+ Actions
+
+ );
+
+ const popoverItems: ReactElement[] = [
+ {
+ setIsActionsPopoverOpen(false);
+ renameNote();
+ }}
+ >
+ Rename
+ ,
+ {
+ setIsActionsPopoverOpen(false);
+ cloneNote();
+ }}
+ >
+ Duplicate
+ ,
+ {
+ setIsActionsPopoverOpen(false);
+ deleteNote();
+ }}
+ >
+ Delete
+ ,
+ {
+ setIsActionsPopoverOpen(false);
+ addSampleNotebooks();
+ }}
+ >
+ Add samples
+ ,
+ ];
+
+ const tableColumns = [
+ {
+ field: 'path',
+ name: 'Name',
+ sortable: true,
+ truncateText: true,
+ render: (value, record) => (
+ {_.truncate(value, { length: 100 })}
+ ),
+ },
+ {
+ field: 'dateModified',
+ name: 'Last updated',
+ sortable: true,
+ render: (value) => moment(value).format(UI_DATE_FORMAT),
+ },
+ {
+ field: 'dateCreated',
+ name: 'Created',
+ sortable: true,
+ render: (value) => moment(value).format(UI_DATE_FORMAT),
+ },
+ ] as Array<
+ EuiTableFieldDataColumnType<{
+ path: string;
+ id: string;
+ dateCreated: string;
+ dateModified: string;
+ }>
+ >;
+
+ return (
+
+
+
+
+
+
+ Notebooks
+
+
+
+
+
+
+
+
+ Notebooks ({notebooks.length})
+
+
+
+
+ Use Notebooks to interactively and collaboratively develop rich reports backed by
+ live data. Common use cases for notebooks includes creating postmortem reports,
+ designing run books, building live infrastructure reports, or even documentation.{' '}
+
+ Learn more
+
+
+
+
+
+
+ setIsActionsPopoverOpen(false)}
+ >
+
+
+
+
+ createNote()}>
+ Create notebook
+
+
+
+
+
+
+ {notebooks.length > 0 ? (
+ <>
+ setSearchQuery(e.target.value)}
+ />
+
+
+ notebook.path.toLowerCase().includes(searchQuery.toLowerCase())
+ )
+ : notebooks
+ }
+ itemId="id"
+ columns={tableColumns}
+ tableLayout="auto"
+ pagination={{
+ initialPageSize: 10,
+ pageSizeOptions: [8, 10, 13],
+ }}
+ sorting={{
+ sort: {
+ field: 'dateModified',
+ direction: 'desc',
+ },
+ }}
+ allowNeutralSort={false}
+ isSelectable={true}
+ selection={{
+ onSelectionChange: (items) => setSelectedNotebooks(items),
+ }}
+ />
+ >
+ ) : (
+ <>
+
+
+ No notebooks
+
+
+ Use notebooks to create post-mortem reports, build live infrastructure
+
+ reports, or foster explorative collaborations with data.
+
+
+
+
+
+ createNote()}
+ >
+ Create notebook
+
+
+
+ addSampleNotebooks()}>
+ Add samples
+
+
+
+
+ >
+ )}
+
+
+
+ {isModalVisible && modalLayout}
+
+ );
+}
diff --git a/public/components/notebooks/components/notebook.tsx b/public/components/notebooks/components/notebook.tsx
new file mode 100644
index 0000000000..b97ab17234
--- /dev/null
+++ b/public/components/notebooks/components/notebook.tsx
@@ -0,0 +1,1113 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ EuiButton,
+ EuiButtonGroup,
+ EuiButtonGroupOption,
+ EuiCard,
+ EuiContextMenu,
+ EuiContextMenuPanelDescriptor,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiIcon,
+ EuiOverlayMask,
+ EuiPage,
+ EuiPageBody,
+ EuiPanel,
+ EuiPopover,
+ EuiSpacer,
+ EuiText,
+ EuiTitle,
+} from '@elastic/eui';
+import CSS from 'csstype';
+import moment from 'moment';
+import PPLService from '../../../services/requests/ppl';
+import queryString from 'query-string';
+import React, { Component } from 'react';
+import { RouteComponentProps } from 'react-router-dom';
+import { ChromeBreadcrumb, CoreStart } from '../../../../../../src/core/public';
+import { DashboardStart } from '../../../../../../src/plugins/dashboard/public';
+import {
+ CREATE_NOTE_MESSAGE,
+ NOTEBOOKS_API_PREFIX,
+ NOTEBOOKS_SELECTED_BACKEND,
+} from '../../../../common/constants/notebooks';
+import { UI_DATE_FORMAT } from '../../../../common/constants/shared';
+import { ParaType } from '../../../../common/types/notebooks';
+import { GenerateReportLoadingModal } from './helpers/custom_modals/reporting_loading_modal';
+import { defaultParagraphParser } from './helpers/default_parser';
+import { DeleteNotebookModal, getCustomModal, getDeleteModal } from './helpers/modal_containers';
+import {
+ contextMenuCreateReportDefinition,
+ contextMenuViewReports,
+ generateInContextReport,
+} from './helpers/reporting_context_menu_helper';
+import { zeppelinParagraphParser } from './helpers/zeppelin_parser';
+import { Paragraphs } from './paragraph_components/paragraphs';
+const panelStyles: CSS.Properties = {
+ float: 'left',
+ width: '100%',
+ maxWidth: '1130px',
+ marginTop: '20px',
+};
+
+const pageStyles: CSS.Properties = {
+ float: 'left',
+ width: '100%',
+ maxWidth: '1500px',
+};
+
+/*
+ * "Notebook" component is used to display an open notebook
+ *
+ * Props taken in as params are:
+ * DashboardContainerByValueRenderer - Dashboard container renderer for visualization
+ * http object - for making API requests
+ * setBreadcrumbs - sets breadcrumbs on top
+ */
+type NotebookProps = {
+ pplService: PPLService;
+ openedNoteId: string;
+ DashboardContainerByValueRenderer: DashboardStart['DashboardContainerByValueRenderer'];
+ http: CoreStart['http'];
+ parentBreadcrumb: ChromeBreadcrumb;
+ setBreadcrumbs: (newBreadcrumbs: ChromeBreadcrumb[]) => void;
+ renameNotebook: (newNoteName: string, noteId: string) => void;
+ cloneNotebook: (newNoteName: string, noteId: string) => Promise;
+ deleteNotebook: (noteList: string[], toastMessage?: string) => void;
+ setToast: (title: string, color?: string, text?: string) => void;
+ location: RouteComponentProps['location'];
+ history: RouteComponentProps['history'];
+};
+
+type NotebookState = {
+ selectedViewId: string;
+ path: string;
+ dateCreated: string;
+ dateModified: string;
+ paragraphs: any; // notebook paragraphs fetched from API
+ parsedPara: Array; // paragraphs parsed to a common format
+ vizPrefix: string; // prefix for visualizations in Zeppelin Adaptor
+ isAddParaPopoverOpen: boolean;
+ isParaActionsPopoverOpen: boolean;
+ isNoteActionsPopoverOpen: boolean;
+ isReportingPluginInstalled: boolean;
+ isReportingActionsPopoverOpen: boolean;
+ isReportingLoadingModalOpen: boolean;
+ isModalVisible: boolean;
+ modalLayout: React.ReactNode;
+ showQueryParagraphError: boolean;
+ queryParagraphErrorMessage: string;
+};
+export class Notebook extends Component {
+ constructor(props: Readonly) {
+ super(props);
+ this.state = {
+ selectedViewId: 'view_both',
+ path: '',
+ dateCreated: '',
+ dateModified: '',
+ paragraphs: [],
+ parsedPara: [],
+ vizPrefix: '',
+ isAddParaPopoverOpen: false,
+ isParaActionsPopoverOpen: false,
+ isNoteActionsPopoverOpen: false,
+ isReportingPluginInstalled: false,
+ isReportingActionsPopoverOpen: false,
+ isReportingLoadingModalOpen: false,
+ isModalVisible: false,
+ modalLayout: ,
+ showQueryParagraphError: false,
+ queryParagraphErrorMessage: '',
+ };
+ }
+
+ toggleReportingLoadingModal = (show: boolean) => {
+ this.setState({ isReportingLoadingModalOpen: show });
+ };
+
+ parseAllParagraphs = () => {
+ let parsedPara = this.parseParagraphs(this.state.paragraphs);
+ this.setState({ parsedPara });
+ };
+
+ // parse paragraphs based on backend
+ parseParagraphs = (paragraphs: any[]): ParaType[] => {
+ try {
+ let parsedPara;
+ // @ts-ignore
+ if (NOTEBOOKS_SELECTED_BACKEND === 'ZEPPELIN') {
+ parsedPara = zeppelinParagraphParser(paragraphs);
+ this.setState({ vizPrefix: '%sh #vizobject:' });
+ } else {
+ parsedPara = defaultParagraphParser(paragraphs);
+ }
+ parsedPara.forEach((para: ParaType) => {
+ para.isInputExpanded = this.state.selectedViewId === 'input_only';
+ para.paraRef = React.createRef();
+ para.paraDivRef = React.createRef();
+ });
+ return parsedPara;
+ } catch (err) {
+ this.props.setToast(
+ 'Error parsing paragraphs, please make sure you have the correct permission.',
+ 'danger'
+ );
+ console.error(err);
+ this.setState({ parsedPara: [] });
+ return [];
+ }
+ };
+
+ // Assigns Loading, Running & inQueue for paragraphs in current notebook
+ showParagraphRunning = (param: number | string) => {
+ let parsedPara = this.state.parsedPara;
+ this.state.parsedPara.map((_: ParaType, index: number) => {
+ if (param === 'queue') {
+ parsedPara[index].inQueue = true;
+ parsedPara[index].isOutputHidden = true;
+ } else if (param === 'loading') {
+ parsedPara[index].isRunning = true;
+ parsedPara[index].isOutputHidden = true;
+ } else if (param === index) {
+ parsedPara[index].isRunning = true;
+ parsedPara[index].isOutputHidden = true;
+ }
+ });
+ this.setState({ parsedPara });
+ };
+
+ // Sets a paragraph to selected and deselects all others
+ paragraphSelector = (index: number) => {
+ let parsedPara = this.state.parsedPara;
+ this.state.parsedPara.map((_: ParaType, idx: number) => {
+ if (index === idx) parsedPara[idx].isSelected = true;
+ else parsedPara[idx].isSelected = false;
+ });
+ this.setState({ parsedPara });
+ };
+
+ // Function for delete a Notebook button
+ deleteParagraphButton = (para: ParaType, index: number) => {
+ if (index !== -1) {
+ return this.props.http
+ .delete(`${NOTEBOOKS_API_PREFIX}/paragraph`, {
+ query: {
+ noteId: this.props.openedNoteId,
+ paragraphId: para.uniqueId,
+ },
+ })
+ .then((res) => {
+ const paragraphs = [...this.state.paragraphs];
+ paragraphs.splice(index, 1);
+ const parsedPara = [...this.state.parsedPara];
+ parsedPara.splice(index, 1);
+ this.setState({ paragraphs, parsedPara });
+ })
+ .catch((err) => {
+ this.props.setToast(
+ 'Error deleting paragraph, please make sure you have the correct permission.',
+ 'danger'
+ );
+ console.error(err.body.message);
+ });
+ }
+ };
+
+ showDeleteParaModal = (para: ParaType, index: number) => {
+ this.setState({
+ modalLayout: getDeleteModal(
+ () => this.setState({ isModalVisible: false }),
+ () => {
+ this.deleteParagraphButton(para, index);
+ this.setState({ isModalVisible: false });
+ },
+ 'Delete paragraph',
+ 'Are you sure you want to delete the paragraph? The action cannot be undone.'
+ ),
+ });
+ this.setState({ isModalVisible: true });
+ };
+
+ showDeleteAllParaModal = () => {
+ this.setState({
+ modalLayout: getDeleteModal(
+ () => this.setState({ isModalVisible: false }),
+ async () => {
+ this.setState({ isModalVisible: false });
+ await this.props.http
+ .delete(`${NOTEBOOKS_API_PREFIX}/paragraph`, {
+ query: {
+ noteId: this.props.openedNoteId,
+ },
+ })
+ .then((res) => {
+ this.setState({ paragraphs: res.paragraphs });
+ this.parseAllParagraphs();
+ this.props.setToast('Paragraphs successfully deleted!');
+ })
+ .catch((err) => {
+ this.props.setToast(
+ 'Error deleting paragraph, please make sure you have the correct permission.',
+ 'danger'
+ );
+ console.error(err.body.message);
+ });
+ },
+ 'Delete all paragraphs',
+ 'Are you sure you want to delete all paragraphs? The action cannot be undone.'
+ ),
+ });
+ this.setState({ isModalVisible: true });
+ };
+
+ showClearOutputsModal = () => {
+ this.setState({
+ modalLayout: getDeleteModal(
+ () => this.setState({ isModalVisible: false }),
+ () => {
+ this.clearParagraphButton();
+ this.setState({ isModalVisible: false });
+ },
+ 'Clear all outputs',
+ 'Are you sure you want to clear all outputs? The action cannot be undone.',
+ 'Clear'
+ ),
+ });
+ this.setState({ isModalVisible: true });
+ };
+
+ showRenameModal = () => {
+ this.setState({
+ modalLayout: getCustomModal(
+ (newName: string) => {
+ this.props.renameNotebook(newName, this.props.openedNoteId);
+ this.setState({ isModalVisible: false });
+ this.loadNotebook();
+ },
+ () => this.setState({ isModalVisible: false }),
+ 'Name',
+ 'Rename notebook',
+ 'Cancel',
+ 'Rename',
+ this.state.path,
+ CREATE_NOTE_MESSAGE
+ ),
+ });
+ this.setState({ isModalVisible: true });
+ };
+
+ showCloneModal = () => {
+ this.setState({
+ modalLayout: getCustomModal(
+ (newName: string) => {
+ this.props.cloneNotebook(newName, this.props.openedNoteId).then((id: string) => {
+ window.location.assign(`#/notebooks/${id}`);
+ setTimeout(() => {
+ this.loadNotebook();
+ }, 300);
+ });
+ this.setState({ isModalVisible: false });
+ },
+ () => this.setState({ isModalVisible: false }),
+ 'Name',
+ 'Duplicate notebook',
+ 'Cancel',
+ 'Duplicate',
+ this.state.path + ' (copy)',
+ CREATE_NOTE_MESSAGE
+ ),
+ });
+ this.setState({ isModalVisible: true });
+ };
+
+ showDeleteNotebookModal = () => {
+ this.setState({
+ modalLayout: (
+ {
+ const toastMessage = `Notebook "${this.state.path}" successfully deleted!`;
+ await this.props.deleteNotebook([this.props.openedNoteId], toastMessage);
+ this.setState({ isModalVisible: false }, () =>
+ setTimeout(() => {
+ this.props.history.push('.');
+ }, 1000)
+ );
+ }}
+ onCancel={() => this.setState({ isModalVisible: false })}
+ title={`Delete notebook "${this.state.path}"`}
+ message="Delete notebook will remove all contents in the paragraphs."
+ />
+ ),
+ });
+ this.setState({ isModalVisible: true });
+ };
+
+ // Function for delete Visualization from notebook
+ deleteVizualization = (uniqueId: string) => {
+ this.props.http
+ .delete(`${NOTEBOOKS_API_PREFIX}/paragraph/` + this.props.openedNoteId + '/' + uniqueId)
+ .then((res) => {
+ this.setState({ paragraphs: res.paragraphs });
+ this.parseAllParagraphs();
+ })
+ .catch((err) => {
+ this.props.setToast(
+ 'Error deleting visualization, please make sure you have the correct permission.',
+ 'danger'
+ );
+ console.error(err.body.message);
+ });
+ };
+
+ // Backend call to add a paragraph, switch to "view both" if in output only view
+ addPara = (index: number, newParaContent: string, inpType: string) => {
+ const addParaObj = {
+ noteId: this.props.openedNoteId,
+ paragraphIndex: index,
+ paragraphInput: newParaContent,
+ inputType: inpType,
+ };
+
+ return this.props.http
+ .post(`${NOTEBOOKS_API_PREFIX}/paragraph/`, {
+ body: JSON.stringify(addParaObj),
+ })
+ .then((res) => {
+ const paragraphs = [...this.state.paragraphs];
+ paragraphs.splice(index, 0, res);
+ const newPara = this.parseParagraphs([res])[0];
+ newPara.isInputExpanded = true;
+ const parsedPara = [...this.state.parsedPara];
+ parsedPara.splice(index, 0, newPara);
+
+ this.setState({ paragraphs, parsedPara });
+ this.paragraphSelector(index);
+ if (this.state.selectedViewId === 'output_only')
+ this.setState({ selectedViewId: 'view_both' });
+ })
+ .catch((err) => {
+ this.props.setToast(
+ 'Error adding paragraph, please make sure you have the correct permission.',
+ 'danger'
+ );
+ console.error(err.body.message);
+ });
+ };
+
+ // Function to clone a paragraph
+ cloneParaButton = (para: ParaType, index: number) => {
+ let inputType = 'CODE';
+ if (para.typeOut[0] === 'VISUALIZATION') {
+ inputType = 'VISUALIZATION';
+ }
+ if (para.typeOut[0] === 'OBSERVABILITY_VISUALIZATION') {
+ inputType = 'OBSERVABILITY_VISUALIZATION';
+ }
+ if (index !== -1) {
+ return this.addPara(index, para.inp, inputType);
+ }
+ };
+
+ // Function to move a paragraph
+ movePara = (index: number, targetIndex: number) => {
+ const paragraphs = [...this.state.paragraphs];
+ paragraphs.splice(targetIndex, 0, paragraphs.splice(index, 1)[0]);
+ const parsedPara = [...this.state.parsedPara];
+ parsedPara.splice(targetIndex, 0, parsedPara.splice(index, 1)[0]);
+
+ const moveParaObj = {
+ noteId: this.props.openedNoteId,
+ paragraphs,
+ };
+
+ return this.props.http
+ .post(`${NOTEBOOKS_API_PREFIX}/set_paragraphs/`, {
+ body: JSON.stringify(moveParaObj),
+ })
+ .then((res) => this.setState({ paragraphs, parsedPara }))
+ .then((res) => this.scrollToPara(targetIndex))
+ .catch((err) => {
+ this.props.setToast(
+ 'Error moving paragraphs, please make sure you have the correct permission.',
+ 'danger'
+ );
+ console.error(err.body.message);
+ });
+ };
+
+ scrollToPara(index: number) {
+ setTimeout(() => {
+ window.scrollTo({
+ left: 0,
+ top: this.state.parsedPara[index].paraDivRef.current?.offsetTop,
+ behavior: 'smooth',
+ });
+ }, 0);
+ }
+
+ // Function for clearing outputs button
+ clearParagraphButton = () => {
+ this.showParagraphRunning('loading');
+ const clearParaObj = {
+ noteId: this.props.openedNoteId,
+ };
+ this.props.http
+ .put(`${NOTEBOOKS_API_PREFIX}/paragraph/clearall/`, {
+ body: JSON.stringify(clearParaObj),
+ })
+ .then((res) => {
+ this.setState({ paragraphs: res.paragraphs });
+ this.parseAllParagraphs();
+ })
+ .catch((err) => {
+ this.props.setToast(
+ 'Error clearing paragraphs, please make sure you have the correct permission.',
+ 'danger'
+ );
+ console.error(err.body.message);
+ });
+ };
+
+ // Backend call to update and run contents of paragraph
+ updateRunParagraph = (
+ para: ParaType,
+ index: number,
+ vizObjectInput?: string,
+ paraType?: string
+ ) => {
+ this.showParagraphRunning(index);
+ if (vizObjectInput) {
+ para.inp = this.state.vizPrefix + vizObjectInput; // "%sh check"
+ }
+
+ const paraUpdateObject = {
+ noteId: this.props.openedNoteId,
+ paragraphId: para.uniqueId,
+ paragraphInput: para.inp,
+ paragraphType: paraType || '',
+ };
+
+ return this.props.http
+ .post(`${NOTEBOOKS_API_PREFIX}/paragraph/update/run/`, {
+ body: JSON.stringify(paraUpdateObject),
+ })
+ .then(async (res) => {
+ if (res.output[0]?.outputType === 'QUERY') {
+ await this.loadQueryResultsFromInput(res);
+ const checkErrorJSON = JSON.parse(res.output[0].result);
+ if (this.checkQueryOutputError(checkErrorJSON)) {
+ return;
+ }
+ }
+ const paragraphs = this.state.paragraphs;
+ paragraphs[index] = res;
+ const parsedPara = [...this.state.parsedPara];
+ parsedPara[index] = this.parseParagraphs([res])[0];
+ this.setState({ paragraphs, parsedPara });
+ })
+ .catch((err) => {
+ if (err.body.statusCode === 413)
+ this.props.setToast(`Error running paragraph: ${err.body.message}`, 'danger');
+ else
+ this.props.setToast(
+ 'Error running paragraph, please make sure you have the correct permission.',
+ 'danger'
+ );
+ console.error(err.body.message);
+ });
+ };
+
+ checkQueryOutputError = (checkErrorJSON: JSON) => {
+ // if query output has error output
+ if (checkErrorJSON.hasOwnProperty('error')) {
+ this.setState({
+ showQueryParagraphError: true,
+ queryParagraphErrorMessage: checkErrorJSON.error.reason,
+ });
+ return true;
+ }
+ // query ran successfully, reset error variables if currently set to true
+ else if (this.state.showQueryParagraphError) {
+ this.setState({
+ showQueryParagraphError: false,
+ queryParagraphErrorMessage: '',
+ });
+ return false;
+ }
+ };
+
+ runForAllParagraphs = (reducer: (para: ParaType, index: number) => Promise) => {
+ return this.state.parsedPara
+ .map((para: ParaType, index: number) => () => reducer(para, index))
+ .reduce((chain, func) => chain.then(func), Promise.resolve());
+ };
+
+ // Handles text editor value and syncs with paragraph input
+ textValueEditor = (evt: React.ChangeEvent, index: number) => {
+ if (!(evt.key === 'Enter' && evt.shiftKey)) {
+ let parsedPara = this.state.parsedPara;
+ parsedPara[index].inp = evt.target.value;
+ this.setState({ parsedPara });
+ }
+ };
+
+ // Handles run paragraph shortcut "Shift+Enter"
+ handleKeyPress = (evt: React.KeyboardEvent, para: ParaType, index: number) => {
+ if (evt.key === 'Enter' && evt.shiftKey) {
+ this.updateRunParagraph(para, index);
+ }
+ };
+
+ // update view mode, scrolls to paragraph and expands input if scrollToIndex is given
+ updateView = (selectedViewId: string, scrollToIndex?: number) => {
+ this.configureViewParameter(selectedViewId);
+ let parsedPara = [...this.state.parsedPara];
+ this.state.parsedPara.map((para: ParaType, index: number) => {
+ parsedPara[index].isInputExpanded = selectedViewId === 'input_only';
+ });
+
+ if (scrollToIndex !== undefined) {
+ parsedPara[scrollToIndex].isInputExpanded = true;
+ this.scrollToPara(scrollToIndex);
+ }
+ this.setState({ parsedPara, selectedViewId });
+ this.paragraphSelector(scrollToIndex !== undefined ? scrollToIndex : -1);
+ };
+
+ loadNotebook = () => {
+ this.showParagraphRunning('queue');
+ this.props.http
+ .get(`${NOTEBOOKS_API_PREFIX}/note/` + this.props.openedNoteId)
+ .then(async (res) => {
+ this.setBreadcrumbs(res.path);
+ let index = 0;
+ for (index = 0; index < res.paragraphs.length; ++index) {
+ // if the paragraph is a query, load the query output
+ if (res.paragraphs[index].output[0]?.outputType === 'QUERY') {
+ await this.loadQueryResultsFromInput(res.paragraphs[index]);
+ }
+ }
+ this.setState(res, this.parseAllParagraphs);
+ })
+ .catch((err) => {
+ this.props.setToast(
+ 'Error fetching notebooks, please make sure you have the correct permission.',
+ 'danger'
+ );
+ console.error(err?.body?.message || err);
+ });
+ };
+
+ loadQueryResultsFromInput = async (paragraph: any) => {
+ const queryType =
+ paragraph.input.inputText.substring(0, 4) === '%sql' ? 'sqlquery' : 'pplquery';
+ await this.props.http
+ .post(`/api/sql/${queryType}`, {
+ body: JSON.stringify(paragraph.output[0].result),
+ })
+ .then((response) => {
+ paragraph.output[0].result = response.data.resp;
+ return paragraph;
+ })
+ .catch((err) => {
+ this.props.setToast('Error getting query output', 'danger');
+ console.error(err);
+ });
+ };
+
+ setPara = (para: ParaType, index: number) => {
+ const parsedPara = [...this.state.parsedPara];
+ parsedPara.splice(index, 1, para);
+ this.setState({ parsedPara });
+ };
+
+ setBreadcrumbs(path: string) {
+ this.props.setBreadcrumbs([
+ this.props.parentBreadcrumb,
+ {
+ text: 'Notebooks',
+ href: '#/notebooks',
+ },
+ {
+ text: path,
+ href: `#/notebooks/${this.props.openedNoteId}`,
+ },
+ ]);
+ }
+
+ checkIfReportingPluginIsInstalled() {
+ fetch('../api/status', {
+ headers: {
+ 'Content-Type': 'application/json',
+ 'osd-xsrf': 'true',
+ 'accept-language': 'en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7,zh-TW;q=0.6',
+ pragma: 'no-cache',
+ 'sec-fetch-dest': 'empty',
+ 'sec-fetch-mode': 'cors',
+ 'sec-fetch-site': 'same-origin',
+ },
+ method: 'GET',
+ referrerPolicy: 'strict-origin-when-cross-origin',
+ mode: 'cors',
+ credentials: 'include',
+ })
+ .then(function (response) {
+ return response.json();
+ })
+ .then((data) => {
+ for (let i = 0; i < data.status.statuses.length; ++i) {
+ if (data.status.statuses[i].id.includes('plugin:reportsDashboards')) {
+ this.setState({ isReportingPluginInstalled: true });
+ }
+ }
+ })
+ .catch((error) => {
+ console.log('error is', error);
+ });
+ }
+
+ configureViewParameter(id: string) {
+ this.props.history.replace({
+ ...this.props.location,
+ search: `view=${id}`,
+ });
+ }
+
+ componentDidMount() {
+ this.setBreadcrumbs('');
+ this.loadNotebook();
+ this.checkIfReportingPluginIsInstalled();
+ const searchParams = queryString.parse(this.props.location.search);
+ const view = searchParams['view'];
+ if (!view) {
+ this.configureViewParameter('view_both');
+ }
+ if (view === 'output_only') {
+ this.setState({ selectedViewId: 'output_only' });
+ } else if (view === 'input_only') {
+ this.setState({ selectedViewId: 'input_only' });
+ }
+ }
+
+ render() {
+ const createdText = (
+
+
+ Created {moment(this.state.dateCreated).format(UI_DATE_FORMAT)}
+
+
+ );
+ const viewOptions: EuiButtonGroupOption[] = [
+ {
+ id: 'view_both',
+ label: 'View both',
+ },
+ {
+ id: 'input_only',
+ label: 'Input only',
+ },
+ {
+ id: 'output_only',
+ label: 'Output only',
+ },
+ ];
+ const addParaPanels: EuiContextMenuPanelDescriptor[] = [
+ {
+ id: 0,
+ title: 'Type',
+ items: [
+ {
+ name: 'Code block',
+ onClick: () => {
+ this.setState({ isAddParaPopoverOpen: false });
+ this.addPara(this.state.paragraphs.length, '', 'CODE');
+ },
+ },
+ {
+ name: 'Visualization',
+ onClick: () => {
+ this.setState({ isAddParaPopoverOpen: false });
+ this.addPara(this.state.paragraphs.length, '', 'VISUALIZATION');
+ },
+ },
+ ],
+ },
+ ];
+ const paraActionsPanels: EuiContextMenuPanelDescriptor[] = [
+ {
+ id: 0,
+ title: 'Actions',
+ items: [
+ {
+ name: 'Add paragraph to top',
+ panel: 1,
+ },
+ {
+ name: 'Add paragraph to bottom',
+ panel: 2,
+ },
+ {
+ name: 'Run all paragraphs',
+ disabled: this.state.parsedPara.length === 0,
+ onClick: () => {
+ this.setState({ isParaActionsPopoverOpen: false });
+ this.runForAllParagraphs((para: ParaType, index: number) => {
+ return para.paraRef.current?.runParagraph();
+ });
+ if (this.state.selectedViewId === 'input_only') {
+ this.updateView('view_both');
+ }
+ },
+ },
+ {
+ name: 'Clear all outputs',
+ disabled: this.state.parsedPara.length === 0,
+ onClick: () => {
+ this.setState({ isParaActionsPopoverOpen: false });
+ this.showClearOutputsModal();
+ },
+ },
+ {
+ name: 'Delete all paragraphs',
+ disabled: this.state.parsedPara.length === 0,
+ onClick: () => {
+ this.setState({ isParaActionsPopoverOpen: false });
+ this.showDeleteAllParaModal();
+ },
+ },
+ ],
+ },
+ {
+ id: 1,
+ title: 'Add to top',
+ items: [
+ {
+ name: 'Code block',
+ onClick: () => {
+ this.setState({ isParaActionsPopoverOpen: false });
+ this.addPara(0, '', 'CODE');
+ },
+ },
+ {
+ name: 'Visualization',
+ onClick: () => {
+ this.setState({ isParaActionsPopoverOpen: false });
+ this.addPara(0, '', 'VISUALIZATION');
+ },
+ },
+ ],
+ },
+ {
+ id: 2,
+ title: 'Add to bottom',
+ items: [
+ {
+ name: 'Code block',
+ onClick: () => {
+ this.setState({ isParaActionsPopoverOpen: false });
+ this.addPara(this.state.paragraphs.length, '', 'CODE');
+ },
+ },
+ {
+ name: 'Visualization',
+ onClick: () => {
+ this.setState({ isParaActionsPopoverOpen: false });
+ this.addPara(this.state.paragraphs.length, '', 'VISUALIZATION');
+ },
+ },
+ ],
+ },
+ ];
+ const noteActionsPanels: EuiContextMenuPanelDescriptor[] = [
+ {
+ id: 0,
+ title: 'Notebook actions',
+ items: [
+ {
+ name: 'Rename notebook',
+ onClick: () => {
+ this.setState({ isNoteActionsPopoverOpen: false });
+ this.showRenameModal();
+ },
+ },
+ {
+ name: 'Duplicate notebook',
+ onClick: () => {
+ this.setState({ isNoteActionsPopoverOpen: false });
+ this.showCloneModal();
+ },
+ },
+ {
+ name: 'Delete notebook',
+ onClick: () => {
+ this.setState({ isNoteActionsPopoverOpen: false });
+ this.showDeleteNotebookModal();
+ },
+ },
+ ],
+ },
+ ];
+
+ const reportingActionPanels: EuiContextMenuPanelDescriptor[] = [
+ {
+ id: 0,
+ title: 'Reporting',
+ items: [
+ {
+ name: 'Download PDF',
+ icon: ,
+ onClick: () => {
+ this.setState({ isReportingActionsPopoverOpen: false });
+ generateInContextReport('pdf', this.props, this.toggleReportingLoadingModal);
+ },
+ },
+ {
+ name: 'Download PNG',
+ icon: ,
+ onClick: () => {
+ this.setState({ isReportingActionsPopoverOpen: false });
+ generateInContextReport('png', this.props, this.toggleReportingLoadingModal);
+ },
+ },
+ {
+ name: 'Create report definition',
+ icon: ,
+ onClick: () => {
+ this.setState({ isReportingActionsPopoverOpen: false });
+ contextMenuCreateReportDefinition(window.location.href);
+ },
+ },
+ {
+ name: 'View reports',
+ icon: ,
+ onClick: () => {
+ this.setState({ isReportingActionsPopoverOpen: false });
+ contextMenuViewReports();
+ },
+ },
+ ],
+ },
+ ];
+
+ const showReportingContextMenu = this.state.isReportingPluginInstalled ? (
+
+ this.setState({ isReportingActionsPopoverOpen: true })}
+ >
+ Reporting actions
+
+ }
+ isOpen={this.state.isReportingActionsPopoverOpen}
+ closePopover={() => this.setState({ isReportingActionsPopoverOpen: false })}
+ >
+
+
+
+ ) : null;
+
+ const showLoadingModal = this.state.isReportingLoadingModalOpen ? (
+
+ ) : null;
+
+ return (
+
+
+
+
+
+ {this.state.parsedPara.length > 0 && (
+
+ {
+ this.updateView(id);
+ }}
+ />
+
+ )}
+
+
+
+ this.setState({ isParaActionsPopoverOpen: true })}
+ >
+ Paragraph actions
+
+ }
+ isOpen={this.state.isParaActionsPopoverOpen}
+ closePopover={() => this.setState({ isParaActionsPopoverOpen: false })}
+ >
+
+
+
+ {showReportingContextMenu}
+
+ this.setState({ isNoteActionsPopoverOpen: true })}
+ >
+ Notebook actions
+
+ }
+ isOpen={this.state.isNoteActionsPopoverOpen}
+ closePopover={() => this.setState({ isNoteActionsPopoverOpen: false })}
+ >
+
+
+
+
+
+
+ {this.state.path}
+
+
+
+
+ {createdText}
+
+
+ {this.state.parsedPara.length > 0 ? (
+ <>
+ {this.state.parsedPara.map((para: ParaType, index: number) => (
+
+
this.setPara(para, index)}
+ dateModified={this.state.paragraphs[index]?.dateModified}
+ index={index}
+ paraCount={this.state.parsedPara.length}
+ paragraphSelector={this.paragraphSelector}
+ textValueEditor={this.textValueEditor}
+ handleKeyPress={this.handleKeyPress}
+ addPara={this.addPara}
+ DashboardContainerByValueRenderer={
+ this.props.DashboardContainerByValueRenderer
+ }
+ deleteVizualization={this.deleteVizualization}
+ http={this.props.http}
+ selectedViewId={this.state.selectedViewId}
+ setSelectedViewId={this.updateView}
+ deletePara={this.showDeleteParaModal}
+ runPara={this.updateRunParagraph}
+ clonePara={this.cloneParaButton}
+ movePara={this.movePara}
+ showQueryParagraphError={this.state.showQueryParagraphError}
+ queryParagraphErrorMessage={this.state.queryParagraphErrorMessage}
+ />
+
+ ))}
+ {this.state.selectedViewId !== 'output_only' && (
+ <>
+
+ this.setState({ isAddParaPopoverOpen: true })}
+ >
+ Add paragraph
+
+ }
+ isOpen={this.state.isAddParaPopoverOpen}
+ closePopover={() => this.setState({ isAddParaPopoverOpen: false })}
+ >
+
+
+ >
+ )}
+ >
+ ) : (
+ // show default paragraph if no paragraphs in this notebook
+
+
+
+
+ No paragraphs
+
+ Add a paragraph to compose your document or story. Notebooks now support two
+ types of input:
+
+
+
+
+
+
+ }
+ title="Code block"
+ description="Write contents directly using markdown, SQL or PPL."
+ footer={
+ this.addPara(0, '', 'CODE')}
+ style={{ marginBottom: 17 }}
+ >
+ Add code block
+
+ }
+ />
+
+
+ }
+ title="Visualization"
+ description="Import OpenSearch Dashboards or Observability visualizations to the notes."
+ footer={
+ this.addPara(0, '', 'VISUALIZATION')}
+ style={{ marginBottom: 17 }}
+ >
+ Add visualization
+
+ }
+ />
+
+
+
+
+
+
+ )}
+ {showLoadingModal}
+
+
+ {this.state.isModalVisible && this.state.modalLayout}
+
+ );
+ }
+}
diff --git a/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/para_input.test.tsx.snap b/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/para_input.test.tsx.snap
new file mode 100644
index 0000000000..4f8523b7d6
--- /dev/null
+++ b/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/para_input.test.tsx.snap
@@ -0,0 +1,318 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` spec renders the markdown component 1`] = `
+
+
+
+
+
+
+ # Type your input here
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[` spec renders the visualization component 1`] = `
+
+
+
+
+
+
+
+
+ Browse
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/para_output.test.tsx.snap b/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/para_output.test.tsx.snap
new file mode 100644
index 0000000000..a4bc6e0ec7
--- /dev/null
+++ b/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/para_output.test.tsx.snap
@@ -0,0 +1,82 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` spec renders markdown outputs 1`] = `
+
+
+
+ Type your input here
+
+
+
+`;
+
+exports[` spec renders other types of outputs 1`] = `
+
+`;
+
+exports[` spec renders query outputs 1`] = `
+
+
+
+ select * from opensearch_dashboards_sample_data_flights limit 2
+
+
+
+
+
+`;
+
+exports[` spec renders visualization outputs 1`] = `
+
+ 2020-07-21T18:37:44+00:00 - 2020-08-20T18:37:44+00:00
+
+`;
diff --git a/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/para_query_grid.test.tsx.snap b/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/para_query_grid.test.tsx.snap
new file mode 100644
index 0000000000..4f60d0e6f2
--- /dev/null
+++ b/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/para_query_grid.test.tsx.snap
@@ -0,0 +1,37 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` spec renders the component 1`] = `
+
+`;
diff --git a/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/paragraphs.test.tsx.snap b/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/paragraphs.test.tsx.snap
new file mode 100644
index 0000000000..ab01c3c85c
--- /dev/null
+++ b/public/components/notebooks/components/paragraph_components/__tests__/__snapshots__/paragraphs.test.tsx.snap
@@ -0,0 +1,258 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` spec renders the component 1`] = `
+
+
+
+
+ [1] Code block
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Refresh
+
+
+
+
+
+
+
+
+
+
+
+ Last successful run Invalid date.
+
+
+
+
+
+
+
+
+
+
+ Type your input here
+
+
+
+
+
+
+`;
diff --git a/public/components/notebooks/components/paragraph_components/__tests__/para_input.test.tsx b/public/components/notebooks/components/paragraph_components/__tests__/para_input.test.tsx
new file mode 100644
index 0000000000..de07ab37d0
--- /dev/null
+++ b/public/components/notebooks/components/paragraph_components/__tests__/para_input.test.tsx
@@ -0,0 +1,160 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { fireEvent, render, waitFor } from '@testing-library/react';
+import { configure } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { sampleParsedParagraghs1 } from '../../helpers/__tests__/sampleDefaultNotebooks';
+import { ParaInput } from '../para_input';
+
+describe(' spec', () => {
+ configure({ adapter: new Adapter() });
+ const visOptions1 = Array.from({ length: 5 }, (v, k) => ({
+ label: `visualization-${k}`,
+ key: `key-${k}`,
+ }));
+ const visOptions2 = Array.from({ length: 5 }, (v, k) => ({
+ label: `visualization-${k}`,
+ key: `key-${k}`,
+ }));
+ const visOptions = [
+ { label: 'VisOptions1', options: visOptions1 },
+ { label: 'VisOptions2', options: visOptions2 },
+ ];
+
+ it('renders the markdown component', () => {
+ const para = sampleParsedParagraghs1[0];
+ const textValueEditor = jest.fn();
+ const handleKeyPress = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const setIsOutputStale = jest.fn();
+ const setSelectedVisOption = jest.fn();
+ const setVisType = jest.fn();
+ const utils = render(
+
+ );
+ expect(utils.container.firstChild).toMatchSnapshot();
+ });
+
+ it('renders the visualization component', () => {
+ const para = sampleParsedParagraghs1[2];
+ const textValueEditor = jest.fn();
+ const handleKeyPress = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const setIsOutputStale = jest.fn();
+ const setSelectedVisOption = jest.fn();
+ const setVisType = jest.fn();
+ const utils = render(
+
+ );
+ expect(utils.container.firstChild).toMatchSnapshot();
+ });
+
+ it('types in the markdown component', () => {
+ const para = sampleParsedParagraghs1[0];
+ para.isSelected = true;
+ const textValueEditor = jest.fn();
+ const handleKeyPress = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const setIsOutputStale = jest.fn();
+ const setSelectedVisOption = jest.fn();
+ const setVisType = jest.fn();
+ const utils = render(
+
+ );
+ const textarea = utils.container.querySelectorAll('textarea#editorArea')[0];
+ fireEvent.change(textarea, { target: { value: 'test input' } });
+ expect(setIsOutputStale).toBeCalledWith(true);
+ });
+
+ it('clicks the visualization component', async () => {
+ const para = sampleParsedParagraghs1[2];
+ para.isSelected = true;
+ const textValueEditor = jest.fn();
+ const handleKeyPress = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const setIsOutputStale = jest.fn();
+ const setSelectedVisOption = jest.fn();
+ const setVisType = jest.fn();
+ const utils = render(
+
+ );
+ const datepicker = utils.container.querySelectorAll(
+ 'button[data-test-subj="superDatePickerstartDatePopoverButton"]'
+ );
+ fireEvent.click(datepicker[0]);
+
+ utils.getByTestId('para-input-visualization-browse-button').click();
+ await waitFor(() => {
+ // modal should show up
+ utils.getByTestId('para-input-select-button').click();
+ });
+ });
+});
diff --git a/public/components/notebooks/components/paragraph_components/__tests__/para_output.test.tsx b/public/components/notebooks/components/paragraph_components/__tests__/para_output.test.tsx
new file mode 100644
index 0000000000..167daf25a2
--- /dev/null
+++ b/public/components/notebooks/components/paragraph_components/__tests__/para_output.test.tsx
@@ -0,0 +1,83 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { fireEvent, render } from '@testing-library/react';
+import { configure, mount, shallow } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { sampleParsedParagraghs1 } from '../../helpers/__tests__/sampleDefaultNotebooks';
+import { ParaOutput } from '../para_output';
+
+describe(' spec', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders markdown outputs', () => {
+ const para = sampleParsedParagraghs1[0];
+ para.isSelected = true;
+ const setVisInput = jest.fn();
+ const utils = render(
+
+ );
+ expect(utils.container.firstChild).toMatchSnapshot();
+ });
+
+ it('renders query outputs', () => {
+ const para = sampleParsedParagraghs1[3];
+ para.isSelected = true;
+ const setVisInput = jest.fn();
+ const utils = render(
+
+ );
+ expect(utils.container.firstChild).toMatchSnapshot();
+ });
+
+ it('renders visualization outputs', () => {
+ const para = sampleParsedParagraghs1[2];
+ para.isSelected = true;
+ const setVisInput = jest.fn();
+ const utils = render(
+ null}
+ />
+ );
+ expect(utils.container.firstChild).toMatchSnapshot();
+ });
+
+ it('renders other types of outputs', () => {
+ const para = sampleParsedParagraghs1[0];
+ para.isSelected = true;
+ para.typeOut = ['HTML', 'TABLE', 'IMG', 'UNKNOWN', undefined];
+ para.out = ['', '', '', '', ''];
+ const setVisInput = jest.fn();
+ const utils = render(
+
+ );
+ expect(utils.container.firstChild).toMatchSnapshot();
+ });
+});
diff --git a/public/components/notebooks/components/paragraph_components/__tests__/para_query_grid.test.tsx b/public/components/notebooks/components/paragraph_components/__tests__/para_query_grid.test.tsx
new file mode 100644
index 0000000000..6a59f8e6c4
--- /dev/null
+++ b/public/components/notebooks/components/paragraph_components/__tests__/para_query_grid.test.tsx
@@ -0,0 +1,46 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { render } from '@testing-library/react';
+import { configure } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { QueryDataGridMemo } from '../para_query_grid';
+
+describe(' spec', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders the component', () => {
+ const props = {
+ rowCount: 5,
+ queryColumns: [
+ {
+ id: 'bytes',
+ displayAsText: 'bytes',
+ },
+ ],
+ visibleColumns: ['bytes'],
+ dataValues: [
+ {
+ bytes: 6219,
+ },
+ {
+ bytes: 6850,
+ },
+ {
+ bytes: 0,
+ },
+ {
+ bytes: 14113,
+ },
+ {
+ bytes: 2492,
+ },
+ ],
+ };
+ const utils = render( );
+ expect(utils.container.firstChild).toMatchSnapshot();
+ });
+});
diff --git a/public/components/notebooks/components/paragraph_components/__tests__/paragraphs.test.tsx b/public/components/notebooks/components/paragraph_components/__tests__/paragraphs.test.tsx
new file mode 100644
index 0000000000..26a8e2c0a5
--- /dev/null
+++ b/public/components/notebooks/components/paragraph_components/__tests__/paragraphs.test.tsx
@@ -0,0 +1,73 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { fireEvent, render } from '@testing-library/react';
+import { configure, mount, shallow } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import httpClientMock from '../../../../../../test/__mocks__/httpClientMock';
+import { sampleParsedParagraghs1 } from '../../helpers/__tests__/sampleDefaultNotebooks';
+import { Paragraphs } from '../paragraphs';
+
+jest.mock('../../../../../../../../src/plugins/embeddable/public', () => ({
+ ViewMode: {
+ EDIT: 'edit',
+ VIEW: 'view',
+ },
+}));
+
+describe(' spec', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders the component', () => {
+ const setPara = jest.fn();
+ const paragraphSelector = jest.fn();
+ const textValueEditor = jest.fn();
+ const handleKeyPress = jest.fn();
+ const addPara = jest.fn();
+ const DashboardContainerByValueRenderer = jest.fn();
+ const deleteVizualization = jest.fn();
+ const setSelectedViewId = jest.fn();
+ const deletePara = jest.fn();
+ const runPara = jest.fn();
+ const clonePara = jest.fn();
+ const movePara = jest.fn();
+ const para = sampleParsedParagraghs1[0];
+ para.isInputExpanded = true;
+ const utils = render(
+
+ );
+ expect(utils.container.firstChild).toMatchSnapshot();
+
+ utils.getByLabelText('Open paragraph menu').click()
+ utils.getByText('Run input').click()
+ utils.getByLabelText('Open paragraph menu').click()
+ utils.getByText('Duplicate').click()
+ utils.getByLabelText('Open paragraph menu').click()
+ utils.getByText('Delete').click()
+ });
+});
diff --git a/public/components/notebooks/components/paragraph_components/para_input.tsx b/public/components/notebooks/components/paragraph_components/para_input.tsx
new file mode 100644
index 0000000000..5cc41ddd0d
--- /dev/null
+++ b/public/components/notebooks/components/paragraph_components/para_input.tsx
@@ -0,0 +1,241 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ EuiButton,
+ EuiButtonEmpty,
+ EuiCodeBlock,
+ EuiComboBox,
+ EuiComboBoxOptionOption,
+ EuiSelectableOption,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiFormRow,
+ EuiHighlight,
+ EuiLink,
+ EuiModal,
+ EuiModalBody,
+ EuiModalFooter,
+ EuiModalHeader,
+ EuiModalHeaderTitle,
+ EuiOverlayMask,
+ EuiSelectable,
+ EuiSpacer,
+ EuiSuperDatePicker,
+ EuiText,
+ EuiTextArea,
+} from '@elastic/eui';
+import { Input, Prompt } from '@nteract/presentational-components';
+import { uiSettingsService } from '../../../../../common/utils';
+import React, { useState } from 'react';
+import { ParaType } from '../../../../../common/types/notebooks';
+
+/*
+ * "ParaInput" component is used by notebook to populate paragraph inputs for an open notebook.
+ *
+ * Props taken in as params are:
+ * para - parsed paragraph from notebook
+ * index - index of paragraph in the notebook
+ * textValueEditor - function for handling input in textarea
+ * handleKeyPress - function for handling key press like "Shift-key+Enter" to run paragraph
+ *
+ * Input component of nteract used as a container for notebook UI.
+ * https://components.nteract.io/#input
+ */
+
+export const ParaInput = (props: {
+ para: ParaType;
+ index: number;
+ runParaError: boolean;
+ textValueEditor: (evt: React.ChangeEvent, index: number) => void;
+ handleKeyPress: (evt: React.KeyboardEvent, para: any, index: number) => void;
+ startTime: string;
+ setStartTime: (startTime: string) => void;
+ endTime: string;
+ setEndTime: (endTime: string) => void;
+ setIsOutputStale: (isStale?: boolean) => void;
+ visOptions: EuiComboBoxOptionOption[];
+ selectedVisOption: EuiComboBoxOptionOption[];
+ setSelectedVisOption: (newOption: EuiComboBoxOptionOption[]) => void;
+ setVisType: React.Dispatch>;
+}) => {
+ const { para, index, runParaError, textValueEditor, handleKeyPress } = props;
+
+ const inputPlaceholderString =
+ 'Type %md, %sql or %ppl on the first line to define the input type. \nCode block starts here.';
+
+ const renderParaInput = () => {
+ return (
+
+ {/* If the para is selected show the editor else display the code in the paragraph */}
+ {para.isSelected ? (
+ {
+ textValueEditor(evt, index);
+ props.setIsOutputStale(true);
+ }}
+ onKeyPress={(evt) => handleKeyPress(evt, para, index)}
+ value={para.inp}
+ autoFocus
+ />
+ ) : (
+
+ {para.inp}
+
+ )}
+
+ );
+ };
+
+ const renderVisInput = () => {
+ const [isModalOpen, setIsModalOpen] = useState(false);
+ const [selectableOptions, setSelectableOptions] = useState([]);
+ const [selectableError, setSelectableError] = useState(false);
+
+ const onSelect = () => {
+ const selectedOptions = selectableOptions.filter((opt) => opt.checked === 'on');
+ if (selectedOptions.length === 0) {
+ setSelectableError(true);
+ return;
+ }
+ props.setIsOutputStale(true);
+ if (selectedOptions.length > 0) props.setVisType(selectedOptions[0].className);
+ props.setSelectedVisOption(selectedOptions);
+ setIsModalOpen(false);
+ };
+
+ const renderOption = (option: EuiComboBoxOptionOption, searchValue: string) => {
+ let visURL = `visualize#/edit/${option.key}?_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:'${props.startTime}',to:'${props.endTime}'))`;
+ if (option.className === 'OBSERVABILITY_VISUALIZATION') {
+ visURL = `#/event_analytics/explorer/${option.key}`;
+ }
+ return (
+
+ {option.label}
+
+ );
+ };
+
+ return (
+ <>
+
+
+
+ {
+ if (newOption.length > 0) props.setVisType(newOption[0].className);
+ props.setSelectedVisOption(newOption);
+ props.setIsOutputStale(true);
+ }}
+ />
+
+
+
+ {
+ setSelectableOptions([
+ ...props.visOptions[0].options,
+ ...props.visOptions[1].options,
+ ]);
+ setSelectableError(false);
+ setIsModalOpen(true);
+ }}
+ >
+ Browse
+
+
+
+
+
+ {
+ props.setStartTime(e.start);
+ props.setEndTime(e.end);
+ props.setIsOutputStale(true);
+ }}
+ />
+
+
+
+
+
+ {isModalOpen && (
+
+ setIsModalOpen(false)} style={{ width: 500 }}>
+
+ Browse visualizations
+
+
+
+ {
+ setSelectableOptions(newOptions);
+ setSelectableError(false);
+ }}
+ >
+ {(list, search) => (
+ <>
+ {search}
+ {list}
+ >
+ )}
+
+ {selectableError && (
+ <>
+
+
+ {'Visualization is required.'}
+
+ >
+ )}
+
+
+
+ setIsModalOpen(false)}>Cancel
+ onSelect()}
+ fill
+ >
+ Select
+
+
+
+
+ )}
+ >
+ );
+ };
+
+ return (
+
+
+ {para.isVizualisation ? renderVisInput() : renderParaInput()}
+
+ );
+};
diff --git a/public/components/notebooks/components/paragraph_components/para_output.tsx b/public/components/notebooks/components/paragraph_components/para_output.tsx
new file mode 100644
index 0000000000..0a3776e9fc
--- /dev/null
+++ b/public/components/notebooks/components/paragraph_components/para_output.tsx
@@ -0,0 +1,189 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { EuiCodeBlock, EuiSpacer, EuiText } from '@elastic/eui';
+import MarkdownRender from '@nteract/markdown';
+import { Media } from '@nteract/outputs';
+import moment from 'moment';
+import { VisualizationContainer } from '../../../../components/custom_panels/panel_modules/visualization_container';
+import PPLService from '../../../../services/requests/ppl';
+import React, { useState } from 'react';
+import { CoreStart } from '../../../../../../../src/core/public';
+import {
+ DashboardContainerInput,
+ DashboardStart,
+} from '../../../../../../../src/plugins/dashboard/public';
+import { ParaType } from '../../../../../common/types/notebooks';
+import { uiSettingsService } from '../../../../../common/utils';
+import { QueryDataGridMemo } from './para_query_grid';
+
+/*
+ * "ParaOutput" component is used by notebook to populate paragraph outputs for an open notebook.
+ *
+ * Props taken in as params are:
+ * para - parsed paragraph from notebook
+ *
+ * Outputs component of nteract used as a container for notebook UI.
+ * https://components.nteract.io/#outputs
+ */
+export const ParaOutput = (props: {
+ http: CoreStart['http'];
+ pplService: PPLService;
+ para: ParaType;
+ visInput: DashboardContainerInput;
+ setVisInput: (input: DashboardContainerInput) => void;
+ DashboardContainerByValueRenderer: DashboardStart['DashboardContainerByValueRenderer'];
+}) => {
+ const createQueryColumns = (jsonColumns: any[]) => {
+ let index = 0;
+ let datagridColumns = [];
+ for (index = 0; index < jsonColumns.length; ++index) {
+ const datagridColumnObject = {
+ id: jsonColumns[index].name,
+ displayAsText: jsonColumns[index].name,
+ };
+ datagridColumns.push(datagridColumnObject);
+ }
+ return datagridColumns;
+ };
+
+ const getQueryOutputData = (queryObject: any) => {
+ const data = [];
+ let index = 0;
+ let schemaIndex = 0;
+ for (index = 0; index < queryObject.datarows.length; ++index) {
+ let datarowValue = {};
+ for (schemaIndex = 0; schemaIndex < queryObject.schema.length; ++schemaIndex) {
+ const columnName = queryObject.schema[schemaIndex].name;
+ if (typeof queryObject.datarows[index][schemaIndex] === 'object') {
+ datarowValue[columnName] = JSON.stringify(queryObject.datarows[index][schemaIndex]);
+ } else if (typeof queryObject.datarows[index][schemaIndex] === 'boolean') {
+ datarowValue[columnName] = queryObject.datarows[index][schemaIndex].toString();
+ } else {
+ datarowValue[columnName] = queryObject.datarows[index][schemaIndex];
+ }
+ }
+ data.push(datarowValue);
+ }
+ return data;
+ };
+
+ const outputBody = (key: string, typeOut: string, val: string) => {
+ /* Returns a component to render paragraph outputs using the para.typeOut property
+ * Currently supports HTML, TABLE, IMG
+ * TODO: add table rendering
+ */
+ const dateFormat = uiSettingsService.get('dateFormat');
+
+ if (typeOut !== undefined) {
+ switch (typeOut) {
+ case 'QUERY':
+ const inputQuery = para.inp.substring(4, para.inp.length);
+ const queryObject = JSON.parse(val);
+ if (queryObject.hasOwnProperty('error')) {
+ return {val} ;
+ } else {
+ const columns = createQueryColumns(queryObject.schema);
+ const data = getQueryOutputData(queryObject);
+ const [visibleColumns, setVisibleColumns] = useState(() => columns.map(({ id }) => id));
+ return (
+
+
+ {inputQuery}
+
+
+
+
+ );
+ }
+ case 'MARKDOWN':
+ return (
+
+
+
+ );
+ case 'VISUALIZATION':
+ let from = moment(visInput?.timeRange?.from).format(dateFormat);
+ let to = moment(visInput?.timeRange?.to).format(dateFormat);
+ from = from === 'Invalid date' ? visInput.timeRange.from : from;
+ to = to === 'Invalid date' ? visInput.timeRange.to : to;
+ return (
+ <>
+
+ {`${from} - ${to}`}
+
+
+ >
+ );
+ case 'OBSERVABILITY_VISUALIZATION':
+ let fromObs = moment(visInput?.timeRange?.from).format(dateFormat);
+ let toObs = moment(visInput?.timeRange?.to).format(dateFormat);
+ fromObs = fromObs === 'Invalid date' ? visInput.timeRange.from : fromObs;
+ toObs = toObs === 'Invalid date' ? visInput.timeRange.to : toObs;
+ const onEditClick = (savedVisualizationId: string) => {
+ window.location.assign(`#/event_analytics/explorer/${savedVisualizationId}`);
+ };
+ return (
+ <>
+
+ {`${fromObs} - ${toObs}`}
+
+
+
+
+ >
+ );
+ case 'HTML':
+ return (
+
+
+
+ );
+ case 'TABLE':
+ return {val} ;
+ case 'IMG':
+ return ;
+ default:
+ return {val} ;
+ }
+ } else {
+ console.log('output not supported', typeOut);
+ return ;
+ }
+ };
+
+ const { para, DashboardContainerByValueRenderer, visInput, setVisInput } = props;
+
+ return !para.isOutputHidden ? (
+ <>
+ {para.typeOut.map((typeOut: string, tIdx: number) => {
+ return outputBody(para.uniqueId + '_paraOutputBody', typeOut, para.out[tIdx]);
+ })}
+ >
+ ) : null;
+};
diff --git a/public/components/notebooks/components/paragraph_components/para_query_grid.tsx b/public/components/notebooks/components/paragraph_components/para_query_grid.tsx
new file mode 100644
index 0000000000..8b8425278f
--- /dev/null
+++ b/public/components/notebooks/components/paragraph_components/para_query_grid.tsx
@@ -0,0 +1,128 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import $ from 'jquery';
+import {
+ EuiDataGrid,
+ EuiLoadingSpinner,
+ EuiSpacer
+} from '@elastic/eui';
+
+type QueryDataGridProps = {
+ rowCount: number,
+ queryColumns: Array,
+ visibleColumns: Array,
+ setVisibleColumns: (visibleColumns: string[]) => void,
+ dataValues: Array,
+}
+
+type RenderCellValueProps = {
+ rowIndex: number,
+ columnId: string
+}
+
+function QueryDataGrid(props: QueryDataGridProps) {
+ const {
+ rowCount,
+ queryColumns,
+ visibleColumns,
+ setVisibleColumns,
+ dataValues,
+ } = props;
+ const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 });
+ // ** Sorting config
+ const [sortingColumns, setSortingColumns] = useState([]);
+ const [isVisible, setIsVisible] = useState(false);
+
+ const onSort = useCallback(
+ (sortingColumns) => {
+ setSortingColumns(sortingColumns);
+ },
+ [setSortingColumns]
+ );
+
+ const onChangeItemsPerPage = useCallback(
+ (pageSize) =>
+ setPagination((pagination) => ({
+ ...pagination,
+ pageSize,
+ pageIndex: 0,
+ })),
+ [setPagination]
+ );
+
+ const onChangePage = useCallback(
+ (pageIndex) =>
+ setPagination((pagination) => ({ ...pagination, pageIndex })),
+ [setPagination]
+ );
+
+ const renderCellValue = useMemo(() => {
+ return ({ rowIndex, columnId }: RenderCellValueProps) => {
+ return dataValues.hasOwnProperty(rowIndex)
+ ? dataValues[rowIndex][columnId]
+ : null;
+ };
+ }, []);
+
+ const getUpdatedVisibleColumns = (queryColumns: Array) => {
+ let updatedVisibleColumns = [];
+ for (let index = 0; index < queryColumns.length; ++index) {
+ updatedVisibleColumns.push(queryColumns[index].displayAsText);
+ }
+ return updatedVisibleColumns;
+ }
+
+
+ useEffect(() => {
+ if ($('.euiDataGrid__overflow').is(':visible')) {
+ setIsVisible(true);
+ }
+ setTimeout(() => {
+ if ($('.euiDataGrid__overflow').is(':visible')) {
+ setIsVisible(true);
+ }
+ }, 1000);
+ setVisibleColumns(getUpdatedVisibleColumns(queryColumns));
+ }, []);
+
+ const displayLoadingSpinner = (!isVisible) ? (
+ <>
+
+
+ >
+ ) : null;
+
+ return (
+
+ {displayLoadingSpinner}
+
+
+ )
+}
+
+function queryDataGridPropsAreEqual(prevProps: QueryDataGridProps, nextProps: QueryDataGridProps) {
+ return prevProps.rowCount === nextProps.rowCount
+ && JSON.stringify(prevProps.queryColumns) === JSON.stringify(nextProps.queryColumns)
+ && JSON.stringify(prevProps.visibleColumns) === JSON.stringify(nextProps.visibleColumns)
+ && JSON.stringify(prevProps.dataValues) === JSON.stringify(nextProps.dataValues)
+}
+
+export const QueryDataGridMemo = React.memo(QueryDataGrid, queryDataGridPropsAreEqual);
\ No newline at end of file
diff --git a/public/components/notebooks/components/paragraph_components/paragraphs.tsx b/public/components/notebooks/components/paragraph_components/paragraphs.tsx
new file mode 100644
index 0000000000..7926ef2633
--- /dev/null
+++ b/public/components/notebooks/components/paragraph_components/paragraphs.tsx
@@ -0,0 +1,569 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ EuiButton,
+ EuiButtonIcon,
+ EuiComboBoxOptionOption,
+ EuiContextMenu,
+ EuiContextMenuPanelDescriptor,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiFormRow,
+ EuiHorizontalRule,
+ EuiIcon,
+ EuiLink,
+ EuiPanel,
+ EuiPopover,
+ EuiSpacer,
+ EuiText,
+ htmlIdGenerator,
+} from '@elastic/eui';
+import moment from 'moment';
+import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
+import { CoreStart } from '../../../../../../../src/core/public';
+import {
+ DashboardContainerInput,
+ DashboardStart,
+} from '../../../../../../../src/plugins/dashboard/public';
+import { ViewMode } from '../../../../../../../src/plugins/embeddable/public';
+import { NOTEBOOKS_API_PREFIX } from '../../../../../common/constants/notebooks';
+import {
+ PPL_DOCUMENTATION_URL,
+ SQL_DOCUMENTATION_URL,
+ UI_DATE_FORMAT,
+} from '../../../../../common/constants/shared';
+import { ParaType } from '../../../../../common/types/notebooks';
+import { uiSettingsService } from '../../../../../common/utils';
+import { ParaInput } from './para_input';
+import { ParaOutput } from './para_output';
+import { CUSTOM_PANELS_API_PREFIX } from '../../../../../common/constants/custom_panels';
+import PPLService from '../../../../services/requests/ppl';
+import _ from 'lodash';
+
+/*
+ * "Paragraphs" component is used to render cells of the notebook open and "add para div" between paragraphs
+ *
+ * Props taken in as params are:
+ * para - parsed paragraph from notebook
+ * dateModified - last modified time of paragraph
+ * index - index of paragraph in the notebook
+ * paragraphSelector - function used to select a para on click
+ * textValueEditor - function for handling input in textarea
+ * handleKeyPress - function for handling key press like "Shift-key+Enter" to run paragraph
+ * addPara - function to add a new para onclick - "Add Para" Div
+ * DashboardContainerByValueRenderer - Dashboard container renderer for visualization
+ * deleteVizualization - function to delete a para
+ * http object - for making API requests
+ * selectedViewId - selected view: view_both, input_only, output_only
+ * deletePara - function to delete the selected para
+ * runPara - function to run the selected para
+ * clonePara - function to clone the selected para
+ * clearPara - function to clear output of all the paras
+ * movePara - function to move a paragraph at an index to another index
+ *
+ * Cell component of nteract used as a container for paragraphs in notebook UI.
+ * https://components.nteract.io/#cell
+ */
+type ParagraphProps = {
+ pplService: PPLService;
+ para: ParaType;
+ setPara: (para: ParaType) => void;
+ dateModified: string;
+ index: number;
+ paraCount: number;
+ paragraphSelector: (index: number) => void;
+ textValueEditor: (evt: React.ChangeEvent, index: number) => void;
+ handleKeyPress: (evt: React.KeyboardEvent, para: ParaType, index: number) => void;
+ addPara: (index: number, newParaContent: string, inputType: string) => void;
+ DashboardContainerByValueRenderer: DashboardStart['DashboardContainerByValueRenderer'];
+ deleteVizualization: (uniqueId: string) => void;
+ http: CoreStart['http'];
+ selectedViewId: string;
+ setSelectedViewId: (viewId: string, scrollToIndex?: number) => void;
+ deletePara: (para: ParaType, index: number) => void;
+ runPara: (para: ParaType, index: number, vizObjectInput?: string, paraType?: string) => void;
+ clonePara: (para: ParaType, index: number) => void;
+ movePara: (index: number, targetIndex: number) => void;
+ showQueryParagraphError: boolean;
+ queryParagraphErrorMessage: string;
+};
+
+export const Paragraphs = forwardRef((props: ParagraphProps, ref) => {
+ const {
+ pplService,
+ para,
+ index,
+ paragraphSelector,
+ textValueEditor,
+ handleKeyPress,
+ DashboardContainerByValueRenderer,
+ showQueryParagraphError,
+ queryParagraphErrorMessage,
+ http,
+ } = props;
+
+ const [visOptions, setVisOptions] = useState([]); // options for loading saved visualizations
+ const [isPopoverOpen, setIsPopoverOpen] = useState(false);
+ const [runParaError, setRunParaError] = useState(false);
+ const [selectedVisOption, setSelectedVisOption] = useState([]);
+ const [visInput, setVisInput] = useState(undefined);
+ const [visType, setVisType] = useState('');
+
+ // output is available if it's not cleared and vis paragraph has a selected visualization
+ const isOutputAvailable =
+ (para.out.length > 0 && para.out[0] !== '') ||
+ (para.isVizualisation && para.typeOut.length > 0 && visInput !== undefined);
+
+ useImperativeHandle(ref, () => ({
+ runParagraph() {
+ return onRunPara();
+ },
+ }));
+
+ const fetchVisualizations = async () => {
+ let opt1: EuiComboBoxOptionOption[] = [];
+ let opt2: EuiComboBoxOptionOption[] = [];
+ await http
+ .get(`${NOTEBOOKS_API_PREFIX}/visualizations`)
+ .then((res) => {
+ opt1 = res.savedVisualizations.map((vizObject) => ({
+ label: vizObject.label,
+ key: vizObject.key,
+ className: 'VISUALIZATION',
+ }));
+ })
+ .catch((err) => console.error('Fetching dashboard visualization issue', err.body.message));
+
+ await http
+ .get(`${CUSTOM_PANELS_API_PREFIX}/visualizations`)
+ .then((res) => {
+ const noAppVisualizations = res.visualizations.filter((vis) => {
+ return !!!vis.application_id;
+ });
+ opt2 = noAppVisualizations.map((vizObject) => ({
+ label: vizObject.name,
+ key: vizObject.id,
+ className: 'OBSERVABILITY_VISUALIZATION',
+ }));
+ })
+ .catch((err) =>
+ console.error('Fetching observability visualization issue', err.body.message)
+ );
+
+ const allVisualizations = [
+ { label: 'Dashboards Visualizations', options: opt1 },
+ { label: 'Observability Visualizations', options: opt2 },
+ ];
+ setVisOptions(allVisualizations);
+
+ const selectedObject = _.filter([...opt1, ...opt2], {
+ key: para.visSavedObjId,
+ });
+ if (selectedObject.length > 0) {
+ setVisType(selectedObject.className);
+ setSelectedVisOption(selectedObject);
+ }
+ };
+
+ useEffect(() => {
+ if (para.isVizualisation) {
+ if (para.visSavedObjId !== '') setVisInput(JSON.parse(para.vizObjectInput));
+ fetchVisualizations();
+ }
+ }, []);
+
+ const createDashboardVizObject = (objectId: string) => {
+ const vizUniqueId = htmlIdGenerator()();
+ // a dashboard container object for new visualization
+ const newVizObject: DashboardContainerInput = {
+ viewMode: ViewMode.VIEW,
+ panels: {
+ '1': {
+ gridData: {
+ x: 0,
+ y: 0,
+ w: 50,
+ h: 20,
+ i: '1',
+ },
+ type: 'visualization',
+ explicitInput: {
+ id: '1',
+ savedObjectId: objectId,
+ },
+ },
+ },
+ isFullScreenMode: false,
+ filters: [],
+ useMargins: false,
+ id: vizUniqueId,
+ timeRange: {
+ to: para.visEndTime,
+ from: para.visStartTime,
+ },
+ title: 'embed_viz_' + vizUniqueId,
+ query: {
+ query: '',
+ language: 'lucene',
+ },
+ refreshConfig: {
+ pause: true,
+ value: 15,
+ },
+ };
+ return newVizObject;
+ };
+
+ const onRunPara = () => {
+ if (
+ (!para.isVizualisation && !para.inp) ||
+ (para.isVizualisation && selectedVisOption.length === 0)
+ ) {
+ setRunParaError(true);
+ return;
+ }
+ let newVisObjectInput = undefined;
+ if (para.isVizualisation) {
+ const inputTemp = createDashboardVizObject(selectedVisOption[0].key);
+ setVisInput(inputTemp);
+ setRunParaError(false);
+ newVisObjectInput = JSON.stringify(inputTemp);
+ }
+ setRunParaError(false);
+ return props.runPara(para, index, newVisObjectInput, visType);
+ };
+
+ const setStartTime = (time: string) => {
+ const newPara = props.para;
+ newPara.visStartTime = time;
+ props.setPara(newPara);
+ };
+ const setEndTime = (time: string) => {
+ const newPara = props.para;
+ newPara.visEndTime = time;
+ props.setPara(newPara);
+ };
+ const setIsOutputStale = (isStale: boolean) => {
+ const newPara = props.para;
+ newPara.isOutputStale = isStale;
+ props.setPara(newPara);
+ };
+
+ // do not show output if it is a visualization paragraph and visInput is not loaded yet
+ const paraOutput = (!para.isVizualisation || visInput) && (
+
+ );
+
+ // do not show input and EuiPanel if view mode is output_only
+ if (props.selectedViewId === 'output_only') {
+ return paraOutput;
+ }
+
+ const renderParaHeader = (type: string, index: number) => {
+ const panels: EuiContextMenuPanelDescriptor[] = [
+ {
+ id: 0,
+ title: 'Paragraph actions',
+ items: [
+ {
+ name: 'Insert paragraph above',
+ panel: 1,
+ },
+ {
+ name: 'Insert paragraph below',
+ panel: 2,
+ },
+ {
+ name: 'Run input',
+ onClick: () => {
+ setIsPopoverOpen(false);
+ onRunPara();
+ },
+ },
+ {
+ name: 'Move up',
+ disabled: index === 0,
+ onClick: () => {
+ setIsPopoverOpen(false);
+ props.movePara(index, index - 1);
+ },
+ },
+ {
+ name: 'Move to top',
+ disabled: index === 0,
+ onClick: () => {
+ setIsPopoverOpen(false);
+ props.movePara(index, 0);
+ },
+ },
+ {
+ name: 'Move down',
+ disabled: index === props.paraCount - 1,
+ onClick: () => {
+ setIsPopoverOpen(false);
+ props.movePara(index, index + 1);
+ },
+ },
+ {
+ name: 'Move to bottom',
+ disabled: index === props.paraCount - 1,
+ onClick: () => {
+ setIsPopoverOpen(false);
+ props.movePara(index, props.paraCount - 1);
+ },
+ },
+ {
+ name: 'Duplicate',
+ onClick: () => {
+ setIsPopoverOpen(false);
+ props.clonePara(para, index + 1);
+ },
+ },
+ {
+ name: 'Delete',
+ onClick: () => {
+ setIsPopoverOpen(false);
+ props.deletePara(para, index);
+ },
+ },
+ ],
+ },
+ {
+ id: 1,
+ title: 'Insert paragraph above',
+ items: [
+ {
+ name: 'Code block',
+ onClick: () => {
+ setIsPopoverOpen(false);
+ props.addPara(index, '', 'CODE');
+ },
+ },
+ {
+ name: 'Visualization',
+ onClick: () => {
+ setIsPopoverOpen(false);
+ props.addPara(index, '', 'VISUALIZATION');
+ },
+ },
+ ],
+ },
+ {
+ id: 2,
+ title: 'Insert paragraph below',
+ items: [
+ {
+ name: 'Code block',
+ onClick: () => {
+ setIsPopoverOpen(false);
+ props.addPara(index + 1, '', 'CODE');
+ },
+ },
+ {
+ name: 'Visualization',
+ onClick: () => {
+ setIsPopoverOpen(false);
+ props.addPara(index + 1, '', 'VISUALIZATION');
+ },
+ },
+ ],
+ },
+ ];
+
+ return (
+ <>
+
+
+
+ {`[${index + 1}] ${type} `}
+ {
+ const newPara = props.para;
+ newPara.isInputExpanded = !newPara.isInputExpanded;
+ props.setPara(newPara);
+ }}
+ />
+
+
+
+ setIsPopoverOpen(true)}
+ />
+ }
+ isOpen={isPopoverOpen}
+ closePopover={() => setIsPopoverOpen(false)}
+ >
+
+
+
+
+
+ >
+ );
+ };
+
+ const renderOutputTimestampMessage = () => {
+ if (props.selectedViewId === 'view_both') {
+ return (
+ <>
+
+
+ {para.isOutputStale ? (
+
+ ) : (
+
+ )}
+
+
+
+ {`Last successful run ${moment(props.dateModified).format(UI_DATE_FORMAT)}.`}
+
+
+ >
+ );
+ } else {
+ // render message when view mode is input_only
+ return (
+ <>
+
+
+
+
+
+
+ {`Output available from ${moment(props.dateModified).format(UI_DATE_FORMAT)}`}
+
+
+
+
+ props.setSelectedViewId('view_both', index)}>
+ View both
+
+
+
+ >
+ );
+ }
+ };
+
+ const sqlIcon = (
+
+ {' '}
+ SQL {' '}
+
+ );
+
+ const pplIcon = (
+
+ {' '}
+ PPL
+
+ );
+
+ const paragraphLabel = !para.isVizualisation ? (
+
+ Specify the input language on the first line using %[language type]. Supported languages
+ include markdown, {sqlIcon} and {pplIcon}.
+
+ ) : null;
+
+ const queryErrorMessage = queryParagraphErrorMessage.includes('SQL') ? (
+
+ {queryParagraphErrorMessage}. Learn More{' '}
+
+
+
+
+ ) : (
+
+ {queryParagraphErrorMessage}.{' '}
+
+ Learn More
+
+
+ );
+
+ const paraClass = `notebooks-paragraph notebooks-paragraph-${
+ uiSettingsService.get('theme:darkMode') ? 'dark' : 'light'
+ }`;
+
+ return (
+ <>
+
+ {renderParaHeader(!para.isVizualisation ? 'Code block' : 'Visualization', index)}
+ paragraphSelector(index)}>
+ {para.isInputExpanded && (
+ <>
+
+
+
+
+ {runParaError && (
+
{`${
+ para.isVizualisation ? 'Visualization' : 'Input'
+ } is required.`}
+ )}
+
+
+
+ onRunPara()} fill>
+ {isOutputAvailable ? 'Refresh' : 'Run'}
+
+
+ {isOutputAvailable && renderOutputTimestampMessage()}
+
+
+ >
+ )}
+ {props.selectedViewId !== 'input_only' && isOutputAvailable && (
+ <>
+
+
+ {paraOutput}
+
+ >
+ )}
+
+
+ >
+ );
+});
diff --git a/public/components/notebooks/docs/dev/API_Documentation.md b/public/components/notebooks/docs/dev/API_Documentation.md
new file mode 100644
index 0000000000..31aec29f68
--- /dev/null
+++ b/public/components/notebooks/docs/dev/API_Documentation.md
@@ -0,0 +1,706 @@
+# Notebooks API Design Documentation
+
+## Contents
+
+1. [**Notebook Examples**](#notebook-examples)
+2. [**Note APIs**](#notes-apis)
+3. [**Paragraph APIs**](#paragraph-apis)
+4. [**Future Work**](#future-work)
+5. [**References**](#references)
+
+## OpenSearch Dashboards Notebooks REST APIs
+
+**_NOTE:_** The Notebook/Paragraph structure used in body & responses, are with Zeppelin Backend Adaptor. The structure of noteboook and paragraph changes with change in backend, but format of request body and response body remains the same.
+
+## Notebook Examples
+
+- **Default Notebook**
+
+```
+{
+ id: 'note_5f4b9eed-5898-4b39-ba6c-755c0fadd84e',
+ dateCreated: '2020-08-20T18:00:59.845Z',
+ name: 'test 1',
+ dateModified: '2020-08-20T18:37:56.844Z',
+ pluginVersion: '7.9.0',
+ backend: 'Default',
+ paragraphs: [
+ {
+ output: [{ result: '# Type your input here', outputType: 'MARKDOWN', execution_time: '0s' }],
+ input: { inputText: '# Type your input here', inputType: 'MARKDOWN' },
+ dateCreated: '2020-08-20T18:00:59.845Z',
+ dateModified: '2020-08-20T18:00:59.845Z',
+ id: 'paragraph_1a710988-ec19-4caa-83cc-38eb609427d1',
+ },
+ {
+ output: [{ result: '', outputType: 'VISUALIZATION', execution_time: '0s' }],
+ input: {
+ inputText:
+ '{"viewMode":"view","panels":{"1":{"gridData":{"x":1,"y":0,"w":44,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"935afa20-e0cd-11e7-9d07-1398ccfcefa3","vis":null}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"i3ccc6260-e314-11ea-9f99-b37e94bb02ca","timeRange":{"to":"2020-08-20T18:37:44.710Z","from":"2020-07-21T18:37:44.710Z"},"title":"embed_viz_i3ccc6260-e314-11ea-9f99-b37e94bb02ca","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}',
+ inputType: 'VISUALIZATION',
+ },
+ dateCreated: '2020-08-20T18:37:44.809Z',
+ dateModified: '2020-08-20T18:37:56.844Z',
+ id: 'paragraph_6d3237a9-6486-4f93-aa25-0a1c838faabd',
+ },
+ ],
+};
+
+```
+
+- **Zeppelin Notebook**
+
+```
+{
+ paragraphs: [
+ {
+ text:
+ "%md\n Input",
+ dateUpdated: '2020-08-20 21:15:04.590',
+ config: {},
+ settings: { params: {}, forms: {} },
+ results: {
+ code: 'SUCCESS',
+ msg: [
+ {
+ type: 'HTML',
+ data:
+ '\nInput
',
+ },
+ ],
+ },
+ apps: [],
+ runtimeInfos: {},
+ progressUpdateIntervalMs: 500,
+ jobName: 'paragraph_1597958104590_901298942',
+ id: 'paragraph_1596519508360_932236116',
+ dateCreated: '2020-08-20 21:15:04.590',
+ status: 'READY',
+ },
+ ],
+ name: 'Embed Vizualization',
+ id: '2FJH8PW8K',
+ defaultInterpreterGroup: 'spark',
+ version: '0.9.0-preview2',
+ noteParams: {},
+ noteForms: {},
+ angularObjects: {},
+ config: { isZeppelinNotebookCronEnable: false },
+ info: {},
+};
+```
+
+## Notes APIs
+
+1. **Fetch all the notebooks available →** returns a list of notebook id and paths
+
+```
+ GET api/notebooks/
+
+ RESPONSE BODY
+ {
+ "data": [
+ {
+ "id": "2FF3GW3H8",
+ "path": "/Embed Viz"
+ },
+ {
+ "id": "2FHEP953H",
+ "path": "/Log Analysis"
+ },
+ {
+ "id": "2FES7PY77",
+ "path": "/Post-mortem Report"
+ },
+ {
+ "id": "2FFAMT6VV",
+ "path": "/test 1"
+ }
+ ]
+ }
+```
+
+2. **Get all paragraphs of a notebook →** returns list of paragraphs
+
+```
+ GET api/notebooks/note/{noteId}
+
+ RESPONSE BODY // list of Paragraphs
+ {
+ "paragraphs": [
+ {
+ "text": "%md\n# This is markdown test",
+ "user": "anonymous",
+ "dateUpdated": "Aug 11, 2020 8:24:38 AM",
+ "config": {
+ "tableHide": true,
+ "editorSetting": {
+ "language": "markdown",
+ "editOnDblClick": true,
+ "completionSupport": false
+ },
+ "colWidth": 12,
+ "editorMode": "ace/mode/markdown",
+ "fontSize": 9,
+ "editorHide": false,
+ "results": {},
+ "enabled": true
+ },
+ "settings": {
+ "params": {},
+ "forms": {}
+ },
+ "results": {
+ "code": "SUCCESS",
+ "msg": [
+ {
+ "type": "HTML",
+ "data": "\n
This is markdown test \n\n"
+ }
+ ]
+ },
+ "apps": [],
+ "runtimeInfos": {},
+ "progressUpdateIntervalMs": 500,
+ "jobName": "paragraph_1597133766113_507090317",
+ "id": "paragraph_1597101740623_82179823",
+ "dateCreated": "Aug 11, 2020 8:16:06 AM",
+ "dateStarted": "Aug 11, 2020 8:24:38 AM",
+ "dateFinished": "Aug 11, 2020 8:24:38 AM",
+ "status": "FINISHED"
+ },
+ {
+ "title": "Paragraph inserted",
+ "text": "%md\n# markdown cell number 2 ",
+ "user": "anonymous",
+ "dateUpdated": "Aug 11, 2020 8:24:32 AM",
+ "config": {},
+ "settings": {
+ "params": {},
+ "forms": {}
+ },
+ "results": {
+ "code": "SUCCESS",
+ "msg": [
+ {
+ "type": "HTML",
+ "data": "\n
markdown cell number 2 \n\n"
+ }
+ ]
+ },
+ "apps": [],
+ "runtimeInfos": {},
+ "progressUpdateIntervalMs": 500,
+ "jobName": "paragraph_1597134223413_576247989",
+ "id": "paragraph_1597134223413_576247989",
+ "dateCreated": "Aug 11, 2020 8:23:43 AM",
+ "dateStarted": "Aug 11, 2020 8:24:32 AM",
+ "dateFinished": "Aug 11, 2020 8:24:32 AM",
+ "status": "FINISHED"
+ }
+ ]
+ }
+```
+
+3. **Add a Notebook →** returns new notebook id
+
+```
+ POST api/notebooks/note
+
+ REQUEST BODY
+ {"name": "Demo Notebook"} // new name
+
+ RESPONSE BODY
+ {
+ "status": "OK",
+ "message": "",
+ "body": "2FG6FWGY5" //New Notebook ID
+ }
+```
+
+4. **Rename a Notebook →** returns acknowledgement
+
+```
+ PUT api/notebooks/note/rename
+
+ REQUEST BODY
+ {
+ "noteId": "2FG6FWGY5", // notebook id to be renamed
+ "name":"Demo 1", // new name
+ }
+
+ RESPONSE BODY
+ {
+ "status": "OK",
+ "message": ""
+ }
+```
+
+5. **Clone a Notebook →** returns new notebook id
+
+```
+ POST api/notebooks/note/clone
+
+ REQUEST BODY
+ {
+ "noteId": "2FG6FWGY5", // notebook id to be cloned
+ "name":"Demo 1_copy", // new name for cloned notebook
+ }
+
+ RESPONSE BODY
+ {
+ "status": "OK",
+ "message": "",
+ "body": "2FFAG7HAQ"
+ }
+```
+
+6. **Delete a Notebook →** returns acknowledgement
+
+```
+ DELETE api/notebooks/note/{noteid}
+
+ RESPONSE BODY
+ {
+ "status": "OK",
+ "message": ""
+ }
+```
+
+7. **Import a Notebook →** returns new notebooks Id
+
+```
+ POST api/notebooks/note/import
+
+ REQUEST BODY
+ // { noteObj: {notebooks as json} }
+
+ {
+ "noteObj": {
+ "angularObjects": {},
+ "config": {
+ "isZeppelinNotebookCronEnable": false
+ },
+ "defaultInterpreterGroup": "md",
+ "id": "2FH5EF6QF",
+ "info": {},
+ "name": "test 1",
+ "noteForms": {},
+ "noteParams": {},
+ "paragraphs": [{
+ "apps": [],
+ "config": {
+ "colWidth": 12,
+ "editorHide": false,
+ "editorMode": "ace/mode/markdown",
+ "editorSetting": {
+ "completionSupport": false,
+ "editOnDblClick": true,
+ "language": "markdown"
+ },
+ "enabled": true,
+ "fontSize": 9,
+ "results": {},
+ "tableHide": true
+ },
+ "dateCreated": "2020-08-10 23:22:20.623",
+ "dateFinished": "2020-08-11 08:15:21.175",
+ "dateStarted": "2020-08-11 08:15:21.150",
+ "dateUpdated": "2020-08-11 08:15:21.140",
+ "id": "paragraph_1597101740623_82179823",
+ "jobName": "paragraph_1597101740623_82179823",
+ "progressUpdateIntervalMs": 500,
+ "results": {
+ "code": "SUCCESS",
+ "msg": [{
+ "data": "\n
This is markdown test \n\n",
+ "type": "HTML"
+ }]
+ },
+ "runtimeInfos": {},
+ "settings": {
+ "forms": {},
+ "params": {}
+ },
+ "status": "FINISHED",
+ "text": "# This is markdown test",
+ "user": "anonymous"
+ }],
+ "version": "0.9.0-SNAPSHOT"
+ }
+ }
+
+
+ RESPONSE BODY
+ {
+ "status": "OK",
+ "message": "",
+ "body": "2FF38BHBY" //new notebook id
+ }
+```
+
+8. **Export a Notebook →** Returns a notebooks object
+
+```
+ GET api/notebooks/note/export/{noteid}
+
+ RESPONSE BODY // A notebook object
+ {
+ "paragraphs": [
+ {
+ "text": "# This is markdown test",
+ "user": "anonymous",
+ "dateUpdated": "2020-08-11 17:08:24.063",
+ "config": {
+ "tableHide": true,
+ "editorSetting": {
+ "completionSupport": false,
+ "editOnDblClick": true,
+ "language": "markdown"
+ },
+ "colWidth": 12.0,
+ "editorMode": "ace/mode/markdown",
+ "editorHide": false,
+ "fontSize": 9.0,
+ "results": {},
+ "enabled": true
+ },
+ "settings": {
+ "params": {},
+ "forms": {}
+ },
+ "results": {
+ "code": "SUCCESS",
+ "msg": [
+ {
+ "type": "HTML",
+ "data": "\n
This is markdown test \n\n"
+ }
+ ]
+ },
+ "apps": [],
+ "runtimeInfos": {},
+ "progressUpdateIntervalMs": 500,
+ "jobName": "paragraph_1597165704063_563073184",
+ "id": "paragraph_1597101740623_82179823",
+ "dateCreated": "2020-08-11 17:08:24.063",
+ "status": "READY"
+ }
+ ],
+ "name": "test 1",
+ "id": "2FF38BHBY",
+ "defaultInterpreterGroup": "spark",
+ "version": "0.9.0-SNAPSHOT",
+ "noteParams": {},
+ "noteForms": {},
+ "angularObjects": {},
+ "config": {
+ "isZeppelinNotebookCronEnable": false
+ },
+ "info": {}
+ }
+```
+
+## Paragraph APIs
+
+1. **Update and Run a Paragraph →** returns the updated paragraph
+
+Does the following backend tasks:
+
+ 1. Updates a paragraph (with new input)
+ 2. Runs it
+ 3. Fetches the paragraph (with updated input and executed result output)
+
+```
+ POST api/notebooks/paragraph/update/run
+
+ REQUEST BODY
+ {
+ "noteId": "2FF38BHBY", // notebook id
+ "paragraphId": "paragraph_1597101740623_82179823", // para id
+ "paragraphInput": "%md\n# This is markdown test 2" // para inp
+ }
+
+ RESPONSE BODY
+ {
+ "text": "%md\n# This is markdown test 2",
+ "user": "anonymous",
+ "dateUpdated": "Aug 11, 2020 5:35:01 PM",
+ "config": {
+ "tableHide": true,
+ "editorSetting": {
+ "completionSupport": false,
+ "editOnDblClick": true,
+ "language": "markdown"
+ },
+ "colWidth": 12,
+ "editorMode": "ace/mode/markdown",
+ "editorHide": false,
+ "fontSize": 9,
+ "results": {},
+ "enabled": true
+ },
+ "settings": {
+ "params": {},
+ "forms": {}
+ },
+ "results": {
+ "code": "SUCCESS",
+ "msg": [
+ {
+ "type": "HTML",
+ "data": "\n
This is markdown test 2 \n\n"
+ }
+ ]
+ },
+ "apps": [],
+ "runtimeInfos": {},
+ "progressUpdateIntervalMs": 500,
+ "jobName": "paragraph_1597165704063_563073184",
+ "id": "paragraph_1597101740623_82179823",
+ "dateCreated": "Aug 11, 2020 5:08:24 PM",
+ "dateStarted": "Aug 11, 2020 5:35:01 PM",
+ "dateFinished": "Aug 11, 2020 5:35:01 PM",
+ "status": "FINISHED"
+ }
+```
+
+2. **Update a Paragraph →** returns the updated paragraph
+
+Does the following backend tasks:
+
+ 1. Updates a paragraph (with new input)
+ 2. Fetches the paragraph (with updated input and old output)
+
+NOTE: This API call doesn’t execute the paragraph input, should be used to save a partially written code
+
+```
+ PUT api/notebooks/paragraph/
+
+ REQUEST BODY
+ {
+ "noteId": "2FF3GW3H8", // notebook id
+ "paragraphId": "paragraph_1596519508360_932236116", // para id
+ "paragraphInput": "%md \n\n### Hi Everyone\n* Here's a demo on **OpenSearch Dashboards Notebooks**\n* I was not present in previous input"
+ // new input
+ }
+
+ RESPONSE BODY
+ {
+ "text": "%md \n\n### Hi Everyone\n* Here's a demo on **OpenSearch Dashboards Notebooks**\n* I was present in previous input",
+ "user": "anonymous",
+ "dateUpdated": "Aug 11, 2020 5:52:14 PM",
+ "config": {},
+ "settings": {
+ "params": {},
+ "forms": {}
+ },
+ "results": {
+ "code": "SUCCESS",
+ "msg": [{
+ "type": "HTML",
+ // old result
+ "data": "\n
Hi Everyone \n
\nHere’s a demo on OpenSearch Dashboards Notebooks \n \n\n
"
+ }]
+ },
+ "apps": [],
+ "runtimeInfos": {},
+ "progressUpdateIntervalMs": 500,
+ "jobName": "paragraph_1597104141269_874537409",
+ "id": "paragraph_1596519508360_932236116",
+ "dateCreated": "Aug 11, 2020 12:02:21 AM",
+ "dateStarted": "Aug 11, 2020 5:51:43 PM",
+ "dateFinished": "Aug 11, 2020 5:51:43 PM",
+ "status": "FINISHED"
+ }
+```
+
+3. **Add a new paragraph →** returns newly created paragraph
+
+Does the following backend tasks:
+
+ 1. Adds new a paragraph
+ 2. Fetches the newly created paragraph
+
+```
+ POST api/notebooks/paragraph/
+
+ REQUEST BODY
+ {
+ "noteId": "2FF3GW3H8", // notebook id
+ "paragraphIndex": 1, // index to create a new para
+ "paragraphInput": "%opensearch\n" // input to be provided in the new para
+ "inputType": "CODE" // a paragraph can be of type CODE or VISUALIZATION
+ }
+
+ RESPONSE BODY
+ {
+ "title": "Paragraph inserted",
+ "text": "%opensearch\n",
+ "user": "anonymous",
+ "dateUpdated": "Aug 11, 2020 5:56:23 PM",
+ "config": {},
+ "settings": {
+ "params": {},
+ "forms": {}
+ },
+ "apps": [],
+ "runtimeInfos": {},
+ "progressUpdateIntervalMs": 500,
+ "jobName": "paragraph_1597168583538_1357513873",
+ "id": "paragraph_1597168583538_1357513873",
+ "dateCreated": "Aug 11, 2020 5:56:23 PM",
+ "status": "READY"
+ }
+```
+
+4. **Delete a paragraph →** returns list of paragraphs
+
+```
+ DELETE api/notebooks/paragraph/{noteId}/{paragraphId}
+
+ RESPONSE BODY // list of Paragraphs
+ {
+ "paragraphs": [{
+ "text": "%md\n# This is markdown test 2",
+ "user": "anonymous",
+ "dateUpdated": "Aug 11, 2020 6:55:07 PM",
+ "config": {
+ "tableHide": true,
+ "editorSetting": {
+ "completionSupport": false,
+ "editOnDblClick": true,
+ "language": "markdown"
+ },
+ "colWidth": 12,
+ "editorMode": "ace/mode/markdown",
+ "editorHide": false,
+ "fontSize": 9,
+ "results": {},
+ "enabled": true
+ },
+ "settings": {
+ "params": {},
+ "forms": {}
+ },
+ "results": {
+ "code": "SUCCESS",
+ "msg": [{
+ "type": "HTML",
+ "data": "\n
This is markdown test 2 \n\n"
+ }]
+ },
+ "apps": [],
+ "runtimeInfos": {},
+ "progressUpdateIntervalMs": 500,
+ "jobName": "paragraph_1597165704063_563073184",
+ "id": "paragraph_1597101740623_82179823",
+ "dateCreated": "Aug 11, 2020 5:08:24 PM",
+ "dateStarted": "Aug 11, 2020 6:55:07 PM",
+ "dateFinished": "Aug 11, 2020 6:55:07 PM",
+ "status": "FINISHED"
+ }, {
+ "title": "Paragraph inserted",
+ "text": "%opensearch\n",
+ "user": "anonymous",
+ "dateUpdated": "Aug 11, 2020 6:55:07 PM",
+ "config": {},
+ "settings": {
+ "params": {},
+ "forms": {}
+ },
+ "apps": [],
+ "runtimeInfos": {},
+ "progressUpdateIntervalMs": 500,
+ "jobName": "paragraph_1597172107715_362327829",
+ "id": "paragraph_1597172107715_362327829",
+ "dateCreated": "Aug 11, 2020 6:55:07 PM",
+ "status": "READY"
+ }]
+ }
+```
+
+5. **Clear outputs of all paragraphs →** returns list of paragraphs (with empty outputs)
+
+```
+ PUT api/notebooks/paragraph/clear
+
+ REQUEST BODY
+ {"noteId":"2FF38BHBY"} // notebook id to clear all paras
+
+ RESPONSE BODY // list of Paragraphs
+ {
+ "paragraphs": [{
+ "text": "%md\n# This is markdown test 2",
+ "user": "anonymous",
+ "dateUpdated": "Aug 11, 2020 6:55:07 PM",
+ "config": {
+ "tableHide": true,
+ "editorSetting": {
+ "completionSupport": false,
+ "editOnDblClick": true,
+ "language": "markdown"
+ },
+ "colWidth": 12,
+ "editorMode": "ace/mode/markdown",
+ "editorHide": false,
+ "fontSize": 9,
+ "results": {},
+ "enabled": true
+ },
+ "settings": {
+ "params": {},
+ "forms": {}
+ },
+ "apps": [],
+ "runtimeInfos": {},
+ "progressUpdateIntervalMs": 500,
+ "jobName": "paragraph_1597165704063_563073184",
+ "id": "paragraph_1597101740623_82179823",
+ "dateCreated": "Aug 11, 2020 5:08:24 PM",
+ "dateStarted": "Aug 11, 2020 6:55:07 PM",
+ "dateFinished": "Aug 11, 2020 6:55:07 PM",
+ "status": "FINISHED"
+ }, {
+ "title": "Paragraph inserted",
+ "text": "%md\n\n# Output is empty\n",
+ "user": "anonymous",
+ "dateUpdated": "Aug 11, 2020 7:17:31 PM",
+ "config": {},
+ "settings": {
+ "params": {},
+ "forms": {}
+ },
+ "apps": [],
+ "runtimeInfos": {},
+ "progressUpdateIntervalMs": 500,
+ "jobName": "paragraph_1597172107715_362327829",
+ "id": "paragraph_1597172107715_362327829",
+ "dateCreated": "Aug 11, 2020 6:55:07 PM",
+ "dateStarted": "Aug 11, 2020 7:17:31 PM",
+ "dateFinished": "Aug 11, 2020 7:17:31 PM",
+ "status": "FINISHED"
+ }]
+ }
+```
+
+## **Future Work**
+
+### **Short Term**
+
+1. **Notes APIs**
+ 1. Run notebook → runs all the paragraphs and returns the updated list of paragraphs
+ 2. Save notebook → updates all the paragraphs and returns the updated list of paragraphs
+2. **Paragraph APIs**
+ 1. Run a paragraph → runs the paragraph with pre-exisiting input code and returns the updated paragraph (with executed result)
+ 2. Refresh a paragraph → runs the paragraph with pre-exisiting input code at certain intervals and returns the updated paragraph (with executed result)
+
+### **Long Term**
+
+1. Checkpoint notebook → saves all the paragraphs and returns acknowledgement
+2. Extend endpoints like refresh, run, save and checkpoint to be asynchronous
+
+## References:
+
+1. Zeppelin APIs : http://zeppelin.apache.org/docs/0.9.0/usage/rest_api/notebook.html
+2. More About Zeppelin: https://zeppelin.apache.org/docs/0.9.0/
diff --git a/public/components/notebooks/docs/dev/Build_Documentation.md b/public/components/notebooks/docs/dev/Build_Documentation.md
new file mode 100644
index 0000000000..9af1785714
--- /dev/null
+++ b/public/components/notebooks/docs/dev/Build_Documentation.md
@@ -0,0 +1,15 @@
+# Build OpenSearch Dashboards Notebooks Plugin
+
+## Setup OpenSearch & OpenSearch Dashboards dev environment and use the plugin with Zeppelin
+
+- Please follow [README.md](../../../../../../DEVELOPER_GUIDE.md) for build instructions.
+
+- **[Optional] If using Zeppelin Backend Adaptor:**
+ - Setup Zeppelin as mentioned in [Apache Zeppelin Setup: Zeppelin Backend Adaptor](./Zeppelin_backend_adaptor.md#apache-zeppelin-setup)
+ - Edit [this line](https://github.com/opensearch-project/dashboards-notebooks/blob/dev/common/index.ts#L19) to `SELECTED_BACKEND = 'ZEPPELIN';`
+ - Edit [this line](https://github.com/opensearch-project/dashboards-notebooks/blob/dev/common/index.ts#L21) for adding Zeppelin endpoint `zeppelinURL = 'http://localhost:8080';`
+- Start OpenSearch Dashboards
+
+- More on [Usage of Plugin](./Usage_Documentation.md)
+
+- Happy Notebooking :)
diff --git a/public/components/notebooks/docs/dev/OpenSearch-Dashboards-Notebooks-Design-Proposal.md b/public/components/notebooks/docs/dev/OpenSearch-Dashboards-Notebooks-Design-Proposal.md
new file mode 100644
index 0000000000..b9bd9050e7
--- /dev/null
+++ b/public/components/notebooks/docs/dev/OpenSearch-Dashboards-Notebooks-Design-Proposal.md
@@ -0,0 +1,278 @@
+# RFC - OpenSearch Dashboards Notebooks
+
+## Contents
+
+1. [Overview](#1-overview)
+2. [Requirements](#2-requirements)
+3. [User Stories](#3-user-stories)
+4. [Design](#4-design)
+5. [Design Details and Implementation](#5-design-details-and-implementation)
+6. [Build & Usage](#6-build--usage)
+7. [Appendix](#7-appendix)
+8. [References](#8-references)
+
+## 1. Overview
+
+### **1.1 Introduction**
+
+OpenSearch Dashboards Notebooks enable data-driven, interactive data analytics and collaborative documents to be created and used as live notes in OpenSearch Dashboards. They allow devops, support specialists, solution and presales specialists, customer success experts and engineers to create and share stories. They facilitate combining visualizations, timelines and text, code and adding annotations. Here are a few OpenSearch Dashboards Notebooks use-cases:
+
+1. Create post-mortem documents
+2. Design runbooks
+3. Build Live infrastructure reports
+4. Foster data driven explorative collaborations
+
+### **1.2 Motivation**
+
+- **Existing Solution:** OpenSearch Dashboards Dashboards offer a solution for a few selected use cases, and are a great tool if you’re focused on monitoring a known set of metrics over time. Current issues include:
+ - Dashboards are static in nature and are not user-friendly to make quick changes in iterations
+ - Dashboards lack context for visualizations
+ - Dashboards do not have multi-timeline support which are needed for post-mortem and cause analysis
+ - Dashboards are restricted to data sources within the OpenSearch environment
+
+* **Our Solution:** OpenSearch Dashboards Notebooks provide:
+ - Familiar notebooks user-interface for faster iterations as live notes
+ - Markdown/Code interpreters for contextual use of data with detailed explanations by allowing a user to combine saved visualizations, text and graphs
+ - Adaptors to embellish existing data in OpenSearch with other reference data sources.
+ - Support multiple timelines to compare and contrast visualizations
+
+### **1.3 Glossary**
+
+1. _Notebooks:_ An interface for on-the-go code writing and execution
+2. _Paragraphs:_ Each notebook consists on multiple paragraphs with allows users to input code or embed a visualization
+3. _Input Cell:_ Each paragraph consists an input cell that contains code for execution in supported interpreters such as markdown, SQL and DSL.
+4. _Output Cell:_ Each paragraph consists an output cell that contains execution result of code or an embeded visualization with its time-range
+5. _Backend Adaptor:_ An add-on to the existing default backend that provides additional interpreters and storage options.
+
+## 2. Requirements
+
+**Functional:**
+
+1. **Notebooks**
+ 1. As a user, I should be able to use OpenSearch Dashboards Notebooks plugin UI for all the interactions
+ 2. As a user, I should be able to View all the notebooks available
+ 3. As a user, I should be able to Create, Edit, Rename, Delete and Clone Notebooks
+ 4. As a user, I should be able to Import and Export Notebooks for collaborative story telling
+2. **Paragraphs**
+ 1. As a user, I should be able to use Create, Edit, Save, Delete and Clone Paragraphs
+ 2. As a user, I should be able to use Toggle all Inputs of paragraphs
+ 3. As a user, I should be able to use Clear and Toggle all Outputs of paragraphs
+3. **Visualizations**
+ 1. As a user, I should be able to embed Saved Visualizations
+ 2. As a user, I should be able to Resize and Delete embedded Visualizations
+ 3. As a user, I should be able to use multiple timelines for different visualizations
+ 4. As a user, I should be able to Inspect Visualization Data
+4. **Default Backend**
+ 1. As a user, I should be able to use Visualizations and Markdown interpreter in Notebooks
+ 2. As a user, I should be able to use SQL and DSL query interpreters in Notebooks
+ 3. As a user, I should be able to store Notebooks as OpenSearch indices
+5. **Backend Adaptors**
+ 1. As a user, I should be able to plug an add-on external backend services (like [Apache Zeppelin](https://zeppelin.apache.org/), [Amazon SageMaker](https://aws.amazon.com/sagemaker/), [Jupyter](https://jupyter.org/)) to the plugin using adaptors
+ 2. As a user, I should be able to use all the interpreters provided by the plugged backend service in addition to those provided by default
+ 3. As a user, I should be able to use the storage adaptors provided by the plugged backend service
+ 4. As a user, I should be able to use external data sources and environments provided by the plugged backend
+
+**Non-functional:**
+
+1. **Default Backend** - As a user, I should be able to use the plugin’s default interpreters without setting up any external backend service
+2. **Backend Adaptors** - As a user, I should be free to create and use external data planes/environments and bring them to OpenSearch Dashboards via supported adaptors
+3. **Security** - As a user, I should be able to view/clone/read/save/edit notebooks adhering to my role settings
+
+## 3. User Stories
+
+**Operations on notebooks**
+
+1. Create: As a user, I should be able to create a notebook.
+2. View: As a user, I should be able to view the notebook.
+3. Save: As a user, I should be able to save the notebook.
+4. Checkpoint: The notebook automatically saves the notebook after every 3 minutes. If the user loads the notebook after the checkpoint is triggered, it will allow load the content till that point.
+5. Save, Autosave: The notebook can saved. After a given time period, the autosave is triggered on the notebook.
+6. Clone: As a user, I should be able to clone the notebook
+7. Rename: As a user, I should be able to rename the notebook
+8. Delete: As a user, I should be able to delete the notebook
+
+**Create, Edit, Delete content in an individual notebook**
+
+1. As a user, I should be able to add paragraphs to a notebook. I should be able to add markdown or code to a paragraph.
+2. Markdown in a paragraph allows adding text and enables the use of titles/headings, images, lists and hyperlinks.
+3. Code can be added in the form of queries, DSL, PPL, SQL etc.
+4. As a user, I should be able to execute the code block or the markup and the output will get reflected in the output cell. The output will display text, images, lists, visualizations/graphs etc.
+5. As a user, I should be able to annotate the output with comments/tags, usernames, time/date etc. using markdown
+6. Time periods: As a user I should be able to set the date/time periods or date/time to the individual output cells. By default, the date/time reflected is global. This is different from the actual timestamp on when the content was edited.
+
+**Share, export and download notebooks**
+
+1. As a creator of notebooks, I should be able to share a OpenSearch Dashboards Notebook with other users so that they can view and/or edit the notebooks as per the privileges and permissions they have.
+2. I should also be able to share the notebook as a pdf via email. I should also be able to download the story as a pdf.
+
+**List of Notebooks**
+
+1. As a user, I should be able to add the notebooks to a list of notebooks. The list of notebooks shows name of the notebook, creator’s details, and last modified dates.
+2. I should be able to view, share and download the individual notebooks in the list of notebooks.
+3. I should be able to view the list of notebooks.
+4. I should be able to filter notebooks based on whether I created or someone else created them and as per dates modified.
+
+## 4. Design
+
+### **4.1 What (Notebooks)**
+
+- Notebooks are browser-based [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) built upon a number of popular open-source libraries
+
+### **4.2 Where (Notebooks Storage)**
+
+- Notebooks are stored as OpenSearch indices in the default backend. If backend adaptors are used by user, the storage is switched to storage options provided by the external backend service.
+- For example: Apache Zeppelin backend service supports files, Git, Amazon S3, mongo and other storage options.
+
+### **4.3 How (Releases)**
+
+- OpenSearch Dashboards Notebooks will be released as a OpenSearch Dashboards plugin shipped with the Open-Distro for OpenSearch solution.
+
+### **4.4 Architecture**
+
+**4.4.1 Version 1:** In this architecture, Backend is tightly coupled with Apache Zeppelin as a backend service to provide interpreters and storage adaptors
+
+![Notebooks Arch_v1](images/Notebooks_v1.png)
+
+- Pros:
+ - Single Backend configuration is easier for development and usage
+ - Zeppelin Backend will provide one stop shop for interpreters, runtime-environments and storage adaptors
+- Cons:
+ - Users will not be free to customize Zeppelin Backend runtime-environment/storage adaptors
+ - Need to develop a new storage adaptor for Zeppelin to store notebooks as OpenSearch indices [POC details](../poc/docs/Zeppelin_OpenSearch_Storage.md)
+ - Difficult to maintain releases, as we have to sync version currency/patches to Zeppelin code repository
+
+**4.4.2 Version 2:** In this architecture, Backends are switchable with two options of Default backend (Markdown, Visualization support) or Apache Zeppelin Backend (25+ interpreter support)
+
+![Notebooks Arch_v1](images/Notebooks_v2.png)
+
+- Pros:
+ - Default Backend configuration is easy to use for any user who wants to stay away from setting up additional environments and interpreters
+ - Apache Zeppelin Backend will provide users the customizability to add new environments and interpreters
+- Cons:
+ - Once a user selects Apache Zeppelin Backend they will not be able to use visualizations to be embedded in notebooks (provided only by default backend)
+
+**4.4.3 Version 3:** In this architecture, Default backend (Markdown, Visualization support) is provided upfront and a user may choose to bring in their own endpoints for adaptors like Apache Zeppelin, Amazon SageMaker or Jupyter
+
+![Notebooks Arch_v1](images/Notebooks_v3.png)
+
+- Pros:
+ - Default Backend configuration is easy to use for any user who wants to stay away from setting up additional environments and interpreters
+ - An Adaptor provides additional functionalities on top of Default Backend, rather than being replacement
+ - Users are free to bring in their backend service with endpoints for interpreter support, runtime-environment and storages
+- Cons:
+ - Need to develop UI as a decoupled service and need to development of multiple parsers as notebook structures change with different backend adaptors
+
+**4.4.4 Decision:** Even though “Version 1” provides good coupling and ease of development, the maintenance and releases are a big issue striking this option out. "Version 2" provides switchable backends which is easy to use but this switching happens at a cost of not supporting a core functionality of visualizations with Zeppelin backend. Finally, we selected "version 3" as it provides user flexibility to bring their own external backend services to connect to OpenSearch Dashboards Notebooks.
+
+## 5. Design Details and Implementation
+
+### **5.1 OpenSearch Dashboards Notebooks Plugin UI**
+
+1. **React based UI**, uses elements from [OpenSearch UI](https://elastic.github.io/eui/#/) elements & [Nteract.io components](https://components.nteract.io/)
+2. **OpenSearch UI Components**
+ 1. Used for blending notebooks in OpenSearch Dashboards Plugins environment
+ 2. All container UI components and buttons use OpenSearch UI components
+3. **Nteract Components**
+ 1. [_Presentational-components_](https://components.nteract.io/#section-nteractpresentational-components) module of nteract is used specifically for notebook UI
+ 2. _[Outputs](https://components.nteract.io/#section-nteractoutputs)_ module is used for rendering markdown if backend adaptor doesn't have a markdown interpreter
+4. **Notebook Parsers**
+ 1. Each Backend has a different notebook structure, thus we need a parser to convert these notebooks to a common structure. Based on the selected backend a parser converts paragraphs in notebook to a parsed-Paragraph.
+ 2. Parsed-Paragraphs are used to render components of notebooks.
+ 3. FUTURE: Can shift this module to the backend, need to weigh pros and cons as behavior of APIs will change especially for Import and Export would change drastically
+5. Here’s a sample wireframe
+
+![OpenSearch Dashboards Notebooks UI](images/UI.png)
+
+### **5.2 OpenSearch Dashboards Notebooks Plugin Backend**
+
+1. Uses the Hapi Backend Contianer provided by OpenSearch Dashboards
+2. Provides API routes for connecting UI components to a backend service
+3. **_Router Modules_:**
+ 1. NotebookConnector - routes Notebook CRUD operations
+ 2. ParagraphConnector - routes Paragraph CRUD operations
+4. **_Default Backend_:**
+ 1. Provides markdown interpreter support for notebooks
+ 2. Provides ability to embed saved visualizations using Dashboard Containers
+ 3. FUTURE: provide interpreter support for SQL and DSL queries
+5. **Backend Adaptors**
+ 1. A Backend Adaptor provides an interface to connect external notebook backends
+ 2. An external notebook backend service is connected through a HTTP endpoint
+ 3. Once a backend service is connected all the interpreters, environments and data sources provided by the service are automatically extended in notebooks
+ 4. Uses [Hapi Wreck](https://hapi.dev/module/wreck/) to connect a backend service with a HTTP endpoint
+ 5. Example Adaptor: **Zeppelin Backend Server**
+ ![Zeppelin Server](images/zeppelin_architecture.png)
+ - Open source, provided by [Apache Zeppelin](http://zeppelin.apache.org/)
+ - Provides all communication to and from a notebook & supports 25+ interpreters
+ - Connects via a HTTP endpoint to the Plugin backend
+ - [Interpreter APIs](http://zeppelin.apache.org/docs/0.9.0/usage/rest_api/interpreter.html) Get interpreter settings, create/update/restart/delete interpreter setting
+ - [Notebook APIs](http://zeppelin.apache.org/docs/0.9.0/usage/rest_api/notebook.html) Create/update/restart/delete noteboooks and paragraphs
+ - Provides inter-paragraph communication capabilities
+ - Can be setup to provide OpenSearch and OpenSearch-SQL interpreters
+ - Can be connected with python environment to use ML/plot libraries
+
+### **5.3 Data Model**
+
+- **Default Backend Notebook Schema:** Each notebook object contains it’s name, unique id, date of creation/modification, OpenSearch Dashboards Notebooks plugin version and an array of paragraphs. The paragraphs contain their unique id, date of creation/modification and input/output cells. An input cell contains a code or text and it’s type (markdown/visualization). Each paragraph contains an array of outputs, this is an array as execution of code can result into multiple outputs like a text with an image. Each output contains the type of output, result value and execution time.
+
+![Default Notebooks](images/Default_Notebooks_Schemav2.png)
+
+### **5.4 WorkFlows**
+
+- **Default Backend -** _View Notebooks:_ View notebooks operation is responsible for loading the sidemenu with folder tree. When user loads the plugin a call is made to the backend server. The default backend fetches all the notebooks from “.notebooks” OpenSearch index and responds with notebook Ids and paths. This response load is then used to populate the folder tree with default parser on UI.
+
+ ![View Notebook](images/default_view_notebook.png)
+
+- **Default Backend -** _Create/Edit/Delete Notebooks_: All the other notebook operations like create/delete/clone/import/export and editing paragraphs in notebooks use this workflow. When a use interacts with these notebook functionalities a backend request is made with payload [like paragraphInput, paragraphId] if necessary. The default backend first searches the “.notebooks” OpenSearch index to get the current state of the notebook. Once fetched/searched, it performs the required operation and then indexes/updates/deletes the notebook. After the successful completion of operations a response is sent back to the UI with either whole or partial notebook information (as required) and parsed by default parser taking the notebook schema into consideration.
+
+ ![View Notebook](images/default_operation_notebook.png)
+
+- **Zeppelin Adaptor -** _All Operations:_ When a user uses the Zeppelin backend adaptor for running notebooks, the backend switches its way of making requests. For any user operation including viewing notebooks in folder tree, a backend request is made by UI. This request may contain any payload [like paragraphInput, paragraphId] if necessary. This payload is reformatted and added with additional options like the user’s Zeppelin HTTP endpoint and request headers. Finally this request is sent to the user’s Zeppelin Server, which does the operation and responds back. The response is sent back to the UI with either whole or partial notebook information (as required) and parsed by Zeppelin parser taking Zeppelin’s notebook schema into consideration.
+
+ ![Zeppelin Notebook](images/zeppelin_notebooks_sequence.png)
+
+### **5.5** [API Design Documentation](API_Documentation.md)
+
+## 6. Build & Usage
+
+### **6.1** [Build Documentation](Build_Documentation.md)
+
+### **6.1** [Usage Documentation](Usage_Documentation.md)
+
+## 7. Appendix
+
+### **7.1** POC: [Embeddable API & Usage](../poc/docs/OpenSearch Dashboards_Embeddable_Documentation.md)
+
+### **7.2** POC: [Zeppelin OpenSearch Storage](../poc/docs/Zeppelin_OpenSearch_Storage.md)
+
+### **7.3** Screenshots:
+
+- **Default Backend**
+
+ - **Markdown Interpreter**
+ ![Markdown](images/Markdown_ss.png)
+ - **Embedding Saved Visualizations**
+ ![Viz](images/vizembed_ss.png)
+ - **Multi-Timeline Support**
+ ![Multi-Timeline Support](images/Multi-timeline_ss.png)
+
+- **Zeppelin Backend Adaptor**
+
+ - **Zeppelin Adaptor in OpenSearch Dashboards Notebooks**:
+ ![Sample UI](images/Zeppelin_ss.png)
+ - **Make requests to OpenSearch Service**:
+ ![OpenSearch service UI](images/opensearch_ss.png)
+ - **Transmit Data between Interpreters**:
+
+ - Use output of an OpenSearch Query as save as a Zeppelin Context in a variable
+ ![OpenSearch Query](images/opensearch_ss_zepcontext.png)
+ - Use the Zeppelin Context vairable and import it in python
+ ![Import Context](images/python_ss.png)
+
+ - **Plot Visualization with Language specific Viz. tools (like Matplotlib)**:
+ ![Matplot Viz.](images/matplot_ss.png)
+
+## 8. References
+
+### **8.1** [More Zeppelin and Backend Adaptor](Zeppelin_backend_adaptor.md)
+
+### **8.2** [Nteract.io](https://nteract.io/) React components: [components.nteract.io](https://components.nteract.io/)
diff --git a/public/components/notebooks/docs/dev/Usage_Documentation.md b/public/components/notebooks/docs/dev/Usage_Documentation.md
new file mode 100644
index 0000000000..c4fc7a3fa0
--- /dev/null
+++ b/public/components/notebooks/docs/dev/Usage_Documentation.md
@@ -0,0 +1,40 @@
+# Using OpenSearch Dashboards Notebooks
+
+## Usage & Interface
+
+![OpenSearch Dashboards Notebooks](./images/dashboards-notebooks.gif)
+
+### 1. Notebook Functionalities
+
+![OpenSearch Dashboards Notebooks](./images/notebook-buttons.png)
+
+- **Create Notebook** - creates a new notebook document
+- **Rename Notebook** - renames the current notebook with new name
+- **Clone Notebook** - clones the current notebook and gives the name
+- **Delete Notebook** - deletes the current notebook
+- **Import Notebook** - imports a notebook json file
+- **Export Notebook** - exports the current notebook as a json file
+
+### 2. Paragraph Functionalities
+
+![OpenSearch Dashboards Notebooks](./images/paragraph-buttons.png)
+NOTE: Please select a paragraph before using these buttons
+
+- **Run Paragraph** - Runs the selected paragraph and saves it
+- **Save Paragraph** - Saves the input of selected paragraph/visualization
+- **Clone Paragraph** - Clones the selected paragraph
+- **Delete Paragraph** - Deletes the selected paragraph
+- **Clear All Paragraph** - Clears the output of all the paragraphs
+- **Hide Inputs** - Hides the input cells of all the paragraphs
+- **Hide Outputs** - Hides the output cells of all the paragraphs
+
+### 3. Miscellaneous
+
+- **Adding a paragraph** - Hover between paragraphs to add a new para/visualization
+- **Editing Visualization Timeline** - Edit timeframes in datepicker to add "from" and "to" time range, then refresh the visualization
+- **Resize Visualizations** - To resize a visualization, unpin the visualization to enter the edit mode, once resized pin the visualization and save it with save button on top
+
+## Import Example Notebooks
+
+- Import sample notebooks from [example_notebooks folder](https://github.com/opensearch-project/dashboards-notebooks/tree/dev) based on your backend
+- A notebook from one backend is incompatible to the other
diff --git a/public/components/notebooks/docs/dev/Zeppelin_backend_adaptor.md b/public/components/notebooks/docs/dev/Zeppelin_backend_adaptor.md
new file mode 100644
index 0000000000..054c1a886e
--- /dev/null
+++ b/public/components/notebooks/docs/dev/Zeppelin_backend_adaptor.md
@@ -0,0 +1,129 @@
+# Zeppelin Backend Adaptor
+
+## Contents
+
+1. [**Zeppelin Backend Service**](#zeppelin-backend-service)
+2. [**Apache Zeppelin Setup**](#apache-zeppelin-setup)
+
+## Zeppelin Backend Service
+
+**Apache Zeppelin** provides several REST APIs for interaction and remote activation of zeppelin functionality. All REST APIs are available starting with the following endpoint `http://[zeppelin-server]:[zeppelin-port]/api`.
+
+![Zeppelin Server](images/zeppelin_architecture.png)
+
+1. **APIs Provided:**
+ 1. **[Server:](http://zeppelin.apache.org/docs/0.9.0/usage/rest_api/zeppelin_server.html)** Get status, version, Log Level
+ 2. **[Interpreter:](http://zeppelin.apache.org/docs/0.9.0/usage/rest_api/interpreter.html)** Get interpreter settings, create/update/restart/delete interpreter setting
+ 3. **[Notebook:](http://zeppelin.apache.org/docs/0.9.0/usage/rest_api/notebook.html)** Create/update/restart/delete note and paragraph ops
+ 4. **[Repository:](http://zeppelin.apache.org/docs/0.9.0/usage/rest_api/notebook_repository.html)** Get/Update NB repo
+ 5. **[Configuration:](http://zeppelin.apache.org/docs/0.9.0/usage/rest_api/configuration.html)** Get all [Zeppelin config](http://zeppelin.apache.org/docs/0.9.0/setup/operation/configuration.html) - server port, ssl, S3 bucket, S3.user
+ 6. **[Credential:](http://zeppelin.apache.org/docs/0.9.0/usage/rest_api/credential.html)** List credentials for all users, create/delete
+ 7. **[Helium:](http://zeppelin.apache.org/docs/0.9.0/usage/rest_api/helium.html)** Contains APIs for all plugin packages (Not needed as of now)
+2. **Security:**
+ 1. By default the APIs are exposed to anonymous user
+ 2. Recommended way to use **access control**: **[Shiro Auth](http://zeppelin.apache.org/docs/0.9.0/setup/security/shiro_authentication.html)**
+ 1. Need to change [**Shiro.ini (Apache link)**](http://shiro.apache.org/configuration.html#ini-sections) in conf directory
+ 2. Ideally should be used with [**Apache KnoxSSO**](https://knox.apache.org/books/knox-0-13-0/dev-guide.html#KnoxSSO+Integration)
+ 3. Also, [Notebooks](http://zeppelin.apache.org/docs/0.9.0/setup/security/notebook_authorization.html) can have access control based on Shiro defined users
+3. **Deployment:**
+ 1. Recommended way is to use stand alone docker
+ 2. Create a **custom docker** with new Shiro & Zeppelin configs and set interpreter config for OpenSearch and OpenSearch-sql.
+ 3. Sample scripts available in `scripts/docker/spark-cluster-managers`
+4. **Storage:**
+ 1. Apache Zeppelin has a pluggable notebook storage mechanism controlled by `zeppelin.notebook.storage` configuration option with multiple implementations.
+ 2. Zeppelin has** built-in S3/github connector**. Just provide credentials in [properties or env-sh](http://zeppelin.apache.org/docs/0.9.0/setup/storage/storage.html#notebook-storage-in-s3)
+ 3. The notebooks are automatically synced by Zeppelin
+
+## **Apache Zeppelin Setup**
+
+- https://zeppelin.apache.org/
+- Web-based notebook that enables data-driven, interactive data analytics and collaborative documents with SQL, Scala and more.
+- **[Installation Steps](http://zeppelin.apache.org/docs/0.9.0/quickstart/install.html)**
+ - http://zeppelin.apache.org/download.html → Install using Binary package with all interpreters.
+ - Unpack the downloaded tar
+ - To Run the service use `bin/zeppelin-daemon.sh start`
+ - To Stop the service use `bin/zeppelin-daemon.sh stop`
+ - Service starts on port 8080
+ - If on a remote server (like ec2) and want to use server IP to access the notebook:
+ - Make sure your inbound/outbound ports are set correctly on the remote machine
+ - You may want to change the Zeppelin host ip to 0.0.0.0 (or keep it localhost)
+ - To change the host ip use the `zeppelin-site.xml.template` inside “conf/“ directory
+ - `cp conf/zeppelin-site.xml.template conf/zeppelin-site.xml`
+ - `vi conf/zeppelin-site.xml` and edit the host ip
+ - Then restart the service
+- **[Optional] Setup OpenSearch Interpreter:**
+
+ - [Zeppelin OpenSearch interpreter Documentation](https://zeppelin.apache.org/docs/0.9.0/interpreter/elasticsearch.html)
+ - This interpreter can be used for OpenSearch:
+
+ - **Note: current issues with OpenSearch Interpreter in Zeppelin**
+ - User needs to remove ssl flag from the OpenSearch config as Zeppelin doesn’t support ssl request yet: https://issues.apache.org/jira/browse/ZEPPELIN-2031 so run the OpenSearch service without ssl enabled
+ - Zeppelin has “no support for ssl” (only uses http) in elastic interpreter:
+ - [Code](https://github.com/apache/zeppelin/blob/0b8423c62ae52f3716d4bb63d60762fee6910788/elasticsearch/src/main/java/org/apache/zeppelin/elasticsearch/client/HttpBasedClient.java#L105)
+ - [Apache Issues](https://issues.apache.org/jira/browse/ZEPPELIN-2031)
+ - Zeppelin has “no issue in search query” in elastic interpreter:
+ - [Apache Issues](https://issues.apache.org/jira/browse/ZEPPELIN-4843?jql=project%20%3D%20ZEPPELIN%20AND%20status%20%3D%20Open%20AND%20text%20~%20%22elasticsearch%22)
+ - Zeppelin “No support for search template“ issue in elastic interpreter:
+ - [Apache Issues](https://issues.apache.org/jira/browse/ZEPPELIN-4184?jql=project%20%3D%20ZEPPELIN%20AND%20text%20~%20%22elastic%20search%22)
+ - **To Change the interpreter settings of Elastic Search Interpreter on Zeppelin:**
+ - Open Zeppelin in browser `localhost:8080`
+ - Please click the top right menu beside drop down and select interpreter option
+ - In the interpreters window, search for elasticsearch interpreter
+ - Edit config parameters similar to that your local/remote service
+ - You’ll be prompted to restart the interpreter -> Click on ok
+ - **If using the default settings, add below mentioned changes in interpreter config:**
+
+ - Change transport.type to http
+ - host → localhost (if running on same machine as Zeppelin) & port → 9200
+ - username: admin & password: admin
+ - Once configured the screen should look like this:
+ ![OpenSearch Interpreter](images/opensearch-zeppelin.png)
+
+ - Start a new notebook to try out the below commands
+ - Run a shell command from notebook to check availability of OpenSearch:
+ - `%sh curl -XGET http://localhost:9200 -u admin:admin`
+
+```
+%elasticsearch
+index movies/default/1 {
+ "title": "The Godfather",
+ "director": "Francis Ford Coppola",
+ "year": 1972,
+ "genres": ["Crime", "Drama"],
+ "rating":5
+}
+```
+
+- **[Optional] Setup OpenSearch-SQL JDBC Interpreter:**
+ - [Zeppelin JDBC Interpreter Documentation](https://zeppelin.apache.org/docs/0.9.0/interpreter/jdbc.html)
+ - Zeppelin has a generic JDBC interpreter, we can use this to add our OpenSearch-SQL Driver
+ - Download [OpenSearch-SQL Driver](https://opensearch.org/) Jar file
+ - To Use JDBC interpreter:
+ - **To add the JDBC interpreter settings for OpenSearch-SQL:**
+ - Open Zeppelin in browser `localhost:8080`
+ - Please click the top right menu beside drop down and select interpreter option
+ - Click on "+ Create" Button
+ - Add OpenSearch-SQL interpreter with type JDBC **configure name: “opensearchsql”**
+ - Note: The name you assign to the interpreter is used later for accessing paragraphs in notebook - “%opensearchsql”
+ - Edit config for with OpenSearch-SQL Driver details (Please refer to the [Github README](https://github.com/opensearch-project/sql/tree/main/sql-jdbc))
+ - **If using the default settings, add below mentioned changes in interpreter config:**
+ - Edit the url: `jdbc:elasticsearch://localhost:9200`
+ - Edit the driver class: `org.opensearch.jdbc.Driver`
+ - Edit the username to admin
+ - Edit the password to admin
+ - Add absolute path to the Jar in the last input box
+ - You’ll be prompted to restart the interpreter -> Click on ok
+ - Once configured the screen should look like this:
+ ![SQL Interpreter](images/opensearch-zeppelin-settings.png)
+
+ - Open a notebook and run below commands to check if interpreter settings are set correctly
+
+```
+%opensearchsql
+SELECT * FROM movies
+```
+
+- **Appendix:**
+ - **[More on Zeppelin UI](http://zeppelin.apache.org/docs/latest/quickstart/explore_ui.html)**
+ - [**More on Zeppelin Config**](http://zeppelin.apache.org/docs/latest/setup/operation/configuration.html)
+ - [**S3-Notebook Storage**](http://zeppelin.apache.org/docs/0.8.2/setup/storage/storage.html#notebook-storage-in-s3)
diff --git a/public/components/notebooks/docs/dev/images/Default_Notebooks_Schemav2.png b/public/components/notebooks/docs/dev/images/Default_Notebooks_Schemav2.png
new file mode 100644
index 0000000000..8a0e2b5ed1
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/Default_Notebooks_Schemav2.png differ
diff --git a/public/components/notebooks/docs/dev/images/Embeddable_API.png b/public/components/notebooks/docs/dev/images/Embeddable_API.png
new file mode 100644
index 0000000000..e24715664e
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/Embeddable_API.png differ
diff --git a/public/components/notebooks/docs/dev/images/Markdown_ss.png b/public/components/notebooks/docs/dev/images/Markdown_ss.png
new file mode 100644
index 0000000000..80c9aa7887
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/Markdown_ss.png differ
diff --git a/public/components/notebooks/docs/dev/images/Multi-timeline_ss.png b/public/components/notebooks/docs/dev/images/Multi-timeline_ss.png
new file mode 100644
index 0000000000..b349d96cab
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/Multi-timeline_ss.png differ
diff --git a/public/components/notebooks/docs/dev/images/Notebooks_v1.png b/public/components/notebooks/docs/dev/images/Notebooks_v1.png
new file mode 100644
index 0000000000..9e246ad32f
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/Notebooks_v1.png differ
diff --git a/public/components/notebooks/docs/dev/images/Notebooks_v2.png b/public/components/notebooks/docs/dev/images/Notebooks_v2.png
new file mode 100644
index 0000000000..825c924cc1
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/Notebooks_v2.png differ
diff --git a/public/components/notebooks/docs/dev/images/Notebooks_v3.png b/public/components/notebooks/docs/dev/images/Notebooks_v3.png
new file mode 100644
index 0000000000..752e1b2527
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/Notebooks_v3.png differ
diff --git a/public/components/notebooks/docs/dev/images/UI.png b/public/components/notebooks/docs/dev/images/UI.png
new file mode 100644
index 0000000000..a8716452aa
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/UI.png differ
diff --git a/public/components/notebooks/docs/dev/images/Zeppelin_ss.png b/public/components/notebooks/docs/dev/images/Zeppelin_ss.png
new file mode 100644
index 0000000000..7efd3c8544
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/Zeppelin_ss.png differ
diff --git a/public/components/notebooks/docs/dev/images/dashboards-notebooks.gif b/public/components/notebooks/docs/dev/images/dashboards-notebooks.gif
new file mode 100644
index 0000000000..2439e1ab01
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/dashboards-notebooks.gif differ
diff --git a/public/components/notebooks/docs/dev/images/dashboards_notebooks_ss.png b/public/components/notebooks/docs/dev/images/dashboards_notebooks_ss.png
new file mode 100644
index 0000000000..e230c1ed7c
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/dashboards_notebooks_ss.png differ
diff --git a/public/components/notebooks/docs/dev/images/default_backend_model.png b/public/components/notebooks/docs/dev/images/default_backend_model.png
new file mode 100644
index 0000000000..954e18f0f7
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/default_backend_model.png differ
diff --git a/public/components/notebooks/docs/dev/images/default_operation_notebook.png b/public/components/notebooks/docs/dev/images/default_operation_notebook.png
new file mode 100644
index 0000000000..122765d9a1
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/default_operation_notebook.png differ
diff --git a/public/components/notebooks/docs/dev/images/default_view_notebook.png b/public/components/notebooks/docs/dev/images/default_view_notebook.png
new file mode 100644
index 0000000000..631288692c
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/default_view_notebook.png differ
diff --git a/public/components/notebooks/docs/dev/images/matplot_ss.png b/public/components/notebooks/docs/dev/images/matplot_ss.png
new file mode 100644
index 0000000000..91efc0c22a
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/matplot_ss.png differ
diff --git a/public/components/notebooks/docs/dev/images/notebook-buttons.png b/public/components/notebooks/docs/dev/images/notebook-buttons.png
new file mode 100644
index 0000000000..30bc67dcd4
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/notebook-buttons.png differ
diff --git a/public/components/notebooks/docs/dev/images/opensearch-zeppelin-settings.png b/public/components/notebooks/docs/dev/images/opensearch-zeppelin-settings.png
new file mode 100644
index 0000000000..ee05b5ced3
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/opensearch-zeppelin-settings.png differ
diff --git a/public/components/notebooks/docs/dev/images/opensearch-zeppelin.png b/public/components/notebooks/docs/dev/images/opensearch-zeppelin.png
new file mode 100644
index 0000000000..479be39c28
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/opensearch-zeppelin.png differ
diff --git a/public/components/notebooks/docs/dev/images/opensearch_ss.png b/public/components/notebooks/docs/dev/images/opensearch_ss.png
new file mode 100644
index 0000000000..fc6317879b
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/opensearch_ss.png differ
diff --git a/public/components/notebooks/docs/dev/images/opensearch_ss_zepcontext.png b/public/components/notebooks/docs/dev/images/opensearch_ss_zepcontext.png
new file mode 100644
index 0000000000..5a0ab2b944
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/opensearch_ss_zepcontext.png differ
diff --git a/public/components/notebooks/docs/dev/images/paragraph-buttons.png b/public/components/notebooks/docs/dev/images/paragraph-buttons.png
new file mode 100644
index 0000000000..9b1f159f46
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/paragraph-buttons.png differ
diff --git a/public/components/notebooks/docs/dev/images/python_ss.png b/public/components/notebooks/docs/dev/images/python_ss.png
new file mode 100644
index 0000000000..297c7ed091
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/python_ss.png differ
diff --git a/public/components/notebooks/docs/dev/images/vizembed_ss.png b/public/components/notebooks/docs/dev/images/vizembed_ss.png
new file mode 100644
index 0000000000..d3c89b471a
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/vizembed_ss.png differ
diff --git a/public/components/notebooks/docs/dev/images/zeppelin_architecture.png b/public/components/notebooks/docs/dev/images/zeppelin_architecture.png
new file mode 100644
index 0000000000..cc1a64e70c
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/zeppelin_architecture.png differ
diff --git a/public/components/notebooks/docs/dev/images/zeppelin_notebooks_sequence.png b/public/components/notebooks/docs/dev/images/zeppelin_notebooks_sequence.png
new file mode 100644
index 0000000000..27d4c50331
Binary files /dev/null and b/public/components/notebooks/docs/dev/images/zeppelin_notebooks_sequence.png differ
diff --git a/public/components/notebooks/docs/example_notebooks/default/Introduction Notebook.json b/public/components/notebooks/docs/example_notebooks/default/Introduction Notebook.json
new file mode 100644
index 0000000000..a0667d3c78
--- /dev/null
+++ b/public/components/notebooks/docs/example_notebooks/default/Introduction Notebook.json
@@ -0,0 +1 @@
+{"id":"note_97f67897-2786-48de-8f89-a3e4ffbf82b7","dateCreated":"2020-08-21T04:14:37.422Z","name":"Introduction Notebook","dateModified":"2020-08-21T04:18:47.576Z","pluginVersion":"7.9.0","backend":"Default","paragraphs":[{"output":[{"result":"## Hi Everyone,\n### Here's an intro to **OpenSearch Dashboards Notebooks**\n* You may use the top left buttons to create, rename, clone, delete, import and export with notebooks \n* Inner top left buttons are used to run, save, clone, delete the selected paragraph. \n* Long hover over the buttons to see Tooltip helpers","outputType":"MARKDOWN","execution_time":"0s"}],"input":{"inputText":"## Hi Everyone,\n### Here's an intro to **OpenSearch Dashboards Notebooks**\n* You may use the top left buttons to create, rename, clone, delete, import and export with notebooks \n* Inner top left buttons are used to run, save, clone, delete the selected paragraph. \n* Long hover over the buttons to see Tooltip helpers","inputType":"MARKDOWN"},"dateCreated":"2020-08-21T04:14:37.422Z","dateModified":"2020-08-21T04:15:02.395Z","id":"paragraph_51ff08eb-1fac-4198-8988-eba18de27440"},{"output":[{"result":"## Greetings!\n* The notebooks are stored in elasticsearch index\n* Yay! you may import and export me as json files\n* **Run** a paragraph with a keyboard shortcut **\"Shift+Enter\"**\n* The default backend supports **markdown** and **saved visualizations**","outputType":"MARKDOWN","execution_time":"0s"}],"input":{"inputText":"## Greetings!\n* The notebooks are stored in elasticsearch index\n* Yay! you may import and export me as json files\n* **Run** a paragraph with a keyboard shortcut **\"Shift+Enter\"**\n* The default backend supports **markdown** and **saved visualizations**","inputType":"MARKDOWN"},"dateCreated":"2020-08-21T04:15:06.311Z","dateModified":"2020-08-21T04:18:27.636Z","id":"paragraph_bb4e4188-0d9f-44ed-b0ea-e37c4f6293be"},{"output":[{"result":"### Hover between paragraphs to add a Saved Visualization or a New Paragraph\n2. **Unpin** the container to *edit the size* or *delete it*\n3. **Refresh** the container after *date is changed*\n","outputType":"MARKDOWN","execution_time":"0s"}],"input":{"inputText":"### Hover between paragraphs to add a Saved Visualization or a New Paragraph\n2. **Unpin** the container to *edit the size* or *delete it*\n3. **Refresh** the container after *date is changed*\n","inputType":"MARKDOWN"},"dateCreated":"2020-08-21T04:18:31.129Z","dateModified":"2020-08-21T04:18:38.923Z","id":"paragraph_7521a92a-1390-4e12-9b69-75de5878791f"},{"output":[{"result":"# Start typing here","outputType":"MARKDOWN","execution_time":"0s"}],"input":{"inputText":"# Start typing here","inputType":"MARKDOWN"},"dateCreated":"2020-08-21T04:18:45.508Z","dateModified":"2020-08-21T04:18:47.576Z","id":"paragraph_8a1a37a2-f759-4f28-8dfd-0c3210edc23b"}]}
diff --git a/public/components/notebooks/docs/example_notebooks/zeppelin/Introduction Notebook-Zeppelin.json b/public/components/notebooks/docs/example_notebooks/zeppelin/Introduction Notebook-Zeppelin.json
new file mode 100644
index 0000000000..90e3c157fe
--- /dev/null
+++ b/public/components/notebooks/docs/example_notebooks/zeppelin/Introduction Notebook-Zeppelin.json
@@ -0,0 +1 @@
+{"paragraphs":[{"text":"%md \n\n## Hi Everyone,\n### Here's an intro to **OpenSearch Dashboards Notebooks**\n* You may use the top left buttons to create, rename, clone, delete, import and export with notebooks \n* Inner top left buttons are used to run, save, clone, delete the selected paragraph. \n* Long hover over the buttons to see Tooltip helpers","user":"anonymous","dateUpdated":"2020-08-21 00:55:58.360","config":{},"settings":{"params":{},"forms":{}},"results":{"code":"SUCCESS","msg":[{"type":"HTML","data":"\n
Hi Everyone, \n
Here’s an intro to OpenSearch Dashboards Notebooks \n
\nYou may use the top left buttons to create, rename, clone, delete, import and export with notebooks \nInner top left buttons are used to run, save, clone, delete the selected paragraph. \nLong hover over the buttons to see Tooltip helpers \n \n\n
"}]},"apps":[],"runtimeInfos":{},"progressUpdateIntervalMs":500,"jobName":"paragraph_1597958104590_901298942","id":"paragraph_1596519508360_932236116","dateCreated":"2020-08-20 21:15:04.590","dateStarted":"2020-08-21 00:55:58.362","dateFinished":"2020-08-21 00:55:58.368","status":"FINISHED"},{"title":"CODE","text":"%md\n\n## Greetings!\n* Yay! you may import and export me as json files\n* **Run** a paragraph with a keyboard shortcut **\"Shift+Enter\"**\n* In Zeppelin each paragraph has to have a \"%[interpreter]\" header (like %md in this paragraph)","user":"anonymous","dateUpdated":"2020-08-21 01:08:56.942","config":{},"settings":{"params":{},"forms":{}},"results":{"code":"SUCCESS","msg":[{"type":"HTML","data":"\n
Greetings! \n
\nYay! you may import and export me as json files \nRun a paragraph with a keyboard shortcut “Shift+Enter” \nIn Zeppelin each paragraph has to have a “%[interpreter]” header (like %md in this paragraph) \n \n\n
"}]},"apps":[],"runtimeInfos":{},"progressUpdateIntervalMs":500,"jobName":"paragraph_1597972120089_1145163794","id":"paragraph_1597972120089_1145163794","dateCreated":"2020-08-21 01:08:40.089","dateStarted":"2020-08-21 01:08:56.944","dateFinished":"2020-08-21 01:08:56.952","status":"FINISHED"},{"title":"Paragraph inserted","text":"%md\n\n## Now that you are using Zeppelin \n* Checkout how to [setup other interpreters](https://zeppelin.apache.org/docs/0.9.0/#available-interpreters)\n* To setup Elasticsearch interpreter and OpenSearch-SQL interpreters [checkout](https://github.com/opensearch-project/dashboards-notebooks/blob/dev/docs/dev/Zeppelin_backend_adaptor.md#apache-zeppelin-setup)\n","user":"anonymous","dateUpdated":"2020-08-21 01:08:52.286","config":{},"settings":{"params":{},"forms":{}},"results":{"code":"SUCCESS","msg":[{"type":"HTML","data":"\n
Now that you are using Zeppelin \n
\n\n
"}]},"apps":[],"runtimeInfos":{},"progressUpdateIntervalMs":500,"jobName":"paragraph_1597958104590_1715920734","id":"paragraph_1596742076640_674206137","dateCreated":"2020-08-20 21:15:04.590","dateStarted":"2020-08-21 01:08:52.288","dateFinished":"2020-08-21 01:08:52.295","status":"FINISHED"},{"title":"Paragraph inserted","text":"%md\n\n### Hover between paragraphs to add a Saved Visualization or a New Paragraph\n2. **Unpin** the container to *edit the size* or *delete it*\n3. **Refresh** the container after *date is changed*","user":"anonymous","dateUpdated":"2020-08-21 01:09:14.147","config":{},"settings":{"params":{},"forms":{}},"results":{"code":"SUCCESS","msg":[{"type":"HTML","data":"\n
Hover between paragraphs to add a Saved Visualization or a New Paragraph \n
\nUnpin the container to edit the size or delete it \nRefresh the container after date is changed \n \n\n
"}]},"apps":[],"runtimeInfos":{},"progressUpdateIntervalMs":500,"jobName":"paragraph_1597958104590_931410594","id":"paragraph_1596524302932_2112910756","dateCreated":"2020-08-20 21:15:04.590","dateStarted":"2020-08-21 01:09:14.149","dateFinished":"2020-08-21 01:09:14.160","status":"FINISHED"},{"title":"CODE","text":"%md\n\n# Start typing here","user":"anonymous","dateUpdated":"2020-08-21 00:56:41.827","config":{},"settings":{"params":{},"forms":{}},"results":{"code":"SUCCESS","msg":[{"type":"HTML","data":"\n
Start typing here \n\n"}]},"apps":[],"runtimeInfos":{},"progressUpdateIntervalMs":500,"jobName":"paragraph_1597971380477_32105829","id":"paragraph_1597971380477_32105829","dateCreated":"2020-08-21 00:56:20.477","dateStarted":"2020-08-21 00:56:41.830","dateFinished":"2020-08-21 00:56:41.836","status":"FINISHED"}],"name":"Introduction Notebook-Zeppelin","id":"2FJH8PW8K","defaultInterpreterGroup":"spark","version":"0.9.0-preview2","noteParams":{},"noteForms":{},"angularObjects":{},"config":{"isZeppelinNotebookCronEnable":false},"info":{}}
diff --git a/public/components/notebooks/docs/example_notebooks/zeppelin/Log Analysis-Zeppelin.json b/public/components/notebooks/docs/example_notebooks/zeppelin/Log Analysis-Zeppelin.json
new file mode 100644
index 0000000000..61571248e3
--- /dev/null
+++ b/public/components/notebooks/docs/example_notebooks/zeppelin/Log Analysis-Zeppelin.json
@@ -0,0 +1 @@
+{"paragraphs":[{"title":"CODE","text":"%md\n## Let's use Zeppelin Adaptor to explore data with Inter-Para Communication\n* Before diving into this notebook make sure:\n * You have integrated [**Sample web logs**](https://www.elastic.co/guide/en/kibana/7.8/getting-started.html#get-data-in)\n * You have used the **Introduction Notebook**\n * You have setup a [**python interpreter**](https://zeppelin.apache.org/docs/0.9.0/interpreter/python.html) & [**OpenSearch-SQL interpreter**](https://github.com/opensearch-project/dashboards-notebooks/blob/dev/docs/dev/Zeppelin_backend_adaptor.md#apache-zeppelin-setup)","user":"anonymous","dateUpdated":"2020-08-21 01:07:36.617","config":{},"settings":{"params":{},"forms":{}},"results":{"code":"SUCCESS","msg":[{"type":"HTML","data":"\n
Let’s use Zeppelin Adaptor to explore data with Inter-Para Communication \n
\nBefore diving into this notebook make sure:\n\n \n \n\n
"}]},"apps":[],"runtimeInfos":{},"progressUpdateIntervalMs":500,"jobName":"paragraph_1597970420851_2109527240","id":"paragraph_1597970420851_2109527240","dateCreated":"2020-08-21 00:40:20.851","dateStarted":"2020-08-21 01:07:36.619","dateFinished":"2020-08-21 01:07:36.626","status":"FINISHED"},{"title":"CODE","text":"%md\n## We'll use the pre-indexed sample web logs provided by OpenSearch Dashboards \n* Make an OpenSearch-SQL query \n* Import the output of SQL query in a python paragraph\n* Plot an anomaly graph using python-matplot","user":"anonymous","dateUpdated":"2020-08-21 00:58:02.620","config":{},"settings":{"params":{},"forms":{}},"results":{"code":"SUCCESS","msg":[{"type":"HTML","data":"\n
We’ll use the pre-indexed sample web logs provided by OpenSearch Dashboards \n
\nMake an OpenSearch-SQL query \nImport the output of SQL query in a python paragraph \nPlot an anomaly graph using python-matplot \n \n\n
"}]},"apps":[],"runtimeInfos":{},"progressUpdateIntervalMs":500,"jobName":"paragraph_1597971322703_978148592","id":"paragraph_1597971322703_978148592","dateCreated":"2020-08-21 00:55:22.703","dateStarted":"2020-08-21 00:58:02.629","dateFinished":"2020-08-21 00:58:02.634","status":"FINISHED"},{"title":"Paragraph inserted","text":"%md\n**OpenSearch-SQL Query to fetch size of request and agent data for all the web requests made**\nSelect bytes,agent from opensearch_dashboards_sample_data_logs\n","user":"anonymous","dateUpdated":"2020-08-20 21:16:13.576","config":{"editorSetting":{"language":"scala","editOnDblClick":false,"completionKey":"TAB","completionSupport":true},"colWidth":12,"editorMode":"ace/mode/scala","fontSize":9,"results":{},"enabled":true},"settings":{"params":{},"forms":{}},"results":{"code":"SUCCESS","msg":[{"type":"HTML","data":"\n
OpenSearch-SQL Query to fetch size of request and agent data for all the web requests made \nSelect bytes,agent from opensearch_dashboards_sample_data_logs
\n\n
"}]},"apps":[],"runtimeInfos":{},"progressUpdateIntervalMs":500,"jobName":"paragraph_1597958173576_437396150","id":"paragraph_1591897831553_-310393619","dateCreated":"2020-08-20 21:16:13.576","status":"READY"},{"title":"Paragraph inserted","text":"%opensearchsql(saveAs=data_logs)\nselect bytes,agent from opensearch_dashboards_sample_data_logs","user":"anonymous","dateUpdated":"2020-08-20 21:16:13.576","config":{"saveAs":"opensearch_dashboards_sample_data_logs","editorSetting":{"language":"sql","editOnDblClick":false,"completionKey":"TAB","completionSupport":true},"colWidth":12,"editorMode":"ace/mode/sql","fontSize":9,"results":{"0":{"graph":{"mode":"table","height":300,"optionOpen":false,"setting":{"table":{"tableGridState":{},"tableColumnTypeState":{"names":{"bytes":"string","agent":"string"},"updated":false},"tableOptionSpecHash":"[{\"name\":\"useFilter\",\"valueType\":\"boolean\",\"defaultValue\":false,\"widget\":\"checkbox\",\"description\":\"Enable filter for columns\"},{\"name\":\"showPagination\",\"valueType\":\"boolean\",\"defaultValue\":false,\"widget\":\"checkbox\",\"description\":\"Enable pagination for better navigation\"},{\"name\":\"showAggregationFooter\",\"valueType\":\"boolean\",\"defaultValue\":false,\"widget\":\"checkbox\",\"description\":\"Enable a footer for displaying aggregated values\"}]","tableOptionValue":{"useFilter":false,"showPagination":false,"showAggregationFooter":false},"updated":false,"initialized":false}},"commonSetting":{}}}},"enabled":true},"settings":{"params":{},"forms":{}},"results":{"code":"SUCCESS","msg":[{"type":"TABLE","data":"bytes\tagent\n6219\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n6850\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n0\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n14113\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n2492\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n0\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n1872\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n4531\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n3629\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n9797\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n9920\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n6936\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n8489\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n2860\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n8535\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n4529\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n9888\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n5919\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n9890\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n3039\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n8766\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n8261\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n5028\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n8130\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n9934\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n3314\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n2492\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n1950\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n0\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n8489\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n9029\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n2860\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n8120\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n3930\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n0\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n3464\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n8535\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n17403\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n9773\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n875\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n18082\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n6514\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n8323\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n8364\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n6274\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n2108\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n7174\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n5846\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n7594\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n7169\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n9338\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n9217\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n8390\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n9101\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n6936\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n4634\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n8909\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n7343\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n4939\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n55\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n1778\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n8996\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n5197\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n2153\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n5223\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n178\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n5400\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n8676\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n6960\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n18409\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n2441\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n3010\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n9263\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n3853\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n4238\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n2377\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n8928\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n6193\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n2372\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n6942\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n173\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n4877\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n15894\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n7468\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n5481\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n6920\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n9920\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n5476\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n2432\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n2034\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n9021\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n7719\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n4037\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n17598\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n6312\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n5835\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n2647\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n8655\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n17357\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n4064\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n3034\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n1634\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n3807\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n8738\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n3629\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n9446\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n7182\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n2159\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n4861\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n3317\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n8663\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n1793\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n6648\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n3307\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n5052\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n4531\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n8995\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n4579\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n8522\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n7304\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n255\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n9052\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n6795\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n6739\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n7936\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n7309\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n6254\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n2453\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n3378\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n9375\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n1685\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n0\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n0\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n4154\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n5919\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n4633\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n3039\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n5375\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n5424\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n14113\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n3841\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n1638\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n0\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n5861\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n3994\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n1828\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n4529\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n5321\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n15990\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n4806\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n4072\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n4617\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n9486\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n9888\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n7193\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n0\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n6429\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n8648\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n7377\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n9371\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n8590\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n2765\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n9424\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n0\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n9716\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n1858\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n2432\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n9797\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n2999\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n6817\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n4842\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n16227\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n1603\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n19561\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n1936\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n5540\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n7085\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n5767\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n2053\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n4061\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n7675\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n0\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n979\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n685\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n6509\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n8723\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n9414\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n3086\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n1872\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n9174\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n5073\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n10103\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n7531\tMozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\n5988\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n7009\tMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\n6540\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n0\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n9952\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n7873\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n3050\tMozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Gecko/20110421 Firefox/6.0a1\n"}]},"apps":[],"runtimeInfos":{},"progressUpdateIntervalMs":500,"jobName":"paragraph_1597958173576_876823109","id":"paragraph_1591897481776_702487776","dateCreated":"2020-08-20 21:16:13.576","status":"READY"},{"title":"Paragraph inserted","text":"%md\n**Import this query output in python**\n","user":"anonymous","dateUpdated":"2020-08-20 21:16:13.577","config":{"tableHide":false,"editorSetting":{"language":"markdown","editOnDblClick":true,"completionSupport":false},"colWidth":12,"editorMode":"ace/mode/markdown","fontSize":9,"editorHide":true,"results":{},"enabled":true},"settings":{"params":{},"forms":{}},"results":{"code":"SUCCESS","msg":[{"type":"HTML","data":"\n
Import this query output in python
\n\n
"}]},"apps":[],"runtimeInfos":{},"progressUpdateIntervalMs":500,"jobName":"paragraph_1597958173576_599341048","id":"paragraph_1591897902017_-1544489575","dateCreated":"2020-08-20 21:16:13.577","status":"READY"},{"title":"Paragraph inserted","text":"%python.ipython\n%matplotlib inline\nlogs = z.getAsDataFrame('data_logs')\nlogs","user":"anonymous","dateUpdated":"2020-08-20 21:16:13.577","config":{"editorSetting":{"language":"scala","editOnDblClick":false,"completionKey":"TAB","completionSupport":true},"colWidth":12,"editorMode":"ace/mode/scala","fontSize":9,"results":{},"enabled":true},"settings":{"params":{},"forms":{}},"results":{"code":"SUCCESS","msg":[{"type":"HTML","data":"\n\n
\n \n \n \n bytes \n agent \n \n \n \n \n 0 \n 6219 \n Mozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Geck... \n \n \n 1 \n 6850 \n Mozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Geck... \n \n \n 2 \n 0 \n Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.... \n \n \n 3 \n 14113 \n Mozilla/4.0 (compatible; MSIE 6.0; Windows NT ... \n \n \n 4 \n 2492 \n Mozilla/4.0 (compatible; MSIE 6.0; Windows NT ... \n \n \n ... \n ... \n ... \n \n \n 195 \n 6540 \n Mozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Geck... \n \n \n 196 \n 0 \n Mozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Geck... \n \n \n 197 \n 9952 \n Mozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Geck... \n \n \n 198 \n 7873 \n Mozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Geck... \n \n \n 199 \n 3050 \n Mozilla/5.0 (X11; Linux x86_64; rv:6.0a1) Geck... \n \n \n
\n
200 rows × 2 columns
\n
"}]},"apps":[],"runtimeInfos":{},"progressUpdateIntervalMs":500,"jobName":"paragraph_1597958173577_325755404","id":"paragraph_1591898708896_1841265952","dateCreated":"2020-08-20 21:16:13.577","status":"READY"},{"title":"Paragraph inserted","text":"\n%md\n**Plot a scatter graph for requests made per browser using matplot**\n","user":"anonymous","dateUpdated":"2020-08-20 21:16:13.577","config":{"editorSetting":{"language":"scala","editOnDblClick":false,"completionKey":"TAB","completionSupport":true},"colWidth":12,"editorMode":"ace/mode/scala","fontSize":9,"results":{},"enabled":true},"settings":{"params":{},"forms":{}},"results":{"code":"SUCCESS","msg":[{"type":"HTML","data":"\n
Plot a scatter graph for requests made per browser using matplot
\n\n
"}]},"apps":[],"runtimeInfos":{},"progressUpdateIntervalMs":500,"jobName":"paragraph_1597958173577_2096035472","id":"paragraph_1591899582298_-864868294","dateCreated":"2020-08-20 21:16:13.577","status":"READY"},{"title":"Paragraph inserted","text":"%python.ipython\n\n%matplotlib inline\n\nimport warnings\nimport numpy as np\nwarnings.filterwarnings(\"ignore\")\nimport matplotlib.pyplot as plt\n\nlogs = z.getAsDataFrame('data_logs')\nagent_with_firefox = logs['agent'].str.count('Firefox').values\nfirefox_bytes = logs['bytes'].values[agent_with_firefox==1]\n\nagent_with_chrome_safari = logs['agent'].str.count('Chrome').values\nchrome_bytes = logs['bytes'].values[agent_with_chrome_safari==1]\n\nagent_with_msie = logs['agent'].str.count('MSIE').values\nmsie_bytes = logs['bytes'].values[agent_with_msie==1]\n\nprint(\"Total Requests:\", len(agent_with_firefox))\nprint(\"# Requests from Firefox Browser\", np.sum(agent_with_firefox))\nprint(\"# Requests from Chrome/Safari Browser\", np.sum(agent_with_chrome_safari))\nprint(\"# Requests from MSIE Browser\", np.sum(agent_with_msie), \"\\n\\n\")\n\nplt.figure(num=None, figsize=(30, 6))\nplt.title(\"Request size for each browser\")\nplt.ylabel('Request Size in Bytes')\nplt.xlabel('Requests made')\nplt.axhline(y=10000, color='r', linestyle='--')\nplt.plot(msie_bytes, 'ro', markersize=5, label=\"MSIE\")\nplt.plot(firefox_bytes, 'bo', markersize=5, label=\"Firefox\")\nplt.plot(chrome_bytes, 'go', markersize=5, label=\"Chrome\")\nplt.legend()\n\n\n\n\n \n","user":"anonymous","dateUpdated":"2020-08-20 21:16:13.577","config":{"editorSetting":{"language":"python","editOnDblClick":false,"completionKey":"TAB","completionSupport":true},"colWidth":12,"editorMode":"ace/mode/python","fontSize":9,"results":{},"enabled":true},"settings":{"params":{},"forms":{}},"results":{"code":"SUCCESS","msg":[{"type":"TEXT","data":"Total Requests: 200\n# Requests from Firefox Browser 86\n# Requests from Chrome/Safari Browser 54\n# Requests from MSIE Browser 60 \n\n\n\n"},{"type":"IMG","data":"iVBORw0KGgoAAAANSUhEUgAABs0AAAGDCAYAAABgLF6CAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjMsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+AADFEAAAgAElEQVR4nOzdfXxcZZ3w/8+3U0oxEQSsAq3YSkEBhUSKcXVRlIc4GB5cWaEKVFll8WHVvX1kb9Zqyy56q/f6w1VWXAERtuINPmB1NiBaQIVoamJBUShYpaWFCiuQ8FA6vX5/nJMyadMkbWcyk+Tzfr3mdc65ztP3zJxMzpzvua4rUkpIkiRJkiRJkiRJk9mUegcgSZIkSZIkSZIk1ZtJM0mSJEmSJEmSJE16Js0kSZIkSZIkSZI06Zk0kyRJkiRJkiRJ0qRn0kySJEmSJEmSJEmTnkkzSZIkSZIkSZIkTXomzSRJkiRpjEXEURHx+xps94KI+HNErKv2tqslIi6PiAtGuezsiEgRMbXWcUmSJEmSSTNJkiRJDSEiVkXEExHRFxHr8uRKc73j2paIODoiVu/IuimlW1JKL65yPC8APgQcklLap5rbliRJkqTJwKSZJEmSpEZyYkqpGWgBWoHz6hzPePJC4KGU0oPbu+JEqcnVaMcREYV6xyBJkiRp9EyaSZIkSWo4KaV1QCdZ8gyAiNg1Ij4XEX+KiAci4j8iYreK+R+JiLURcX9EnJ036zc3n7csIt5ZsezbI+KnFdMviYgbIuLhiPh9RLylYt4JEfHbiHgsItZExIcjogkoAfvlNeP6ImK/LY9jqHXz8s211CLitIpt9EXEUxGxbDTHXLGfY4EbKuK5PC8/KSJ+ExF/yd+DgyvWWRURH4uIFUD/UAmnEd6XN0ZET0Q8GhH3RcQnt1j3ryPi5/m+74uIt1fM3jMifpC/L10RccCW+97C2fnnujYiPlSxj09GxDURcWVEPAq8PX/PvpAvf38+vmu+/E0R8eaK+FJEnDDwHkZEbz4+N1/2kby5y6tH+Z5cHhEXR8QPI6IfeN0IxyVJkiSpgZg0kyRJktRwImIWUARWVhR/BjiILJE2F5gJfCJf/g3Ah4HjgAOBY7djX01kCaf/Ap4HzAe+HBGH5ot8Dfj7lNKzgZcCP04p9efx3Z9Sas5f9w+x+a3W3XKBlNLVA9sA9gPuBZaMdMxbbONHW8Tz9og4KN/OB4EZwA+B70fEtIpV5wNvBJ6TUtq4ne9LP3AW8Jx8G++OiFPydfcnSyp+Md93C9C7xX4/BexJ9hn/yxDvXaXXkX2uxwMfz5OEA04GrsnjuAr438Ar830eDrwCOD9f9ibg6Hz8NWTv9Wsrpm/KxxcD1+fxzcqPYzTvCcBb8+N5NvBTJEmSJI0bJs0kSZIkNZLvRsRjwH3Ag8BCgIgI4F3AP6aUHk4pPQb8K3B6vt5bgMtSSnfkCa1Pbsc+O4BVKaXLUkobU0q/Aq4FTs3nPw0cEhG7p5T+J58/WqNeNyKmkCVjlqWUvjKKYx7JacAPUko3pJSeBj4H7Aa8qmKZi1JK96WUnhhi/WHfl5TSspTS7SmlTSmlFWQJuoEE1NuAH6WUlqSUnk4pPZRSqkyafTul9Is8UXcVFTUKt+FTKaX+lNLtwGVkyaoBt6aUvpvH8US+70UppQdTSuvJknNn5svexOAk2YUV06/lmaTZ02TNXe6XUnoypTSQ/BrpXAH4XkrpZ3k8T45wXJIkSZIaiEkzSZIkSY3klLxW1tHAS4Dn5uUzgGcBy/Pm/v4C/HdeDlkNrfsqtvPH7djnC4G2ge3m234bsE8+/83ACcAf8yb7/mo7tr096w7UTnp/Pj3SMY9kPyreh5TSJrL3aGbFMvdtuVKFYd+XiGiLiJ9ExPqIeAQ4l2c+rxcA9wyz7XUV448DzSMcy5af7X7bmAdbHPcWy98KHBQRzydL1F0BvCAinktWI+3mfLmPAgH8Im/e8uy8fKRzZah4JEmSJI0TDdVJsiRJkiQBpJRuyvvl+hxwCvBn4Ang0JTSmiFWWUuWqBmw/xbz+8kSUAO2THLclFI6bhux/BI4OSJ2Ad4HfCvfVxrFcWxr3UEi4nSy2lNH5rXCYORjHsn9wMsq9hH5viu3NdwxDPu+kNWK+3egmFJ6MiK+wDNJs/vIklDV8gLgd/n4/mTHNmDLY7ifLLn1my2XTyk9HhHLgQ8Ad6SUNkTEz4H/BdyTUvpzvtw6slp+RMRfAz+KiJsZ+T0ZKh5JkiRJ44Q1zSRJkiQ1qi8Ax0VES15L6qvAv0XE8wAiYmZEtOfLfgt4e0QcEhHPIm/WsUIv8DcR8ayImAv8XcW8pWS1j86MiF3y15ERcXBETIuIt0XEHnky61GgnK/3ALB3ROwxVPAjrFu5XCtZn1mn5M0JAptrhg13zCP5FvDGiDgmT9p9CHgK+Pko19/m+5LPfzbwcJ4wewVZX14DrgKOjYi3RMTUiNg7IkZqgnE4/5x/docC7wCuHmbZJcD5ETEjr0H2CeDKivk3kSUwB5piXLbFNBHxt3m/egD/Q5YIKzPyeyJJkiRpHDNpJkmSJKkh5QmkK4B/zos+BqwEbouIR4EfAS/Oly2RJdl+nC/z4y0292/ABrJE19fJkjoD+3kMOJ6sr7D7yZoO/Aywa77ImcCqfJ/nAmfk6/2OLEFzb95UX2WTgQy37hZOBvYEfhoRffmrNNIxjySl9Pt8f18kq7V2InBiSmnDKNcf6X15D7Ao74PuE2RJuoF1/0TWLOWHgIfJkpaHj2a/23AT2ftwI/C5lNL1wyx7AdANrABuB36Vl1Vu69k80xTjltMARwJdEdEHXAd8IKX0h1G8J5IkSZLGsUjJliMkSZIkTTwRkYADU0or6x2LJEmSJKnxWdNMkiRJkiRJkiRJk55JM0mSJEmSJEmSJE16Ns8oSZIkSZIkSZKkSc+aZpIkSZIkSZIkSZr0TJpJkiRJkiRJkiRp0pta7wDG2nOf+9w0e/bseochSZIkSZIkSZKkMbZ8+fI/p5RmDDVv0iXNZs+eTXd3d73DkCRJkiRJkiRJ0hiLiD9ua57NM0qSJEmSJEmSJGnSM2kmSZIkSZIkSZKkSa9mSbOIeEFE/CQi7oyI30TEB/LyvSLihoi4Ox/umZdHRFwUESsjYkVEvLxiWwvy5e+OiAUV5UdExO35OhdFRNTqeCRJkiRJkiRJkjRx1bJPs43Ah1JKv4qIZwPLI+IG4O3AjSmlT0fEx4GPAx8DisCB+asNuBhoi4i9gIXAPCDl27kupfQ/+TLnALcBPwTeAJRqeEySJEmSJEmSJEl18/TTT7N69WqefPLJeofS0KZPn86sWbPYZZddRr1OzZJmKaW1wNp8/LGIuBOYCZwMHJ0v9nVgGVnS7GTgipRSAm6LiOdExL75sjeklB4GyBNvb4iIZcDuKaVb8/IrgFMwaSZJkiRJkiRJkiao1atX8+xnP5vZs2djA3xDSynx0EMPsXr1aubMmTPq9cakT7OImA20Al3A8/OE2kBi7Xn5YjOB+ypWW52XDVe+eohySZIkSZIkSZKkCenJJ59k7733NmE2jIhg77333u7aeDVPmkVEM3At8MGU0qPDLTpEWdqB8qFiOCciuiOie/369SOFLEmSJEmSJEmS1LBMmI1sR96jmibNImIXsoTZVSmlb+fFD+TNLpIPH8zLVwMvqFh9FnD/COWzhijfSkrpkpTSvJTSvBkzZuzcQUmSJEmSJEmSJE1iEcGZZ565eXrjxo3MmDGDjo4OAB544AE6Ojo4/PDDOeSQQzjhhBMAWLVqFS996UsBWLZsGXvssQctLS2bXz/60Y/G/mAq1KxPs8hSeF8D7kwp/d+KWdcBC4BP58PvVZS/LyK+CbQBj6SU1kZEJ/CvEbFnvtzxwHkppYcj4rGIeCVZs49nAV+s1fFIkiRJkiRJkiSNO+UylErQ0wOtrVAsQqGwU5tsamrijjvu4IknnmC33XbjhhtuYObMZ3rQ+sQnPsFxxx3HBz7wAQBWrFgx5HaOOuooli5dulOxVFMta5q9GjgTeH1E9OavE8iSZcdFxN3Acfk0wA+Be4GVwFeB9wCklB4GFgO/zF+L8jKAdwP/ma9zD1Cq4fFIkiRJkiap8qYyS+9ayuKbFrP0rqWUN5XrHZIkSZI0snIZ2tth/nxYuDAbtrdn5TupWCzygx/8AIAlS5Ywf/78zfPWrl3LrFnPNBZ42GGH7fT+xkLNapqllH7K0P2OARwzxPIJeO82tnUpcOkQ5d3AS3ciTEmSJEmShlXeVKb9yna61nTRv6GfpmlNtM1so/OMTgpTdu4JXUmSJKmmSiXo6oK+vmy6ry+bLpUgb0pxR51++uksWrSIjo4OVqxYwdlnn80tt9wCwHvf+15OO+00/v3f/51jjz2Wd7zjHey3335bbeOWW26hpaVl8/S1117LAQccsFNx7Yya9mkmSZIkSdJ4V1pZomtNF30b+kgk+jb00bWmi9JKGzuRJElSg+vpgf7+wWX9/dDbu9ObPuyww1i1ahVLlizZ3GfZgPb2du69917e9a538bvf/Y7W1lbWr1+/1TaOOuooent7N7/qmTADk2aSJEmSJA2rZ20P/RsG32jo39BP77qdv9EgSZIk1VRrKzQ1DS5raoKK2l0746STTuLDH/7woKYZB+y111689a1v5Rvf+AZHHnkkN998c1X2WUsmzSRJkiRJGkbrvq00TRt8o6FpWhMt+1TnRoMkSZJUM8UitLVBczNEZMO2tqy8Cs4++2w+8YlP8LKXvWxQ+Y9//GMef/xxAB577DHuuece9t9//6rss5Zq1qeZJEmSJEkTQXFukbaZbVv1aVacW50bDZIkSVLNFArQ2Zn1Ydbbm9UwKxaz8iqYNWsWH/jAB7YqX758Oe973/uYOnUqmzZt4p3vfCdHHnkkq1atGrTcln2anX/++Zx66qlViW1HREqpbjuvh3nz5qXu7u56hyFJkiRJGkfKm8qUVpboXddLyz4tFOcWKUypzo0GSZIkaXvceeedHHzwwfUOY1wY6r2KiOUppXlDLW9NM0mSJEmSRlCYUqDjoA46DuqodyiSJEmSasQ+zSRJkiRJkiRJkjTpmTSTJEmSJEmSJEnSpGfSTJIkSZIkSZIkSZOeSTNJkiRJkiRJkiRNeibNJEmSJEmSJEmSNOmZNJMkSZIkSZIkSdKoFQoFWlpaNr9WrVpFd3c373//+7d7Wx/5yEc49NBD+chHPlKDSLfP1HoHIEmSJEmSJEmSpNool6FUgp4eaG2FYhEKhZ3b5m677UZvb++gstmzZzNv3rytlt24cSNTp247HfWVr3yF9evXs+uuu+5cUFVgTTNJkiRJkiRJkqQJqFyG9naYPx8WLsyG7e1ZebUtW7aMjo4OAD75yU9yzjnncPzxx3PWWWdRLpf5yEc+wpFHHslhhx3GV77yFQBOOukk+vv7aWtr4+qrr+aPf/wjxxxzDIcddhjHHHMMf/rTnwA4+eSTueKKK4Asyfa2t72t+geANc0kSZIkSZIkSZImpFIJurqgry+b7uvLpkslyPNbO+SJJ56gpaUFgDlz5vCd73xnq2WWL1/OT3/6U3bbbTcuueQS9thjD375y1/y1FNP8epXv5rjjz+e6667jubm5s211k488UTOOussFixYwKWXXsr73/9+vvvd73LJJZfw6le/mjlz5vD5z3+e2267bceDH4ZJM0mSJEmSJEmSpAmopwf6+weX9fdDb+/OJc2Gap5xSyeddBK77bYbANdffz0rVqzgmmuuAeCRRx7h7rvvZs6cOYPWufXWW/n2t78NwJlnnslHP/pRAJ7//OezaNEiXve61/Gd73yHvfbaa8eDH4ZJM0nSxFKLRpolSZIkSZKkcai1FZqanqlpBtl0XkmsppqamjaPp5T44he/SHt7+3ZtIyI2j99+++3svffe3H///VWLcUv2aSZJmjjGspFmSZIkSZIkqcEVi9DWBs3NEJEN29qy8rHU3t7OxRdfzNNPPw3AXXfdRf+WVeCAV73qVXzzm98E4KqrruKv//qvAfjFL35BqVSip6eHz33uc/zhD3+oSZzWNJMkTRy1aqRZkiRJkiRJGocKBejszG6P9fZmNczq0TDTO9/5TlatWsXLX/5yUkrMmDGD7373u1std9FFF3H22Wfz2c9+lhkzZnDZZZfx1FNP8a53vYvLLruM/fbbj89//vOcffbZ/PjHPx5UE60aIqVU1Q02unnz5qXu7u56hyFJqoXFi7MaZpX/2yJg0SI4//z6xSVJkiRJkiRVyZ133snBBx9c7zDGhaHeq4hYnlKaN9TyNs8oSZo4BhpprjRWjTRLkiRJkiRJGtdMmknSKJQ3lVl611IW37SYpXctpbzJPrIaUqM00ixJkiRJkiRp3LFPM0kaQXlTmfYr2+la00X/hn6apjXRNrONzjM6KUwZ48Z/NbxGaaRZkiRJkiRJ0rhj0kySRlBaWaJrTRd9G/oA6NvQR9eaLkorS3Qc1FHn6LSVQgE6OrKXJEmSJEmSJI2SzTNK0gh61vbQv6F/UFn/hn561/XWKSJJkiRJkiRJUrWZNJOkEbTu20rTtKZBZU3TmmjZp6VOEUmSJEmSJEmSqs2kmSSNoDi3SNvMNpqnNRMEzdOaaZvZRnFusd6hSZIkSZIkSdKYW7duHaeffjoHHHAAhxxyCCeccAKXXHIJHeO8yxT7NJOkERSmFOg8o5PSyhK963pp2aeF4twihSmFeocmSZIkSZIkScMqbypTWlmiZ20Prfu27vS9zZQSb3rTm1iwYAHf/OY3Aejt7eX73//+6OIplykUGvPeqkkzSRqFwpQCHQd10HHQ+H5SQlLtVftCVJIkSZIkaUeVN5Vpv7KdrjVd9G/op2laE20z2+g8o3OH71f85Cc/YZddduHcc8/dXNbS0sJf/vIXbrzxRk499VTuuOMOjjjiCK688koigtmzZ3P22Wdz/fXX8773vY+XvOQlnHvuuTz++OMccMABXHrppey5554cffTRtLa2snz5ctavX88VV1zBhRdeyO23385pp53GBRdcAMCVV17JRRddxIYNG2hra+PLX/5yVRJxNWueMSIujYgHI+KOirKrI6I3f62KiN68fHZEPFEx7z8q1jkiIm6PiJURcVFERF6+V0TcEBF358M9a3UskiRJozFwITr/2vksXLaQ+dfOp/3KdsqbyvUOTZIkSZIkTUKllSW61nTRt6GPRKJvQx9da7oorSzt8DYHEmJD6enp4Qtf+AK//e1vuffee/nZz362ed706dP56U9/yumnn85ZZ53FZz7zGVasWMHLXvYyPvWpT21ebtq0adx8882ce+65nHzyyXzpS1/ijjvu4PLLL+ehhx7izjvv5Oqrr+ZnP/sZvb29FAoFrrrqqh0+nkq17NPscuANlQUppdNSSi0ppRbgWuDbFbPvGZiXUjq3ovxi4BzgwPw1sM2PAzemlA4EbsynJUmS6qYWF6KSJEmSJEk7qmdtD/0b+geV9W/op3ddb03294pXvIJZs2YxZcoUWlpaWLVq1eZ5p512GgCPPPIIf/nLX3jta18LwIIFC7j55ps3L3fSSScB8LKXvYxDDz2Ufffdl1133ZUXvehF3Hfffdx4440sX76cI488kpaWFm688UbuvffeqsRfs+YZU0o3R8TsoebltcXeArx+uG1ExL7A7imlW/PpK4BTgBJwMnB0vujXgWXAx3Y+cknSeFYuQ6kEPT3Q2grFIjRoE8magIa7ELV5V0mSJEmSNNZa922laVoTfRv6Npc1TWuiZZ+WHd7moYceyjXXXDPkvF133XXzeKFQYOPGjc/st6lpVNsf2MaUKVMGbW/KlCls3LiRlBILFizgwgsv3JHwh1XLmmbDOQp4IKV0d0XZnIjoiYibIuKovGwmsLpimdV5GcDzU0prAfLh82odtCSpsZXL0N4O8+fDwoXZsL09K5fGwsCFaKUdvRAtbyqz9K6lLL5pMUvvWmoTj5IkSZIkabsV5xZpm9lG87RmgqB5WjNtM9sozi3u8DZf//rX89RTT/HVr351c9kvf/lLbrrpplGtv8cee7Dnnntyyy23APCNb3xjc62z0TjmmGO45pprePDBBwF4+OGH+eMf/7gdR7BtNatpNoL5wJKK6bXA/imlhyLiCOC7EXEoEEOsm7Z3ZxFxDlkTj+y///47EK4kaTwolaCrC/ryB2f6+rLpUgk6rOSjMTBwIbpl57rbeyFai056JUmSJEnS5FOYUqDzjE5KK0v0ruulZZ8WinOLO3V/ISL4zne+wwc/+EE+/elPM336dGbPns0pp5wy6m18/etf59xzz+Xxxx/nRS96EZdddtmo1z3kkEO44IILOP7449m0aRO77LILX/rSl3jhC1+4I4czSKS03Tmo0W88a55xaUrppRVlU4E1wBEppdXbWG8Z8OF8uZ+klF6Sl88Hjk4p/X1E/D4fX5s347gspfTikWKaN29e6u7u3rkDkyQ1pMWLsxpmlf/aImDRIjj//PrFpcmlvKm80xeiS+9ayvxr5w9qOqF5WjNL3rzEZh4lSZIkSZrk7rzzTg4++OB6hzEuDPVeRcTylNK8oZavR/OMxwK/q0yYRcSMiCjk4y8CDgTuzZtdfCwiXpn3g3YW8L18teuABfn4gopySdIk1doKWzaN3NQELTveRLO03QpTCnQc1MH5rzmfjoM6dujJrbHupFeSJEmSJEk1TJpFxBLgVuDFEbE6Iv4un3U6g5tmBHgNsCIifg1cA5ybUno4n/du4D+BlcA9QCkv/zRwXETcDRyXT0uSJrFiEdraoLk5q2HW3JxNF3e8iWapLqrZN5okSZIkSZJGp2Z9mqWU5m+j/O1DlF0LXLuN5buBlw5R/hBwzM5FKUmaSAoF6OzM+jDr7c1qmBWLWbk0nlSrbzRJkiRJkiSNXs2SZpIk1UOhAB0d2Usar2rRSa8kSZIkSZo4UkpkvVppW1JK272OSTNJkqQGNNA3WsdBZoAlSZIkSdIzpk+fzkMPPcTee+9t4mwbUko89NBDTJ8+fbvWM2kmSZIkSZIkSZI0TsyaNYvVq1ezfv36eofS0KZPn86sWbO2ax2TZpIkSZIkSZIkSePELrvswpw5c+odxoQ0pd4BSJIkSZIkSZIkSfVm0kySJEmSJEmSJEmTnkkzSZIkSZIkSZIkTXomzSRJkiRJkiRJkjTpmTSTJEmSJEmSJEnSpGfSTJIkSZIkSZIkSZOeSTNJkiRJkiRJkiRNelPrHYAkSZIkSVJVlctQKkFPD7S2QrEIhUK9o5IkSVKDM2kmSZIkSZImjnIZ2tuhqwv6+6GpCdraoLPTxJkkSZKGZfOMkiRJkiRp4iiVsoRZXx+klA27urJySZIkaRgmzSRJkiRJ0sTR05PVMKvU3w+9vfWJR5IkSeOGzTNKkiRJkqSJo7U1a5Kxr++ZsqYmaGmpX0yqObuxkyRJ1WDSTJIk1U15U5nSyhI9a3to3beV4twihSne3ZAkSTuhWMz6MNuyT7Nisd6RqUbsxk6SJFWLSTNJklQX5U1l2q9sp2tNF/0b+mma1kTbzDY6z+g0cSZJknZcoZBlS0qlrEnGlharHU1wld3YweBu7Do66hubJEkaX+zTTJIk1UVpZYmuNV30begjkejb0EfXmi5KK0v1Dk2SJI13hUKWLTn//GxowmxCsxs7SZJULSbNJElSXfSs7aF/w+C7G/0b+uld590NSZIkjd5AN3aV7MZOkiTtCJNmkiSpLlr3baVp2uC7G03TmmjZx7sbkiRJGr2BbuyamyEiG9qNnSRJ2hH2aSZJkuqiOLdI28y2rfo0K8717oYkSZJGz27sJElStURKqd4xjKl58+al7u7ueochSZKA8qYypZUletf10rJPC8W5RQpTvLshSZIkSZKk2oiI5SmleUPNs6aZJEmqm8KUAh0HddBxUEe9Q5EkSZIkSdIkZ59mkiRJkiRJkiRJmvRMmkmSJEmSJEmSJGnSM2kmSZIkSZIkSZKkSc+kmSRJkiRJkiRJkiY9k2aSJEmSJEmSJEma9GqWNIuISyPiwYi4o6LskxGxJiJ689cJFfPOi4iVEfH7iGivKH9DXrYyIj5eUT4nIroi4u6IuDoiptXqWCRJkiRJkiRJkjSx1bKm2eXAG4Yo/7eUUkv++iFARBwCnA4cmq/z5YgoREQB+BJQBA4B5ufLAnwm39aBwP8Af1fDY5EkSZIkSZIkSdIEVrOkWUrpZuDhUS5+MvDNlNJTKaU/ACuBV+SvlSmle1NKG4BvAidHRACvB67J1/86cEpVD0CSJEmSJEmSJEmTRj36NHtfRKzIm2/cMy+bCdxXsczqvGxb5XsDf0kpbdyiXJIkSZIkSZIkSdpuY500uxg4AGgB1gKfz8tjiGXTDpQPKSLOiYjuiOhev3799kUsSZIkSZIkSZKkCW9Mk2YppQdSSuWU0ibgq2TNL0JWU+wFFYvOAu4fpvzPwHMiYuoW5dva7yUppXkppXkzZsyozsFIkiRJkiRJkiRpwhjTpFlE7Fsx+Sbgjnz8OuD0iNg1IuYABwK/AH4JHBgRcyJiGnA6cF1KKQE/AU7N118AfG8sjkGSJEmSJEmSJEkTz9SRF9kxEbEEOBp4bkSsBhYCR0dEC1lTiquAvwdIKf0mIr4F/BbYCLw3pVTOt/M+oBMoAJemlH6T7+JjwDcj4gKgB/harY5FkiRJkiRJkiRJE1tklbYmj3nz5qXu7u56hyFJkiRJkiRJkqQxFhHLU0rzhpo3ps0zSpIkSZIkSZIkSY3IpJkkSZIkSZIkSZImPZNmkiRJkiRJkiRJmvRMmkmSJEmSJEmSJGnSM2kmSZIkSZIkSZKkSW9qvQNQgyqXoVSCnh5obYViEQqFekclSZIkaTzw94QkSZKkccikmbZWLkN7O3R1QX8/NDVBWxt0dvpDV5IkSdLw/D0hSZIkaZyyeUZtrVTKfuD29UFK2bCrKyuXJEmSpOH4e0KSJEnSOGXSTFvr6cmeCK3U3w+9vfWJR5IkSdL44e8JSZIkSeOUSTNtrbU1a0KlUlMTtLTUJx5JkiRJ44e/JyRJkiSNU6OC6cYAACAASURBVCbNtLViMetzoLkZIrJhW1tWLkmSJEnD8feEJEmSpHFqar0DUAMqFLJOukulrAmVlpbsB66ddkuSJEkaib8nJEmSJI1TkVKqdwxjat68eam7u7veYUiSJEmSJEmSJGmMRcTylNK8oebZPKMkSZIkSZIkSZImPZNmkiRJkiRJkiRJmvRMmkmSJEmSJEmSJGnSM2kmSZIkSZIkSZKkSc+kmSRJkiRJkiRJkiY9k2aSJEmSJEmSJEma9EyaSZIkSZIkSZIkadIzaSZJkiRJkiRJkqRJb8SkWUQcEBG75uNHR8T7I+I5tQ9NkiRJkiRJkiRJGhujqWl2LVCOiLnA14A5wH/VNCpJkiRJkiRJkiRpDI0mabYppbQReBPwhZTSPwL71jYsSZIkSZIkSZIkaeyMJmn2dETMBxYAS/OyXWoXkiRJkiRJkiRJkjS2RpM0ewfwV8C/pJT+EBFzgCtrG5YkSZIkSZIkSZI0dqaOtEBK6bcR8TFg/3z6D8Cnax2YJEmSJEmSJEmSNFZGrGkWEScCvcB/59MtEXFdrQOTJEmSJEmSJEmSxspommf8JPAK4C8AKaVeYE4NY5IkSZIkSZIkSZLG1GiSZhtTSo9sUZZGWikiLo2IByPijoqyz0bE7yJiRUR8JyKek5fPjognIqI3f/1HxTpHRMTtEbEyIi6KiMjL94qIGyLi7ny45+gOWZIkSZIkSZIkSRpsNEmzOyLirUAhIg6MiC8CPx/FepcDb9ii7AbgpSmlw4C7gPMq5t2TUmrJX+dWlF8MnAMcmL8Gtvlx4MaU0oHAjfm0JEmSJEmSJEmStN1GkzT7B+BQ4Cngv4BHgA+MtFJK6Wbg4S3Krk8pbcwnbwNmDbeNiNgX2D2ldGtKKQFXAKfks08Gvp6Pf72iXJIkSZIkSZIkSdouo0mavTGl9L9TSkfmr/OBk6qw77OBUsX0nIjoiYibIuKovGwmsLpimdV5GcDzU0prAfLh87a1o4g4JyK6I6J7/fr1VQhdkiRJkiRJkiRJE8lokmbnjbJs1CLifwMbgavyorXA/imlVuB/Af8VEbsDMcTqI/anttUKKV2SUpqXUpo3Y8aMHQ1bkiRJkiRJkiRJE9TUbc2IiCJwAjAzIi6qmLU7WcJrh0TEAqADOCZvcpGU0lNkzT+SUloeEfcAB5HVLKtswnEWcH8+/kBE7JtSWps34/jgjsYkSZIkSZIkSZKkyW24mmb3A93Ak8Dyitd1QPuO7Cwi3gB8DDgppfR4RfmMiCjk4y8CDgTuzZtdfCwiXhkRAZwFfC9f7TpgQT6+oKJckiRJkiRJkiRJ2i7brGmWUvo18OuIeBj4QUpp0/ZsOCKWAEcDz42I1cBCsmYddwVuyHJg3JZSOhd4DbAoIjYCZeDclNLD+abeDVwO7EbWB9pAP2ifBr4VEX8H/An42+2JT5IkSZIkSZIkSRoQeQuJ214g4krgr4BrgctSSneORWC1Mm/evNTd3V3vMCRJkiRJkiRJkjTGImJ5SmneUPOGa54RgJTSGUArcA9wWUTcGhHnRMSzqxynJEmSJEmSJEmSVBcjJs0AUkqPktU0+yawL/Am4FcR8Q81jE2SJEmSJEmSJEkaEyMmzSLixIj4DvBjYBfgFSmlInA48OEaxydJkiRJkiRJkiTV3NRRLPO3wL+llG6uLEwpPR4RZ9cmLEmSJEmSJEmSJGnsjJg0SymdNTAeEc8FHkoppXzejTWMTZIkSZIkSZIkSRoT22yeMSJeGRHLIuLbEdEaEXcAdwAPRMQbxi5ESZIkSZIkSZIkqbaGq2n278A/AXuQ9WdWTCndFhEvAZYA/z0G8UmSJEmSJEmSJEk1t82aZsDUlNL1KaX/B6xLKd0GkFL63diEJkmSJEmSJEmSJI2N4ZJmmyrGn9hiXqpBLJIkSZIkSZIkSVJdDNc84+ER8SgQwG75OPn09JpHJkmSJEmSJEmSJI2RbSbNUkqFsQxEkiRJkiRJkiRJqpfhmmeUJEmSJEmSJEmSJgWTZpIkSZIkSZIkSZr0TJpJkiRJkiRJkiRp0jNpJkmSJEmSJEmSpElvxKRZRPxNRNwdEY9ExKMR8VhEPDoWwUmSJEmSJEmSJEljYeoolvk/wIkppTtrHYwkSZIkSZIkSZJUD6NpnvEBE2aSJEmSJEmSJEmayEZT06w7Iq4Gvgs8NVCYUvp2zaKSJEmSJEmSJEmSxtBokma7A48Dx1eUJcCkmSRJkiRJkiRJkiaEEZNmKaV3jEUgkiRJkiRJkiRJUr1sM2kWER9NKf2fiPgiWc2yQVJK769pZJIkSZIkSZIkSdIYGa6m2Z35sHssApEkSZIkSZIkSZLqZZtJs5TS9/Ph18cuHEmSJEmSJEmSJGnsTal3AJIkSZIkSZIkSVK9mTSTJEmSJEmSJEnSpGfSTJIkSZIkSZIkSZPeiEmziDgoIm6MiDvy6cMi4vzahyZJkiRJkiRJkiSNjdHUNPsqcB7wNEBKaQVwei2DkiRJkiRJkiRJY6tchqVLYfHibFgu1zsiaWyNJmn2rJTSL7Yo2ziajUfEpRHx4EAttbxsr4i4ISLuzod75uURERdFxMqIWBERL69YZ0G+/N0RsaCi/IiIuD1f56KIiNHEJUmSJEmSJEmSnlEuQ3s7zJ8PCxdmw/Z2E2eaXEaTNPtzRBwAJICIOBVYO8rtXw68YYuyjwM3ppQOBG7MpwGKwIH56xzg4nx/ewELgTbgFcDCgURbvsw5FettuS9Jaig+rSNJkiRJkqRGVCpBVxf09UFK2bCrKytXxnt7E9/UUSzzXuAS4CURsQb4A3DGaDaeUro5ImZvUXwycHQ+/nVgGfCxvPyKlFICbouI50TEvvmyN6SUHgaIiBuAN0TEMmD3lNKtefkVwCnA8H/Cv/89HH304LK3vAXe8x54/HE44YSt13n727PXn/8Mp5669fx3vxtOOw3uuw/OPHPr+R/6EJx4Yrbvv//7reeffz4ceyz09sIHP7j1/H/9V3jVq+DnP4d/+qet53/hC9DSAj/6EVxwwdbzv/IVePGL4fvfh89/fuv53/gGvOAFcPXVcPHFW8+/5hp47nPh8suz15Z++EN41rPgy1+Gb31r6/nLlmXDz30u+yaptNtuz3zrLl4MN944eP7ee8O112bj550Ht946eP6sWXDlldn4Bz+YvYeVDjoILrkkGz/nHMp3/Z7S3g/T09xHa18zxRe8jsIXLsrmn3EGrF49eP2/+iu48MJs/M1vhoceAqBMyrZz+PNoPf0fKc4tUnhjBzzxxOD1Ozrgwx/Oxrc876Aq51751NMoXbGenkXX0dq8kuJeXRRiUzbfcy8bNsC5x113UU5TaF/xWboePZj+TdNpap5CWxt0Pu9MCvffN3j9bZx7mx1zDPzzP2fjxWJdzj2/98bPuTdIS0v2/sF2fe9t5rnnuQeee+Pg3CunKZQebqOnb252ffD991CY7bnnuTf+vvfKS79P6f6b6PneV2i9bRXFh/aiQEUDI5572bjn3tbz/Z+bjXvubT3fcy8b99zber7nnuceTPpzr+cf/kh/3zuorGvT35/o7Q06kude+fcrB9/b22UDba+ZTmcnFBZ47m2l0b/3tmHEpFlK6V7g2IhoAqaklB4b9daH9vyU0tp822sj4nl5+Uyg8q7x6rxsuPLVQ5RvJSLOIauRxmG77rqT4Wu8KrOJ9sNX0LX7o/QXNtFUnkJbeoTOTf9GYUphO7aTntlOuoOma39B28w2OpnK6LdCdjPr9hfSsxhaD5lCMU15Jtk12m1sCtrboevWvel//B00TXmStt3vpPOwj2z3tlR7pYfb6Hr0YPo2PQuoeFrniMPpGPQ1J0nSjtvqIY0pT9J2xhQ6b2K7rlWkeiuTaP9/J9G1rpv+DX00HTKFtkd3p/PXhw1OnEmStBM2P2x07SG0NkHxpV4zafJqbV5J05QnN9+7AmjaLdHSEnk7dJPbVvf2np6+uSZeR51jU/VEVrFrmAUiysBngfPyWmBExK9SSi8fdsVn1p8NLE0pvTSf/ktK6TkV8/8npbRnRPwAuDCl9NO8/Ebgo8DrgV1TShfk5f8MPA7cnC9/bF5+FPDRlNKJw8Uzb9681N3dPZrQNcEsvWsp86+dT9+Gvs1lzdOaWfLmJXQcNPqvtWpsZ6B94K4u6O+HpiayGkedUNiOK7OlS7O2hfueCYXmZliyJHsQQVDeVKa0skTP2h5a923NagVuR5K0mhYvztqDrvzajYBFi7IHMyRJqgavDzRRVOv6XZKkbanW/RlpovBvYnje25s4ImJ5SmneUPNG06fZb/Llrs/7FwN26rG+B/JmF8mHD+blq4EXVCw3C7h/hPJZQ5RLQ+pZ20P/hv5BZf0b+uld17uNNWq3nWq1D9zTk/0DGxRL/9Y1iSer8qYy7Ve2M//a+SxctpD5186n/cp2ypvq09hwa2t2sVGpqSmrhSxJUrV4faCJolrX7xOWHWpI0k6z/yZpsEIhS5AtWZIlgpYsMWFWyXt7k8NokmYbU0ofBb4K3BIRR7BzlTGvAxbk4wuA71WUnxWZVwKP5M04dgLHR8SeEbEncDzQmc97LCJeGREBnFWxLWkrrfu20jRt8Lda07QmWvbZvm+1amynWjez/KIeXmllia41XfRt6COR6NvQR9eaLkor63P1WyxmT+c0N2dPoTQ3Z9PFYl3CkSRNUF4faKKo1vX7hDTwGPj8+dnjzvPnZ9MmziRpu/iwkbS1QiFroeL887OhCbNneG9vchhN0iwAUkrfAt4CXAa8aDQbj4glwK3AiyNidUT8HfBp4LiIuBs4Lp8G+CFwL7CSLEH3nny/DwOLgV/mr0V5GcC7gf/M17kH8DkQbVNxbpG2mW00T2smCJqnNdM2s43i3O37VqvGdqp1M8sv6uE12tPJPq0jSRoLXh9ooqjW9fuEZNUISaoKHzaStD28tzc5jKZPsyNSSssrpncHTkkpXVHr4GrBPs0mt4H+rXrX9dKyT8sO92+1s9upZvvA5XL227i3N7uoKxb9oh5gPxiSpMnK6wNNFNW6fp9w7FBDqpmB/6E9PVlCxf+hE5v9N0nS5DRcn2bbTJpFxOtTSj+OiL8Zan5K6dtVjHHMmDRTo/BmVu0N9GnWtaaL/g39NE1rom1mG51ndHqzRZKkccabmJowqnEyL12aNcnY98zDYTQ3Z487d/hwmLSjTKBMTt6fmZy8tpQmtx1Nmn0qpbQwIi4bYnZKKZ1dzSDHikkzaXLx6WSpNvyBIWkseRNTDaEa//yqdTKXy5SPL1L6+R70PHkwrdPvpPiqRyhcX/KPQtoJ5qOlycFrS0nDJc2mbmullNLCfPiOWgUmSbVWmFKg46AOm2OUqsgfGJLGWmX3TTC4+yZvYmpMVOufX5VO5jIF2umkizL9TKGJTbRRoJPAf8XSjuvpyf7EK/X3ZzWQ/H8jTRxeW0oazpRtzYiIEyPihRXTn4iIX0fEdRExZ2zCkyQNqVzOHoNcvDgblsv1jkjbMgE/q8ofGCkN/oEhSbUw3E1MaUxU659flU7mUgm6fhH0PTmVxBT6npxK1y/C/8XSTmptzXLilZqasib7JE0cXltKGs42a5oB/wK8EiAiOoAzgPlAK/AfQHvNo5Mkbc1qPuPHBP2sfAJX0lgbuIlZ2VyWNzE1pqr1z69KJ7P/i6XaKBazy/UtL9+LxXpHJqmaGvHa0i4QpMaxzZpmZP2WPZ6P/w3wtZTS8pTSfwIzah+aJGlIVvMZPyboZ1XNJ3AnYEU8STUwcBOzuRkisqE3MTWmqvXPr0ons7VhpNooFLLn25YsgUWLsuE4f95N0hAa7dpy4Hnb+fNh4cJs2N7u72OpXoaraRYR0Qw8DhwDfLli3vSaRiVp7PlIy/jho8XjxwT9rKr1BO4ErYgnTRiNdGkwcBOzVMq+QltavFSZLBrmPKzWP78qnczWhpFqp1DILtXH8eW6pBE02rWlfaxJjWW4pNkXgF7gUeDOlFI3QES0AmvHIDZJY8U71+NLI7YjoKFN0M+qWj8wJuoPg4a5watxqbypTGlliZ61PbTu20pxbpHClLE/gRrx0sCbmJNPQ52H1by7VoWTudFu9kmSNN400rXlBH3eVhq3tpk0SyldGhGdwPOAX1fMWge8o9aBSRpDE/XO9UTlo8XjxwT+rAqU6aBER+oh6+60CGzfnbpq/jBolERVQ93g1bhT3lSm/cp2utZ00b+hn6ZpTbTNbKPzjM4xT5x5aaBG0HDnYSPdXaPhwpEkSTtogj5vK41bw9U0I6W0BlizRZm1zKSJxkdaxhcfLR4/JupnVaXMULV+GDRSoqrhbvBqXCmtLNG1pou+DdkJ1Lehj641XZRWlug4aGxPIC8N1Ag8DyVJ0mQwgZ+3lcalYZNmkmqnUZpfAnykZTzy0eLxYyJ+VlXKDFXrh0EjJaq8waud0bO2h/4Ng0+g/g399K7rHfOkmZcGagSeh5IkaTKYqM/bSuOVSTOpDhqp+SXAR1rUGBqlfT2NrEqZoWr9MGikRJU3eLUzWvdtpWla0+aaZgBN05po2WcHTqCd/E710kCNwPNwfGmohwIlSRpnJuLzttJ4NWLSLCK+kVI6c6QySaPXSM0vAT7SovprpPb1NLIqZoaq8cOgkRJV3uAdO1W7OdtACfvi3CJtM9u2eqimOHc7T6AqfKd6aaBGUK3z0GRO7TXcQ4GSJEnSDoqU0vALRPwqpfTyiukCcHtK6ZBaB1cL8+bNS93d3fUOQ5Pc4psWs3DZQhLP/P0FwaLXLeL815xfx8ikOlm6FObPH5z1aG6GJUt8zKoRNViSs8HC2ZyDMdFQO1W7OdtoJw/P3NzvXddLyz4tO3Zz3+9UaTOTOWNj6V1LmX/t/EE1ZZunNbPkzUvq81CgpJppoOeNJEnaYRGxPKU0b6h526xpFhHnAf8E7BYRjw4UAxuAS6oepTSJVLX5pSqp1oWvF9DjS8N8Xj09lPueoMQb6aGVVnoo9v03BTuCakwNVgWlwcKxWY0xULUa243UIV6uMKVAx0EdO3eTuZHaLNW40zDXBlXScC08TFCN1CejpNppwOeNJEmqum0mzVJKFwIXRsSFKaXzxjAmacKrWvNLVVKtC18voMeXRvq8yoe10l64ga7yPPp5Fk08Tluhm86X9eOp06AaLDPUYOGoxqp2c3aiJpcaqc1SjSuNdG1QLSZzxkYjPhQoqfoa8HkjSZKqbsoollkaEU0AEXFGRPzfiHhhjeOSJrTClAKdZ3Sy5M1LWPS6RSx585K6NhFTeeGb0uAL33psZyIrbyqz9K6lLL5pMUvvWkp5U7lusWSfVxr8ed2W6vJ5lSjSRRt9PJtEgT6eTRdtlLAjKElbG7g5W2mHbs4OJJcGbWgCJJcGOtdrboaIbGjnehqFiXgtV7XvCw1r4KHA5mnNBEHztOa6PhQoqTaGe95IkqSJYps1zSpcDBweEYcDHwW+BlwBvLaWgUkTXVWaX6qSaj1oP1Ef2Aeq0lZRo/Wp0bN8E/19kLW8m+nvT/T+KtHRMZpnKqoYy4oC/Zt2G1TWv2k3em8POk4e01AkjQNVq7E9kFzaslrNeE8uNVqbpRo3JuK1XKO18DBRDTwUuNN9MkpqaFZmlyRNBqNJmm1MKaWIOBn4/1JKX4uIBbUOTGpoE6yzh2pd+E7YC+gqtVXUaH1qtJa7aeIQ+mjeXNbE47Rs/C3wirGNpRWammKLcyfG/7kjqSaqdnN2IieXbLNUO2AiXsuZzBk7jfRQoKTamKjPG0mSVGk0SbPHIuI84EzgqIgoALvUNiypgU3Azh6qdeE7YS+gq9Rwe6P1qVEsXE8bj9JF2zP9iNFFcWoXY500m7DnjqSaqdrNWZNL0mYT9f+xyRxJqo6J/LyRJEkDRpM0Ow14K3B2SmldROwPfLa2YUkNbAL2fFutC9+qXkA3Um2+nh7KfU9Q4o300EorPRT7/pvCdrZV1GgdpBeOaKGz6c2U+o+ilxZa6KXYdAuFl1819rH440uSpLrz/7EkaSQ+b/T/t3f/UZKddZ3HP9+u0CapCgQ0OMMkgeBkFPxBN5ZpBI0gkqawNbIBTWsQAQ26sOCuugs4x8FpWXFFfuxZDmsIeJBgByQgY0vZCQohLlCkJ9UCIRIbiDCTGYiCkKqYdFL93T/uraSqp7u6q/tW3VvPfb/OmVNTt6qrnvp173Of7/P9PgCA0Jm7b30ns8dKutDdP2JmZ0oquPvdA2/dAJTLZV9aWkq7GRhlc3PSoUPR6uhtZtLhw9LBg+m1KyQZy+ZrfWhB05cVVWuVH8rIKixp8bqmCpdu/0wha2uaZe19BgAAAAAAAIBBM7Oj7l7e6LYtM83M7NckXSnpUZK+R9I+Sf9X0jOTbCQwMkJc7CFrMpbNV1VFNd2nhs6MmqOzVNOUqvoO9dOazK2pwXRyAAAAAAAAAHjQdsozvkzR4jY1SXL3fzazRw+0VUCWhbrYQ5bU69F726nZjAI7KQTN6p8pqLl2Rndz1s7Q8mdNM5f291iZW1OD2hoAgBHRWmupulJV/URdk3sn0514AgAAAAAI0naCZve5+6qZSZLM7DRJW9d0BEJFds7gZSybL2qOrWuOkVwIAMCQZK7EMQAAAADsQqsVDS/X69HYI8PL2bGdoNmNZvYaSWeY2bMk/WdJfz3YZgEZR3bOYGUsmy9jzQEAIHeqK1XVjtfUWI1msDRWG6odr6m6Us1O9jYAAAAAbEOrJU1PnzrWuLhI4CwLthM0e5Wkl0j6rKSXSvqwpKsH2SgAOZexbL6MNQcA+sP0NQSgfqKu5mp36ebmalPLJ5cJmgEAAAAYKdVqFDBrV7VqNKLr1So5GlmwZdDM3dckvT3+BwDDkbFsvow1BwC2h+lrCMTk3kkVx4sPZppJUnG8qIk91EpGfrHOHwAAwGiq16NT9E7NZjRZn7HH9G0ZNDOzL2uDNczc/fEDaREAABgYko5yhulrCERlf0VT+6ZOWdOssp9aycgn1vkDAAAYXZOT0ZzWxkNzAlUsRtWtkL7tlGcsd/z/dEnPl/SonT6hmX2vpPd2bHq8pN+TdLakX5N0V7z9Ne7+4fhvXq2oRGRL0ivcfTHe/mxJb5FUkHS1u79+p+0CACB0JB3lENPXEIjCWEGLVyyqulLV8sllTeyZIKsGucY6f1sjEw8AAGRVpRKNx6wfn6kwJzATtlOe8d/WbXqzmf2DokBX39z9C5ImJMnMCpKOS/qgpBdJepO7v6Hz/mb2REmXS/p+SY+R9BEzOxDf/FZJz5J0TNLNZnbE3T+/k3YBABA6ko62IbRUPKavISCFsYJmDswQEADEOn9bIRMPAABkWaEQTWCuVqM5rRMToz/8EJLtlGd8csfVMUWZZ2cl9PzPlPRFd/8XM9vsPpdKutbd75P0ZTNbkXRRfNuKu38pbue18X0JmgEAsAGSjrYQYioe09cAILwJEWKdv62QiQcAALKuUIjGYhiPyZ7tlGf8k47/PyDpDkk/n9DzXy5pvuP6y83slyUtSfotd/+mpH2SPtVxn2PxNkn66rrtUxs9iZldKelKSTr//POTaTkAIJMoxbM5ko62EGIqHtPXsAvsTxGEVkutSyqqfuIRqt/7BE2e/i5Vnvq/Vbi+OtL7Qtb5641MPAAAAOzUdsozPmMQT2xm45J+VtKr401vkzQnyePLP5H0YkkbpaC5oqy3jbafutH9KklXSVK5XN7wPgCA0Ucpnt5IOtpCqKl4TF/DDrA/RShaC1VN3/hq1VplNXWmivfeo6kbl7S4UFXh0tHdL7LOX29k4gEAAGCntlOe8b/1ut3d37jD565IusXdvxY/ztc6nvPtkhbiq8ckndfxd+dKujP+/2bbAQDbEFoWQcileJKoLEXS0RZIxQMexP4Uoaj+ZUO11k+oEa8w0NBZqrXKqr7/bzRzacqN2yXW+dscmXjIAo43AACMpu2UZyxL+hFJR+LrPyPp4+oujbgTs+oozWhme939RHz1uZI+F///iKS/MLM3SnqMpAslfVpRBtqFZnaBpOOKSj3+4i7bBAC5EWIWQaileJJcaoukox5IxQMexP4UoahrUk2d2bWtqTO1rAmN7jcZWyETD2njeAMAwOjaTtDsuyQ92d3vliQze62kv3T3X93pk5rZmZKeJemlHZv/l5lNKCqxeEf7Nne/1czeJ+nzitZUe5m7t+LHebmkRUkFSe9091t32iYAyJsQswhCLcUT4lJbmUQqHvAg9qcIxeTz96t47X1qtB4KnBUL92nieRem2CoMA5l4SBPHG4SErEkAebOdoNn5klY7rq9KetxuntTd75H0neu2vaDH/V8n6XUbbP+wpA/vpi0AkFchZhGEWoon1KW2MolUvIHjpHs0sD9FKCozBU39xBmqfeIBNe8dU/H0NU099QxVZjZaOhtAKgLsHHC8QSjImgSQR9sJmr1b0qfN7IOKssCeK+nPB9oqYJ3Q1l0CsiCpLIIs/T5DLcUT9FJbAQ6SYHOcdG8tKz8J9qcIRaEgLV5vqlZPi5OIxzjUAFkSaOeA4w1CQdYkgDwyd9/6TmZPlvTj8dWPu3t9oK0aoHK57EtLS2k3IzeSGPgJcd0lIAuS+G3x+xyOQMcSAn5h2MzCgjQ72z2AVCpJ8/OcdEv8JIaB9xgAMibQzgHHG4Ribk46dEjqHD42kw4flg4eTK9dALBbZnbU3csb3badTDNJOlPSt939z8zsHDO7wN2/nFwTEaKkOokhrrsEZEESWQT8Pocj2KW2mLaYO5Qq6i3Un0SmMpJD3Z8CwKgKtHPA8Qa7kZXKAxJZkwDyacugmZkdklSW9L2S/kzSwyRdI+lpg20aRl1SAz8hrrsEZMVuF0jn9zk8QS61FeggCTbHSXdvIf4kspiRXFBLM6pqxuuSJiVVJDGKCQCpCLhzEGT/HQOXtSzFSiV6Vkea0AAAIABJREFU/vXtqYz2MrcA0NPYNu7zXEk/K6kpSe5+p6SzBtkohKHXwE8/2usuddrJuksAksfvE7vSHiTpFMggCTbWPukulaKyLqUSJ92dQvxJdGYku7wrIzkV7ZGo2dmo1tDsbHS91UqnPXGTFhai8kcLC6k2BQCGj84B0KVzArp79wT0NLSzJufno5KM8/OUGQUQvu2UZ1x1dzczlyQzK271B4CU3ISxyv6KpvZNnTJDubKfTjSQNn6f2BWmLeYOpYp6C/EnkbmM5IzVwMzabHIAGDo6B0CXLFYeIGsSQN5sJ2j2PjP7U0lnm9mvSXqxpKsH2yyEIKmBnyTWXUKOZakYeID4fWJXGCTJJU66NxfiT6Kdkdxe+1JKOSM5YyNRGYvhAUA66BwADwq4YmliGObJHz5zDJu5+9Z3MnuWpEskmaRFd79h0A0blHK57EtLS2k3IzfaO7VQBn4wYpi+DQBAqjK3ptnCQlSSsXMkqlSKag2lMFg7NxdView8JTOLyh8dPDj05gAAgJQxjNEb70/+8JljUMzsqLuXN7xtO0GzdQ9WkHS5u78nicYNG0EzIEcyNjAGAEAetdZa2clIzthZN10VAMCwkKkxOpiAvjn6TvnDZ45B6RU027Q8o5k9XNLLJO2TdETSDfH135G0LGkkg2YAciRjJZgAAGLEJocKYwXNHJhJZw2zUxqTrRqYIa5jBwDInozNGcEWqFi6OYZ58ofPHGnotabZuyV9U9InJf2qomDZuKRL3X15CG0DgN0JuBh4e9Z+/URdk3snWUcMwGhgxAZZkKGRqIzF8LAFYv4ARhVraCIUAQ/zYBN85khDr6DZ4939ByXJzK6W9K+Sznf3u4fSMqSKE0IEIdDp25lbHwYAtiuDIzb0eZC2DMXw0AMxfwCjjEwNhCLQYR70wGeONPQKmt3f/o+7t8zsywTM8oETQgQj0Onb1ZWqasdraqxGg86N1YZqx2uqrlSzUfoKADaTsREb+jwAtiuDMX8A2DYyNRCKQId50AOfOdLQK2j2JDP7dvx/k3RGfN0kubs/fOCtQyo4IURQApy+XT9RV3O1e9C5udrU8sllgmYAsi1jIzb0eQBsV8Zi/gDQFzI1EJIAh3mwBT5zDNvYZje4e8HdHx7/O8vdT+v4PwGzgPU6IQSQvsm9kyqOF7u2FceLmtjDNEEAGdcesSmVJLPoMsURG/o8ALarHfPvRJYGgFHRztSYn5cOH44uyawHMGitlrSwIM3NRZetVtotAranV6YZcipjk8CBXQlxrZrK/oqm9k2dsqZZZT/TBAFkXMZqa9DnAbBdZGmMnhDPA4DdIFMDwDBRCh+jzNw97TYMVblc9qWlpbSbkWns1BCKTH6XEzp7b621VF2pavnksib2TKiyv6LCGD9QAOhHJo8TADKr3Y3LQMwfWwh5/04wEAAwChYWpNnZ7gmKpVKU6UrwHllgZkfdvbzRbWSa4RQZmwQO7Fjm1qpJ8Oy9MFbQzIEZ1jADkF8JjBrS5wHQD7I0RkfmzgMSEnIwEAAQFtaDxSgjaIYNcUKIEGTuAB3q2TsADFuSkxDo8wBAcDJ3HpCQ6HTC1WiYpPh04lOuatVG+nUBAMJDKXyMsrG0GwAAg5K5Bdt7nb0DALavcxKCe/ckBABA7mXuPCAh9aNraja6l9hoNl3Lt6yl1CIAADbWXg+2VJLMokvWg8WoIGgGIFiZO0CHevYOAMPGJAQAQA+ZOw9IyGRrSUXd07WtqHs08QDrtgMAsqVdCn9+Xjp8OLqknDBGBeUZAQQrc2vVtM/e15cTG/WzdwAYNmp9AAB6yNx5gJTIWpyVwvWa0rdV05SaOlNF3aMp1VQ5rSbposG0GwCAHaIUPkaVufvW9wpIuVz2pSVmYQFISftkOTNn70AYWmstVVeqqp+oa3LvpCr7KyqMpfTbSmBQDFtIcE0zAAAGLqnj1sKCWpf/kqrNH9eyJjShZVWKN6lw7XsYkQQAAOiDmR119/KGtxE0AwDsCgECpKy11tL0NdOqHa+pudpUcbyoqX1TWrxicfiBM4I5w8MkBKQsU8H6JHFcB5K3sCDNznZnSJdKUa2qfoJd9DMAAAAS0StoRnlGAMDOceKODKiuVFU7XlNjNRqIaqw2VDteU3WlqpkDQ551Xa1Gv4f2oFijEV2vVpkBnjRqfSBFmQrWd7Rp10E8juvAYPRai7Of41gm604CAACEZSztBgAARlhngMC9O0AADEn9RF3N1e6BqOZqU8snl1NoTI9BMQDB6AzWu7wrWJ+GdhBv9rpZHfrYIc1eN6vpa6bVWmv190Ac14HBaK/F2Wmna3G2J40cPBhdEjADAABIFEEzAMDOESBABkzunVRxvHsgqjhe1MSeHQxE7boxyQ2KtVpRNae5ueiy1efYd9KPA+AhmQrWK8EgHsd1YDAqlShrs1SSzKLLqaloOwAAADKF8owAgJ1rBwg612fY6axZYIcq+yua2jd1Spm0yv4UBqLag2LrS5v1OSiWVIU0Kq0Bg9EO1rfLwkopBuvVO4jXV5lajuvAYFBWEQAAYGQQNAMA7FxCAQJgNwpjBS1esajqSlXLJ5c1sWdiZ2v5JNKYZAbFkloajSXWhieR9aQwMjIVrFeCQTyO68DgsBYnAGDAWq3oXK9ej+ZCMT8D2JnUgmZmdoekuyW1JD3g7mUze5Sk90p6nKQ7JP28u3/TzEzSWyQ9R9I9kn7F3W+JH+eFkg7GD/sH7v6uYb4OYMc4kiEEzJpFRhTGCpo5MNNfRsXAGrP7QbFeFdL6edikHge9tdeTWh9AWbxikcBZoDIVrFeCQTyO6wAAACOJKiNActLONHuGu/9rx/VXSfo7d3+9mb0qvv4/JFUkXRj/m5L0NklTcZDtkKSyJJd01MyOuPs3h/kigL5xJENImDWLgGRlPkNSFdKotDYcnetJSepaTyoTgVwMRJaC9YkG8TiuAwAAjByqjADJGUu7AetcKqmdKfYuST/Xsf3PPfIpSWeb2V5J05JucPdvxIGyGyQ9e9iNBvrWeSRz7z6SAQD612pJCwvS3Fx02Wrt6CGmp6XZWenQoehyenpHD7Vr7QpppZJkFl3upEJaUo+D3nqtJzXSEvhdYXjaQbyDFx/UzIEZshwBAABypFeVEQD9STPTzCVdb2Yu6U/d/SpJ3+3uJyTJ3U+Y2aPj++6T9NWOvz0Wb9tsexczu1LSlZJ0/vnnJ/06gP5RLwsAkpNQ9m6WZuYlVSGNSmvDkdh6UllCVnxusT4fUpeVtG8AAEYIVUaA5KQZNHuau98ZB8ZuMLN/6nFf22Cb99jevSEKyF0lSeVy+ZTbgaHjSAYAyUko2pW1+QxJVUij0trgJbaeVJZkKYqMoWF9PqSOgD0AADvSrjKy/hBKlRGgf6mVZ3T3O+PLr0v6oKSLJH0tLruo+PLr8d2PSTqv48/PlXRnj+1AtlEvCwCSk1AdivZ8hk7MZ8B2tNeTmr9sXoefcVjzl82PfpCB+i651Lk+n8u71ucDhoIy9gAA7Ei7ysj8vHT4cHTJnBNgZ1LJNDOzoqQxd787/v8lkg5LOiLphZJeH19+KP6TI5JebmbXSpqS9K24fOOipP9pZo+M73eJpFcP8aUAO0O9LOAUlIPCjiWUvcvMPOxGez2pmQOBZGGRFT88GSpF12t9vtS+2xl6fzAEWUv7BgBghFBlBEhGWuUZv1vSB82s3Ya/cPe/NbObJb3PzF4i6SuSnh/f/8OSniNpRdI9kl4kSe7+DTObk3RzfL/D7v6N4b0M5FUi5+4cyXpifCRfKAeFXUko2sV8BoRk1xMRiCIPR4Kl6JLoO2VufT5K9eUPAftc4twPAABkibnna4mvcrnsS0tLaTcDI4xz98HjPc6fhdsXNHvdbNcgXWm8pPnL5sPJ2sBgtUdbiHYByU1E4Hc1eAsL0uxsd4CgVIrq6fQxsSqpvlPmJrEk9P5ghHAikDt85AAAIA1mdtTdyxvdltqaZsCoosz+4PEe50+vclDAtrSzdw8ejC4ZZUGOJbYuFb+rwUto7bik+k6ZW5+PtfXyhwVZcodzPwAAkDUEzYA+ce4+eLzH+dMuB9Up1XJQADDCmIgwQtql6DrtoBRdkn2n9vp8By8+qJkDM+mWSU7o/cGIIWCfK5z7AQCArCFoBvSJc/fB4z3On8r+iqb2Tak0XpLJVBovaWrflCr7WTsHAPrFRIQR0l47rlSSzKLLHawdF2zfKaH3B0B2Bbv/AgAAI4s1zYA+UXN98HiP86m11lJ1parlk8ua2DOhyv5KurPbs4YV0gFsU+bWpUJvCawdF3TfibX1gKAFvf8CAACZ1WtNM4JmwA5w7j54vMdAB0YTAPSJiQhDkLHJDPSdAIwq9l8AAGDYCJp1IGgGABg5CwvS7Gy0MnpbqSTNz0drfQA9tIMn9RN1Te6dJHgCJIHJDFti37M53hsAAAAgXb2CZqcNuzEAAKBPvVZIJ2iGHhIt05exrBogVdVqFDBrT2ZoNKLr1Sr7ZVEitBfeG2QBh3QAAIDNETQDkChmzgID0F4hvTPTjBXSsQ3Vlapqx2tqrEbfncZqQ7XjNVVXqpo50MfAPlk1QDcmM/SU2L4nQLw3SBuHdAAAgN7G0m4AgHC0Z87OXjerQx87pNnrZjV9zbRaa620mwaMtkolGs0olSSz6HJqKtoO9FA/UVdztXtgv7na1PLJ5f4eqDOrxr07qwbIo/Zkhk5MZnhQYvueAPHeIG0c0gEAAHojaAYgMZ0zZ13eNXMWwC4UCtH03/l56fDh6JLpwNiGyb2TKo53D+wXx4ua2NPnwH69rtY9DS0ckOYulhYOSK17GlFWTUparWi5v7m56LLF/AwME5MZekps3xMg3pvRE9rxpleiLAAAACjPCCBBvWbOUm4G2KVCISr5Rdkv9KGyv6KpfVOnrJ1T2d/fwH5r4oc0/cKCantaaj5MKt4vTZ0saPFJP6g0QreUlkLq2pMZqtVopHligkWBOiS17wkR781oCfF4Q9VvAACA3giaAUhMe+Zse40GiZmzAJCmwlhBi1csqrpS1fLJZU3smdjRWpPVC6XauVIj/rPGd0TXqxdKaYRxO0tLSd2lpYgrY2iYzLCppPY9IeK9GS0hHm/aibLrA4EkygIAAEQImmGgWmstVVeqqp+oa3LvJCeEgWPmLABkT2GsoJkDM7vK+K1/7TNqFta6tjULa1r++mc1832X9vVYSfQNepWWGtVBTCA0Sex7QsV7MzpCPN6QKAsAANAbQTMMTGutpelrpk8JoCxesUjgLFDMnAWAMCWVSZxU34DSUgCAYQj1eEOiLAAAwObG0m4AwlVdqap2vKbGakMuV2O1odrxmqor1bSbhgFqz5w9ePFBzRyY2XHArLXW0sLtC5q7cU4Lty+otTbiK24DwAhrZxKXxksymUrjpR1lEifVN2iXliqVJLPoktJSAICkcbwBAADIHzLNMDD1E3U1V7trWTRXm1o+uUwpEvREliIAZEtSmcRJ9Q0oLQUAGAaONwAAAPlD0AwDk1QpJ+RPZyaCpK5MBAKuAJCOJNbgSbJvQGkp7BRr7gLoB8cbAACAfCFohoFpl3Jany3Ubykn5A9ZiltrtaIZr/V6tNYCM14BjIIs9g0IoAxBhg5aZLMDAAAAAHohaIaBSaqUE/KHLMXeWi1pelqq1aRmM1qMfGoqKh1D4AxAlmWtb0AAZQgydtAimx0AAAAA0MtY2g1A2NqlnA5efFAzB2YYgMK2tDMRSuMlmUyl8VLqmQhZUq1GY4+NhuQeXdZq0XYAyLos9Q06Aygu7wqgICEZO2j1ymYHAAAAAIBMMwCZk7VMhKyp16PJ+p2azWhxctZaAIDtoxzwEGTsoEU2O5B9lM0FAABAmgiaIV8ytKYGemtnIjBoearJyai6VeOh8T4Vi9IE433JYn8BBC/RAAr7jI1l7KCVxXX1EsN3EAGgbC4AAEB/OA1IHkEz5EfG1tQAdqpSib6667/KlQDG+zKD/QWQC4kFUNhnbC5jB61gs9n5DiIQrDsIYJQxcA1g2DgNGAyCZsiPzjU1pO41NahphxFSKEQHv2o1qm41MUFnPHHsL4BcSCyAwj5jcxk8aAWZzc53EIGgbC6AUcXANYA0cBowGATNMBqSmK6TsTU1gsXUqqEoFKKvLV/dAWF/AeRGIgEU9hm9cdAaPL6DCATrDgIYVQxcA0gDpwGDQdAM2ZfUdJ2MrakRJKZWIRTsLwD0g30G0sZ3EIEIet1BAF1Cm2/LwDWANHAaMBhjaTcA2FLndB337uk6/WivqVEqSWbRJQtBJSupzwpIG/sLAP1gn4G08R1EINplc+cvm9fhZxzW/GXzWrxicfTXHQTQpT3fdnZWOnQoupyejraPqvbAdScGrgEMGqcBg0GmGbIvqek6GVxTIzhMrUIo2F8A6Af7jJ5Cm0meSXwHEZAg1x0E0CXEUobtgev1hXcYuAYwSJwGDAZBM2RfknmmrKkxWOQEIyTsLwD0g33GhqjcPER8BwEAIyLE+bYMXANIC6cByRt6eUYzO8/MPmpmt5nZrWb2ynj7a83suJktx/+e0/E3rzazFTP7gplNd2x/drxtxcxeNezXgm1otaSFBWluLrrcSa49eaa9JfEeJ4XPCgAAdKByMwAAWC/UUobtgeuDB6NLAmYAMJrSyDR7QNJvufstZnaWpKNmdkN825vc/Q2ddzazJ0q6XNL3S3qMpI+Y2YH45rdKepakY5JuNrMj7v75obwKbC2pqcVM19lc1qZv81kBmddaa6m6UlX9RF2TeydV2V9hnZAOvD9AskKcSQ7sVrAlS4N9YQCSRilDAECWDT1o5u4nJJ2I/3+3md0maV+PP7lU0rXufp+kL5vZiqSL4ttW3P1LkmRm18b3JWiWFUkWqSbPdGNZLATOZwVkVmutpel3X6LaVz6h5tq9Ko6drqnzn6rFF1xPYEjx+3PNtGrHa2quNlUcL2pq35QWr1jk/cGWGCveGJWbgW5Zm/OWmGBfGIBBYL4tACDLhl6esZOZPU7SpKRavOnlZvYZM3unmT0y3rZP0lc7/uxYvG2z7Rs9z5VmtmRmS3fddVeCrwA99ZpajGTwHgPoQ/X2BdW+eKMaa/fKJTXW7lXtizeqevtC2k3LhOpKVbXjNTVWG3K5GqsN1Y7XVF2hjhx6a48Vz85Khw5Fl9PT6VZMzgoqNwPdgi1ZGuwLAzAolDIEAGRVakEzMytJuk7Sb7r7tyW9TdL3SJpQlIn2J+27bvDn3mP7qRvdr3L3sruXzznnnF23HdsUapHqLOE9BtCH+k1/qaZ1j+I3raXlm96fUouypX6iruZq90SE5mpTyyeZiIDeGCveXHsm+fy8dPhwdEniCfIs2Dlvwb4wAAAA5E0qQTMze5iigNl73P0DkuTuX3P3lruvSXq7HirBeEzSeR1/fq6kO3tsR1YwtXjweI+B3GittbRw+4LmbpzTwu0Laq31n8IyeUIq3t+9rXi/NHEyoUaOuMm9kyqOd09EKI4XNbGHiQjojbHi3kKdSd5qSQsL0txcdElmIbYj2Dlvwb4wAAAA5M3Q1zQzM5P0Dkm3ufsbO7bvjdc7k6TnSvpc/P8jkv7CzN4o6TGSLpT0aUWZZhea2QWSjku6XNIvDudVYFsoUj14vMdA5iWxzlFSa21VJp+vqQ9eq9qelpoPiwJmUycLqjz3eX2+qjBV9lc0tW/qlPe5sp+JCOiNdbvyh+WbsFPtOW/rvzsjP+ct2BcGAACAvDH3DSsaDu4JzX5M0k2SPitpLd78GkmzikozuqQ7JL20HUQzs9+V9GJJDygq51iNtz9H0pslFSS9091ft9Xzl8tlX1paSvIlAQCwoaQGVRduX9DsdbNqrD40Il8aL2n+snnNHJjpq0Gt6UtUvesTWj77Xk38++mqnPNUFRavZ5Q31lprqbpS1fLJZU3smVBlf6WvwGSyjUkg4oqhIICSPwsL0dp1nYHSUikqPznTx24Z+dTevQc35y3YFwYASAKnNwCyxMyOunt5w9uGHTRLG0EzhKY9wFs/Udfk3sl0B3gBdElqUHXuxjkd+tghecfSnSbT4Wcc1sGLD/bXKAa0RgNRmJHDTytf5uakQ4eiNezazKJ12w72uVsGAAAIHac3ALKmV9Bs6OUZASQnqZJtAAaj1zpH/QTN2mttdWaa7XitrfbiQqRCZFu1Gp1RtiOujUZ0vVrls8soflr5QklOAACQdVnK7OL0BsAoGUu7AcAwhbZge3WlqtrxmhqrDblcjdWGasdrqq5U024aAD00qNppJ4Oq7bW2SuMlmUyl8RJrbYWuV8QVQOrayzeVSlGGWanE8k0YYaGdJGFo+OoA2dXO7JqdjbLjZ2ej62n9TkM+vWFfCISHTDPkRoip4PUTdTVXu3sdzdWmlk8u97fOEYCBqFSki6Za+sRdVd37yLpO/+akLjqnokqlv51OYaygxSsWs7PWFgaPNBbgVBmaLl0oRH1ISnJi5IV4koSh4KsDZFvWMrtCPb1hXwiEiaAZciNrHYYkJFqyDUDyrCW9YFr6Sk1aa0pjRen8KckWJfUfOJs5MENAPC/aaSzrz75IY0FeZXBEgpKcCEK1qtanbla1+ROqa1KTjboqn7pJhVE+ScJQhHh+DYQkqaUCkhLq6Q37QiBMlGdEboSYCk7JNiDbqitVffrOmu5da0hy3bvW0KfvpIQqtqGdxjI/Lx0+HF0yXTEfqO+ysc4RCffuEQkAO9Y6uqzp5nWa1bwO6bWa1bymm9epdcs/pt204IS2ew/x/BoISVJLBSQl1NMb9oVAmMg0Q26EmApOyTYg2yihil0hjSV/MphNlRlZmy4NBKLaukQ1PVENlSRJDZ2lmp6i6gMPF7+sWAKlYUPcvYd4fg2EJIuZXSGe3rAvBMJE0Ay5kcUOQxIo2QZkFyVUAfSF+i6bY0QCGIh6oax14Wg1daaWTysTNJMSi3aFuHsP9fwaCAXrrw4H+0IgTATNkBt0GAAMW7uEau14Tc3VporjRUqoAtgc2VSbY0QCGIjJHx5TseTr4tGmiSdbeo3KkoSiXSHu3jm/BrIvxMyurGFfCISJoBlyhQ4DgGGihCqAvpBNtTlGJICBiOLRti4ebcSj2xKKdoW6e+f8GgDYFwIhMndPuw1DVS6XfWlpKe1mAAAAAN1CXPQGQOa1l+wiHr2BhQVpdrY72lUqSfPzfY2OsnsHAADIFjM76u7lDW8jaAYAAABkBKPXAJAdCUa72L0DAABkB0GzDgTNAAAAAADAthDtAgAACE6voBlrmgEAAAAAAGyExWoAAAByZSztBgAAAAAAAAAAAABpI9MMAAAAAAAgL9olJ+t1aXKSkpMAAAAdCJoBAAAAAADkQaslTU9LtZrUbErFojQ1JS0uEjgDAAAQ5RkBANhQqyUtLEhzc9Flq5V2iwAAAIBdqlajgFmjIblHl7VatB0AAABkmgEAsB4TcAEAABCkej3q4HZqNqXlZWlmJp02AQAAZAiZZgAArMMEXAAAAARpcjKaEdapWJQmJtJpDwAAQMYQNAMAYJ1eE3ABAACAkVWpRCUUSiXJLLqcmoq294t65gAAIECUZwQAYJ32BNxG46FtTMAFAADAyCsUoprj1Wo0I2xiIgqY9VuDnHrmAAAgUGSaAQCwTpITcAEAAIBMKRSi9csOHowudxLkop45AAAIFJlmAACsk9QEXAAAACBIveqZz8yk0yYAAIAEEDQDAGAD7Qm4nPMDAAAA61DPHAAABIryjAAAAAAAANg+6pkDAIBAkWkGAAAAAEhUqxWVOa7Xo4QUyhwDgaGeOQAACBRBMwAA0LfWWkvVlarqJ+qa3Dupyv6KCmMMkoSMAXAA29VqSdPTUq0WLXFULEYJKIuL7DeAoFDPHAAABIigGQAA6EtrraXpa6ZVO15Tc7Wp4nhRU/umtHjFIoGzQDEADqAf1Wq0v2gvddRoRNerVcbWAQAAAGQba5oBALCB1lpLC7cvaO7GOS3cvqDWWivtJmVGdaWq2vGaGqsNuVyN1YZqx2uqrlTTbhoGpHMA3L17ABwA1qvXowB7p2YzquAGAAAAAFk28plmZvZsSW+RVJB0tbu/PuUmBSFrZbcoCTV4WfvMMTpC/H2SSdVb/URdzdXu0dDmalPLJ5c1c4AUghD1GgAnawTYnRD7YJOTUUZqO9NMiq5PTKTXJmwuqe9gUn3CEPuWwG7wm9gc7w2AfrDPwHaNdNDMzAqS3irpWZKOSbrZzI64++fTbdloy9pgMSWhBi9rnzlGR6i/z85MKkldmVQEhaTJvZMqjhcffH8kqThe1MQeRkNDxQA4MBih9sEqlag/sL5/UKmk3TKsl9R3MKk+Yah9S2Cn+E1sjvcGQD/YZ6Afo16e8SJJK+7+JXdflXStpEtTbtPIy1rZLUpCDV7WPnOMjlB/n70yqSBV9lc0tW9KpfGSTKbSeElT+6ZU2c9oaKjaA+ClkmQWXTIADuxeqH2wQiEagJiflw4fji4ZkMimpL6DSfUJQ+1bAjvFb2JzvDcA+sE+A/0Y9aDZPklf7bh+LN7WxcyuNLMlM1u66667hta4UZW1wWLWRBi8rH3mGB2h/j7bmVSdyKR6SGGsoMUrFjV/2bwOP+Ow5i+bH/msCPTGADgwGCH3wQqFqHzrwYPRJfuLbErqO5hUnzDUviWwU/wmNsd7A6Af7DPQj5EuzyjJNtjmp2xwv0rSVZJULpdPuR3dslZ2i5JQg5e1zxyjI9TfZzuTan2pIjKpHlIYK2jmwAzlKnOkPQDOGmZAcuiDIW1JfQeT6hOG2rcEdorfxOZ4bwD0g30G+jHqmWbHJJ3Xcf1cSXem1JZgZK3sFiWhBi9rnzlGR6i/TzKpAADDQB8MaUvqO5hUnzDUviWwU/wmNsd7A6Af7DPQD3Mf3cQrMztN0u2SninpuKT7ocXhAAAJwElEQVSbJf2iu9+62d+Uy2VfWloaUgtHV2utpepKVcsnlzWxZ0KV/ZVUB4tbrajG7PJyNAOgUqHES9Ky9pljdPD7BABg5+iDIW1JfQeT6hPStwS68ZvYHO8NgH6wz0AnMzvq7uUNbxvloJkkmdlzJL1ZUkHSO939db3uT9AMAAAAAAAAAAAgn3oFzUZ9TTO5+4clfTjtdgAAAAAAAAAAAGB0jfqaZgAAAAAAAAAAAMCuETQDAAAAAAAAAABA7hE0AwAAAAAAAAAAQO4RNAMAAAAAAAAAAEDuETQDAAAAAAAAAABA7hE0AwAAAAAAAAAAQO4RNAMAAAAAAAAAAEDuETQDAAAAAAAAAABA7hE0AwAAAAAAAAAAQO6Zu6fdhqEys7sk/Uva7Rgh3yXpX9NuBADgQeyXASBb2C8DQLawXwaAbGG/jCx6rLufs9ENuQuaoT9mtuTu5bTbAQCIsF8GgGxhvwwA2cJ+GQCyhf0yRg3lGQEAAAAAAAAAAJB7BM0AAAAAAAAAAACQewTNsJWr0m4AAKAL+2UAyBb2ywCQLeyXASBb2C9jpLCmGQAAAAAAAAAAAHKPTDMAAAAAAAAAAADkHkEzbMjMnm1mXzCzFTN7VdrtAYC8MbPzzOyjZnabmd1qZq+Mtz/KzG4ws3+OLx+ZdlsBIE/MrGBmdTNbiK9fYGa1eL/8XjMbT7uNAJAnZna2mb3fzP4p7jv/KH1mAEiPmf3XeBzjc2Y2b2an02fGKCFohlOYWUHSWyVVJD1R0qyZPTHdVgFA7jwg6bfc/QmSniLpZfG++FWS/s7dL5T0d/F1AMDwvFLSbR3X/0jSm+L98jclvSSVVgFAfr1F0t+6+/dJepKifTR9ZgBIgZntk/QKSWV3/wFJBUmXiz4zRghBM2zkIkkr7v4ld1+VdK2kS1NuEwDkirufcPdb4v/frejkf5+i/fG74ru9S9LPpdNCAMgfMztX0k9Lujq+bpJ+UtL747uwXwaAITKzh0u6WNI7JMndV93930WfGQDSdJqkM8zsNElnSjoh+swYIQTNsJF9kr7acf1YvA0AkAIze5ykSUk1Sd/t7iekKLAm6dHptQwAcufNkv67pLX4+ndK+nd3fyC+Tr8ZAIbr8ZLukvRncencq82sKPrMAJAKdz8u6Q2SvqIoWPYtSUdFnxkjhKAZNmIbbPOhtwIAIDMrSbpO0m+6+7fTbg8A5JWZzUj6ursf7dy8wV3pNwPA8Jwm6cmS3ubuk5KaohQjAKQmXkPyUkkXSHqMpKKiJYDWo8+MzCJoho0ck3Rex/VzJd2ZUlsAILfM7GGKAmbvcfcPxJu/ZmZ749v3Svp6Wu0DgJx5mqSfNbM7FJUv/0lFmWdnx6VnJPrNADBsxyQdc/dafP39ioJo9JkBIB0/JenL7n6Xu98v6QOSnir6zBghBM2wkZslXWhmF5jZuKLFGo+k3CYAyJV4nZx3SLrN3d/YcdMRSS+M//9CSR8adtsAII/c/dXufq67P05R//jv3f2XJH1U0vPiu7FfBoAhcveTkr5qZt8bb3qmpM+LPjMApOUrkp5iZmfG4xrt/TJ9ZowMcycTEqcys+comjlbkPROd39dyk0CgFwxsx+TdJOkz+qhtXNeo2hds/dJOl9RZ/T57v6NVBoJADllZk+X9NvuPmNmj1eUefYoSXVJV7j7fWm2DwDyxMwmJF0taVzSlyS9SNEkcfrMAJACM/t9Sb8g6QFF/eNfVbSGGX1mjASCZgAAAAAAAAAAAMg9yjMCAAAAAAAAAAAg9wiaAQAAAAAAAAAAIPcImgEAAAAAAAAAACD3CJoBAAAAAAAAAAAg9wiaAQAAAAAAAAAAIPcImgEAAADAAJhZy8yWzexzZvbXZnZ2Btr0mhSf+1fM7P+k9fwAAAAAsBWCZgAAAAAwGP/h7hPu/gOSviHpZWk3SFJqQTMAAAAAyDqCZgAAAAAweJ+UtK99xcx+x8xuNrPPmNnvd2z/XTP7gpl9xMzmzey34+0fM7Ny/P/vMrM74v8XzOyPOx7rpfH2vWb28Y5Mtx83s9dLOiPe9h4zK5rZ35jZP8b3+YX1jY6f903xY91mZj9iZh8ws382sz/ouN9fmdlRM7vVzK7s2P4iM7vdzG6U9LSO7eeY2XVxu282s6cJAAAAAFJ2WtoNAAAAAICQmVlB0jMlvSO+fomkCyVdJMkkHTGziyU1JV0uaVLRudotko5u8fAvkfQtd/8RM/sOSf/PzK6X9J8kLbr76+LnP9PdbzKzl7v7RNyOyyTd6e4/HV9/xCbPseruF5vZKyV9SNIPK8qc+6KZvcnd/03Si939G2Z2hqSbzew6SeOSfj++/7ckfVRSPX7Mt0h6k7v/g5mdL2lR0hO2834CAAAAwKAQNAMAAACAwTjDzJYlPU5R8OuGePsl8b92AKmkKIh2lqQPuvs9kmRmR7bxHJdI+iEze158/RHxY90s6Z1m9jBJf+Xuyxv87WclvcHM/kjSgrvftMlzHOm4/63ufiJu35cknSfp3yS9wsyeG9/vvLgNeyR9zN3viu//XkkH4vv8lKQnmln7OR5uZme5+93beM0AAAAAMBCUZwQAAACAwfiPOKvrsYqyrtprmpmkP4zXO5tw9/3u/o74Nt/ksR7QQ+dvp3dsN0n/peOxLnD3693945IulnRc0rvN7JfXP6C7364oC+yzkv7QzH5vk+e+L75c6/h/+/ppZvZ0RUGwH3X3JykKBrbbuNnrGYvv3273PgJmAAAAANJG0AwAAAAABsjdvyXpFZJ+O878WpT0YjMrSZKZ7TOzR0v6uKTnmtkZZnaWpJ/peJg7FAW4JOl5HdsXJf1G/LgyswPxWmWPlfR1d3+7orKQT47vf3/HfR8j6R53v0bSGzru069HSPqmu99jZt8n6Snx9pqkp5vZd8bP+fyOv7le0svbV8xsYofPDQAAAACJoTwjAAAAAAyYu9fN7B8lXe7u7zazJ0j6ZFyesCHpCne/JS5huCzpXyR1lkt8g6T3mdkLJP19x/arFZV/vMWiB7tL0s9Jerqk3zGz++PHb2eaXSXpM2Z2i6Q/l/THZrYm6X5Jv7HDl/e3kn7dzD4j6QuSPhW/5hNm9lpJn5R0QtEabYX4b14h6a3x35ymKGD46zt8fgAAAABIhLlvVi0DAAAAAJCWOODUcPc3pN0WAAAAAMgDyjMCAAAAAAAAAAAg98g0AwAAAAAAAAAAQO6RaQYAAAAAAAAAAIDcI2gGAAAAAAAAAACA3CNoBgAAAAAAAAAAgNwjaAYAAAAAAAAAAIDcI2gGAAAAAAAAAACA3CNoBgAAAAAAAAAAgNz7/yfnauRJYaAwAAAAAElFTkSuQmCC\n"}]},"apps":[],"runtimeInfos":{},"progressUpdateIntervalMs":500,"jobName":"paragraph_1597958173577_1190291426","id":"paragraph_1591860123109_1248831991","dateCreated":"2020-08-20 21:16:13.577","status":"READY"},{"text":"%python.ipython\n","user":"anonymous","dateUpdated":"2020-08-20 21:16:13.577","config":{},"settings":{"params":{},"forms":{}},"apps":[],"runtimeInfos":{},"progressUpdateIntervalMs":500,"jobName":"paragraph_1597958173577_538284345","id":"paragraph_1597047441935_258792906","dateCreated":"2020-08-20 21:16:13.577","status":"READY"}],"name":"Log Analysis-Zeppelin","id":"2FJF9WE51","defaultInterpreterGroup":"spark","version":"0.9.0-preview2","noteParams":{},"noteForms":{},"angularObjects":{},"config":{"isZeppelinNotebookCronEnable":false},"info":{}}
diff --git a/public/components/notebooks/docs/poc/OpenSearch_Dashboards_Embeddable_Documentation.md b/public/components/notebooks/docs/poc/OpenSearch_Dashboards_Embeddable_Documentation.md
new file mode 100644
index 0000000000..a7ac63ece6
--- /dev/null
+++ b/public/components/notebooks/docs/poc/OpenSearch_Dashboards_Embeddable_Documentation.md
@@ -0,0 +1,55 @@
+# OpenSearch Dashboards Embeddable API & Embedding Visualizations
+
+**NOTE:** The embeddable API and Visualizations have been in high flux for past 6 releases 7.4→7.9 versions in OpenSearch Dashboards
+
+## **In Version 7.5 and older**
+
+1. [Elastic blog](https://www.elastic.co/blog/developing-new-kibana-visualizations) on embedding Visualization
+2. [Test Plugin](https://github.com/elastic/kibana/tree/7.5/test/plugin_functional/plugins/kbn_tp_visualize_embedding) for OpenSearch Dashboards Visualization embedding
+
+**Between 7.6 and 7.8 - Embeddable API has changed at a high frequency, better to use it from 7.9**
+
+## **Embeddable API - Situation post 7.9 update**
+
+- Embeddables are re-usable widgets that can be rendered in any environment or plugin. Developers can embed them directly in their plugin. End users can dynamically add them to any embeddable _containers_.
+- Containers are a special type of embeddable that can contain nested embeddables. Embeddables can be dynamically added to embeddable _containers_. _Currently only dashboard uses this interface._
+
+![Embeddable API](../dev/images/Embeddable_API.png)
+
+* [Source](https://github.com/elastic/kibana/issues/19875)
+* [Code](https://github.com/elastic/kibana/tree/master/src/plugins/embeddable)
+* [README](https://github.com/elastic/kibana/blob/master/src/plugins/embeddable/README.md)
+
+1. Visualizations, Saved Search and Dashboard embeddable are part of this API now.
+2. Embeddable Factory allows to create objects:
+ 1. with “.create()” menthod → needs input of data/source/query/time range explicitly
+ 2. with “.createFromSavedObject()” method → either inherits values from containers or takes from explicit input provided
+3. Each of the above has a implementation has to inherit an embeddable & Factory API like:
+ 1. [Viz. Embeddable](https://github.com/elastic/kibana/blob/master/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts) & [Factory](https://github.com/elastic/kibana/blob/master/src/plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx)
+ 2. [Creating Custom Embeddable Example](https://github.com/elastic/kibana/blob/master/examples/embeddable_examples/public/multi_task_todo/multi_task_todo_embeddable.tsx) & [Factory](https://github.com/elastic/kibana/blob/master/examples/embeddable_examples/public/multi_task_todo/multi_task_todo_embeddable_factory.ts) by Value
+ 3. [Creating Custom Embeddable Example](https://github.com/elastic/kibana/blob/master/examples/embeddable_examples/public/todo/todo_ref_embeddable.tsx) & [Factory](https://github.com/elastic/kibana/blob/master/examples/embeddable_examples/public/todo/todo_ref_embeddable_factory.tsx) by reference
+4. [Visualizations Embeddable API Code](https://github.com/streamich/kibana/tree/master/src/plugins/visualizations/public/embeddable)
+5. [Dashboard Container](https://github.com/elastic/kibana/blob/master/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx) is exposed as an embeddable - to have multiple embeddable in a GRID like structure just like the Dashboard Plugin.
+
+**Embeddable Examples**
+
+- Examples folder in OpenSearch Dashboards has all the usage samples for new APIs
+- Use to create new embeddable objects
+- [Embeddable Examples](https://github.com/elastic/kibana/tree/master/examples/embeddable_examples) shows how to create new embeddable inheriting the API
+- [Embeddable Explorer](https://github.com/elastic/kibana/tree/master/examples/embeddable_explorer)shows usage of these embeddable examples in a Panel Container
+- [Dashboard Embeddable](https://github.com/elastic/kibana/tree/master/examples/dashboard_embeddable_examples) shows usage of these embeddable examples in a Dashboard Container
+
+**Embeddable Renderer**
+
+- The OpenSearch Dashboards react Element/Prop to create new embeddable objects: [Code](https://github.com/elastic/kibana/blob/master/src/plugins/embeddable/public/lib/embeddables/embeddable_renderer.tsx)
+- Embeddable container use the renderer to create/update each child(an embeddable object)
+ - [Example Dashboard Container](https://github.com/elastic/kibana/blob/master/src/plugins/dashboard/public/application/embeddable/dashboard_container_by_value_renderer.tsx)
+ - [Example of Static Embedding](https://github.com/elastic/kibana/blob/master/examples/embeddable_explorer/public/hello_world_embeddable_example.tsx#L59) (without factory)
+ - [Example of Embedding with factory.create() method](https://github.com/elastic/kibana/blob/master/examples/embeddable_explorer/public/hello_world_embeddable_example.tsx#L73) (with factory)
+
+## Embedding Visualizations in Notebooks Plugin
+
+- Notebooks use embeddable API with dashboard containers for embedding visualizations
+- Dashboard containers allow loading saved objects by Id
+- Notebook paragraphs store the dashboard container object as json string in input cells
+- For storing visualizations in Zeppelin input cells, the json string is stored with a prefix “%sh #{JSON_STRING}”. Making the Json object look like a comment so that, it doesn’t interrupt running the whole notebook.
diff --git a/public/components/notebooks/docs/poc/Zeppelin_OpenSearch_Storage.md b/public/components/notebooks/docs/poc/Zeppelin_OpenSearch_Storage.md
new file mode 100644
index 0000000000..256a9ff487
--- /dev/null
+++ b/public/components/notebooks/docs/poc/Zeppelin_OpenSearch_Storage.md
@@ -0,0 +1,67 @@
+# **Custom OpenSearch Storage in Zeppelin**
+
+### **Requirement:**
+
+- Use Zeppelin as a backend service for OpenSearch Dashboards Notebooks and store notebooks as OpenSearch indices
+- Use Zeppelin’s storage adaptor interface and implement a new storage adaptor using OpenSearch Client
+
+### **Design:**
+
+- [“Transport client API“](https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/transport-client.html) is getting deprecated in favor of high level client.
+- Finalized, [“High level client API”](https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.8/java-rest-high.html) for ease of use and minimal operations needed for Adaptor.
+- Notebooks will be indexed as* .notebooks/\_doc/{Unique_id} →* Unique ID is generated by zeppelin
+
+### **Design Details:**
+
+1. Implements the interface common for all Zeppelin Storage adaptors
+2. Implementation of functions in OpenSearch Zeppelin storage adaptor:
+
+ - Init - Get all config params
+ - List - List all notebooks
+ - Get - fetch a notebook
+ - save - save a notebook
+ - remove - a note
+ - close - client connection
+ - Upgrade client to Https requests - Done using keystore
+
+### **Usage:**
+
+1. POC for OpenSearch adapter is stored in branch 'zeppelin-opensearch' of dashboards-notebooks
+```
+git checkout zeppelin-opensearch
+```
+2. Clone Apache Zeppelin and checkout to 'v0.9.0-preview2' branch in a separate folder
+```
+cd /your/folder/
+git clone https://github.com/apache/zeppelin.git
+cd zeppelin
+git checkout v0.9.0-preview2
+```
+3. Apply patch from dashboards-notebooks
+```
+git apply /path/to/zeppelin-patch
+```
+4. Once, in this branch copy "opensearch" storage adaptor to your zeppelin files
+```
+cp -r /path/to/dashboards-notebooks/zeppelin/zeppelin-plugins/notebookrepo/opensearch path/to/your/zeppelin
+```
+4. Add OpenSearch storage property in zeppelin config file "conf/zeppelin-site.xml" and you should comment default git storage
+```
+
+ zeppelin.notebook.storage
+ org.apache.zeppelin.notebook.repo.OpenSearchNotebookRepo
+ versioned notebook persistence layer implementation
+
+
+
+```
+5. [Build Zeppelin](https://zeppelin.apache.org/docs/0.9.0/setup/basics/how_to_build.html) using Open-JDK 8
+```
+ mvn clean package -DskipTests
+```
diff --git a/public/components/notebooks/docs/poc/docs/Zeppelin_OpenSearch_Storage.md b/public/components/notebooks/docs/poc/docs/Zeppelin_OpenSearch_Storage.md
new file mode 100644
index 0000000000..2449ca6723
--- /dev/null
+++ b/public/components/notebooks/docs/poc/docs/Zeppelin_OpenSearch_Storage.md
@@ -0,0 +1,73 @@
+# **Custom OpenSearch Storage in Zeppelin**
+
+### **Requirement:**
+
+- Use Zeppelin as a backend service for OpenSearch Dashboards Notebooks and store notebooks as indices
+- Use Zeppelin’s storage adaptor interface and implement a new storage adaptor using Elasticsearch Client
+
+### **Design:**
+
+- [“Transport client API“](https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/transport-client.html) is getting deprecated in favor of high level client.
+- Finalized, [“High level client API”](https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.8/java-rest-high.html) for ease of use and minimal operations needed for Adaptor.
+- Notebooks will be indexed as* .notebooks/\_doc/{Unique_id} →* Unique ID is generated by zeppelin
+
+### **Design Details:**
+
+1. Implements the interface common for all Zeppelin Storage adaptors
+2. Implementation of functions in OpenSearch Zeppelin storage adaptor:
+
+ - Init - Get all config params
+ - List - List all notebooks
+ - Get - fetch a notebook
+ - save - save a notebook
+ - remove - a note
+ - close - client connection
+ - Upgrade client to Https requests - Done using keystore
+
+### **Usage:**
+
+
+1. Clone [dashbaords-notebooks](https://github.com/opensearch-project/dashboards-notebooks/) repository
+
+2. Clone [Apache Zeppelin](https://github.com/apache/zeppelin) and checkout to 'v0.9.0-preview2' branch in a separate folder
+
+```
+cd zeppelin
+git checkout v0.9.0-preview2
+```
+
+3. Apply patch from dashboards-notebooks
+
+```
+git apply /path/to/dashboards-notebooks/poc/zeppelin-patch
+```
+
+4. Once, in this branch copy "opensearch" storage adaptor to your zeppelin files
+
+```
+cp -r /path/to/dashboards-notebooks/poc/zeppelin/zeppelin-plugins/notebookrepo/opensearch path/to/your/zeppelin/zeppelin-plugins/notebookrepo/.
+```
+
+5. Add OpenSearch storage property in zeppelin config file "conf/zeppelin-site.xml" and you should comment default git storage
+
+```
+
+ zeppelin.notebook.storage
+ org.apache.zeppelin.notebook.repo.OpenSearchNotebookRepo
+ versioned notebook persistence layer implementation
+
+
+
+```
+
+6. [Build Zeppelin](https://zeppelin.apache.org/docs/0.9.0/setup/basics/how_to_build.html) using Open-JDK 8
+
+```
+ mvn clean package -DskipTests
+```
diff --git a/public/components/notebooks/docs/poc/zeppelin-patch b/public/components/notebooks/docs/poc/zeppelin-patch
new file mode 100644
index 0000000000..e6f8611879
--- /dev/null
+++ b/public/components/notebooks/docs/poc/zeppelin-patch
@@ -0,0 +1,3057 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+diff --git a/elasticsearch/pom.xml b/elasticsearch/pom.xml
+index 13bc6d469..bbdde076a 100644
+--- a/elasticsearch/pom.xml
++++ b/elasticsearch/pom.xml
+@@ -23,25 +23,26 @@
+
+ zeppelin-interpreter-parent
+ org.apache.zeppelin
+- 0.9.0-preview2
++ 0.9.0-SNAPSHOT
+ ../zeppelin-interpreter-parent/pom.xml
+
+
+ zeppelin-elasticsearch
+ jar
+- 0.9.0-preview2
++ 0.9.0-SNAPSHOT
+ Zeppelin: Elasticsearch interpreter
+
+
+ elasticsearch
+- 2.4.3
+- 4.0.2
++ 7.8.0
++ 4.1.4
+ 18.0
+ 0.1.6
+ 1.4.9
+
+
+
++
+
+ org.opensearch
+ elasticsearch
+@@ -58,11 +59,11 @@
+ commons-lang3
+
+
+-
+- org.apache.httpcomponents
+- httpasyncclient
+- ${httpasyncclient.version}
+-
++
++
++
++
++
+
+
+ com.google.guava
+diff --git a/elasticsearch/src/main/java/org/apache/zeppelin/elasticsearch/ElasticsearchInterpreter.java b/elasticsearch/src/main/java/org/apache/zeppelin/elasticsearch/ElasticsearchInterpreter.java
+index 45b37c4eb..d7987a011 100644
+--- a/elasticsearch/src/main/java/org/apache/zeppelin/elasticsearch/ElasticsearchInterpreter.java
++++ b/elasticsearch/src/main/java/org/apache/zeppelin/elasticsearch/ElasticsearchInterpreter.java
+@@ -21,19 +21,6 @@ import com.google.gson.Gson;
+ import com.google.gson.GsonBuilder;
+ import com.google.gson.JsonObject;
+
+-import org.apache.commons.lang3.StringUtils;
+-import org.opensearch.common.xcontent.XContentBuilder;
+-import org.opensearch.common.xcontent.XContentFactory;
+-import org.opensearch.common.xcontent.XContentHelper;
+-import org.opensearch.search.aggregations.Aggregation;
+-import org.opensearch.search.aggregations.Aggregations;
+-import org.opensearch.search.aggregations.InternalMultiBucketAggregation;
+-import org.opensearch.search.aggregations.bucket.InternalSingleBucketAggregation;
+-import org.opensearch.search.aggregations.bucket.MultiBucketsAggregation;
+-import org.opensearch.search.aggregations.metrics.InternalMetricsAggregation;
+-import org.slf4j.Logger;
+-import org.slf4j.LoggerFactory;
+-
+ import java.io.IOException;
+ import java.util.ArrayList;
+ import java.util.Arrays;
+@@ -48,7 +35,6 @@ import java.util.Set;
+ import java.util.TreeSet;
+ import java.util.regex.Matcher;
+ import java.util.regex.Pattern;
+-
+ import com.github.wnameless.json.flattener.JsonFlattener;
+
+ import org.apache.zeppelin.completer.CompletionType;
+@@ -57,12 +43,25 @@ import org.apache.zeppelin.elasticsearch.action.AggWrapper;
+ import org.apache.zeppelin.elasticsearch.action.HitWrapper;
+ import org.apache.zeppelin.elasticsearch.client.ElasticsearchClient;
+ import org.apache.zeppelin.elasticsearch.client.HttpBasedClient;
+-import org.apache.zeppelin.elasticsearch.client.TransportBasedClient;
+ import org.apache.zeppelin.interpreter.Interpreter;
+ import org.apache.zeppelin.interpreter.InterpreterContext;
+ import org.apache.zeppelin.interpreter.InterpreterResult;
+ import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
+
++import org.apache.commons.lang3.StringUtils;
++import org.opensearch.common.Strings;
++import org.opensearch.common.xcontent.ToXContent;
++import org.opensearch.common.xcontent.XContentBuilder;
++import org.opensearch.common.xcontent.XContentFactory;
++import org.opensearch.search.aggregations.Aggregation;
++import org.opensearch.search.aggregations.Aggregations;
++import org.opensearch.search.aggregations.InternalMultiBucketAggregation;
++import org.opensearch.search.aggregations.bucket.InternalSingleBucketAggregation;
++import org.opensearch.search.aggregations.bucket.MultiBucketsAggregation;
++import org.opensearch.search.aggregations.metrics.InternalNumericMetricsAggregation;
++import org.slf4j.Logger;
++import org.slf4j.LoggerFactory;
++
+ /**
+ * Elasticsearch Interpreter for Zeppelin.
+ */
+@@ -70,25 +69,25 @@ public class ElasticsearchInterpreter extends Interpreter {
+ private static Logger logger = LoggerFactory.getLogger(ElasticsearchInterpreter.class);
+
+ private static final String HELP = "Elasticsearch interpreter:\n"
+- + "General format: /// \n"
+- + " - indices: list of indices separated by commas (depends on the command)\n"
+- + " - types: list of document types separated by commas (depends on the command)\n"
+- + "Commands:\n"
+- + " - search /indices/types \n"
+- + " . indices and types can be omitted (at least, you have to provide '/')\n"
+- + " . a query is either a JSON-formatted query, nor a lucene query\n"
+- + " - size \n"
+- + " . defines the size of the result set (default value is in the config)\n"
+- + " . if used, this command must be declared before a search command\n"
+- + " - count /indices/types \n"
+- + " . same comments as for the search\n"
+- + " - get /index/type/id\n"
+- + " - delete /index/type/id\n"
+- + " - index /index/type/id \n"
+- + " . the id can be omitted, elasticsearch will generate one";
++ + "General format: /// \n"
++ + " - indices: list of indices separated by commas (depends on the command)\n"
++ + " - types: list of document types separated by commas (depends on the command)\n"
++ + "Commands:\n"
++ + " - search /indices/types \n"
++ + " . indices and types can be omitted (at least, you have to provide '/')\n"
++ + " . a query is either a JSON-formatted query, nor a lucene query\n"
++ + " - size \n"
++ + " . defines the size of the result set (default value is in the config)\n"
++ + " . if used, this command must be declared before a search command\n"
++ + " - count /indices/types \n"
++ + " . same comments as for the search\n"
++ + " - get /index/type/id\n"
++ + " - delete /index/type/id\n"
++ + " - index /index/type/id \n"
++ + " . the id can be omitted, elasticsearch will generate one";
+
+ protected static final List COMMANDS = Arrays.asList(
+- "count", "delete", "get", "help", "index", "search");
++ "count", "delete", "get", "help", "index", "search");
+
+ private static final Pattern FIELD_NAME_PATTERN = Pattern.compile("\\[\\\\\"(.+)\\\\\"\\](.*)");
+
+@@ -119,20 +118,14 @@ public class ElasticsearchInterpreter extends Interpreter {
+ this.resultSize = Integer.parseInt(getProperty(ELASTICSEARCH_RESULT_SIZE));
+ } catch (final NumberFormatException e) {
+ this.resultSize = 10;
+- logger.error("Unable to parse " + ELASTICSEARCH_RESULT_SIZE + " : " +
+- getProperty(ELASTICSEARCH_RESULT_SIZE), e);
++ logger.error("Unable to parse " + ELASTICSEARCH_RESULT_SIZE + " : "
++ + getProperty(ELASTICSEARCH_RESULT_SIZE), e);
+ }
+
+- try {
+- if (StringUtils.isEmpty(clientType) || "transport".equals(clientType)) {
+- elsClient = new TransportBasedClient(getProperties());
+- } else if ("http".equals(clientType)) {
+- elsClient = new HttpBasedClient(getProperties());
+- } else {
+- logger.error("Unknown type of Elasticsearch client: " + clientType);
+- }
+- } catch (final IOException e) {
+- logger.error("Open connection with Elasticsearch", e);
++ if (StringUtils.isEmpty(clientType) || "http".equals(clientType)) {
++ elsClient = new HttpBasedClient(getProperties());
++ } else {
++ logger.error("Unknown type of Elasticsearch client: " + clientType);
+ }
+ }
+
+@@ -155,7 +148,8 @@ public class ElasticsearchInterpreter extends Interpreter {
+
+ if (elsClient == null) {
+ return new InterpreterResult(InterpreterResult.Code.ERROR,
+- "Problem with the Elasticsearch client, please check your configuration (host, port,...)");
++ "Problem with the Elasticsearch client, please check your configuration "
++ + "(host, port,...)");
+ }
+
+ String[] items = StringUtils.split(cmd.trim(), " ", 3);
+@@ -172,7 +166,7 @@ public class ElasticsearchInterpreter extends Interpreter {
+
+ if (lines.length < 2) {
+ return processHelp(InterpreterResult.Code.ERROR,
+- "Size cmd must be followed by a search");
++ "Size cmd must be followed by a search");
+ }
+
+ final String[] sizeLine = StringUtils.split(lines[0], " ", 2);
+@@ -230,7 +224,7 @@ public class ElasticsearchInterpreter extends Interpreter {
+
+ @Override
+ public List completion(String s, int i,
+- InterpreterContext interpreterContext) {
++ InterpreterContext interpreterContext) {
+ final List suggestions = new ArrayList<>();
+
+ for (final String cmd : COMMANDS) {
+@@ -243,8 +237,8 @@ public class ElasticsearchInterpreter extends Interpreter {
+
+ private void addAngularObject(InterpreterContext interpreterContext, String prefix, Object obj) {
+ interpreterContext.getAngularObjectRegistry().add(
+- prefix + "_" + interpreterContext.getParagraphId().replace("-", "_"),
+- obj, null, null);
++ prefix + "_" + interpreterContext.getParagraphId().replace("-", "_"),
++ obj, null, null);
+ }
+
+ private String[] getIndexTypeId(String[] urlItems) {
+@@ -257,8 +251,8 @@ public class ElasticsearchInterpreter extends Interpreter {
+ final String id = StringUtils.join(Arrays.copyOfRange(urlItems, 2, urlItems.length), '/');
+
+ if (StringUtils.isEmpty(index)
+- || StringUtils.isEmpty(type)
+- || StringUtils.isEmpty(id)) {
++ || StringUtils.isEmpty(type)
++ || StringUtils.isEmpty(id)) {
+ return null;
+ }
+
+@@ -288,7 +282,7 @@ public class ElasticsearchInterpreter extends Interpreter {
+
+ if (indexTypeId == null) {
+ return new InterpreterResult(InterpreterResult.Code.ERROR,
+- "Bad URL (it should be /index/type/id)");
++ "Bad URL (it should be /index/type/id)");
+ }
+
+ final ActionResponse response = elsClient.get(indexTypeId[0], indexTypeId[1], indexTypeId[2]);
+@@ -300,9 +294,9 @@ public class ElasticsearchInterpreter extends Interpreter {
+ addAngularObject(interpreterContext, "get", json);
+
+ return new InterpreterResult(
+- InterpreterResult.Code.SUCCESS,
+- InterpreterResult.Type.TEXT,
+- jsonStr);
++ InterpreterResult.Code.SUCCESS,
++ InterpreterResult.Type.TEXT,
++ jsonStr);
+ }
+
+ return new InterpreterResult(InterpreterResult.Code.ERROR, "Document not found");
+@@ -317,10 +311,10 @@ public class ElasticsearchInterpreter extends Interpreter {
+ * @return Result of the count request, it contains the total hits
+ */
+ private InterpreterResult processCount(String[] urlItems, String data,
+- InterpreterContext interpreterContext) {
++ InterpreterContext interpreterContext) {
+ if (urlItems.length > 2) {
+ return new InterpreterResult(InterpreterResult.Code.ERROR,
+- "Bad URL (it should be /index1,index2,.../type1,type2,...)");
++ "Bad URL (it should be /index1,index2,.../type1,type2,...)");
+ }
+
+ final ActionResponse response = searchData(urlItems, data, 0);
+@@ -328,9 +322,9 @@ public class ElasticsearchInterpreter extends Interpreter {
+ addAngularObject(interpreterContext, "count", response.getTotalHits());
+
+ return new InterpreterResult(
+- InterpreterResult.Code.SUCCESS,
+- InterpreterResult.Type.TEXT,
+- "" + response.getTotalHits());
++ InterpreterResult.Code.SUCCESS,
++ InterpreterResult.Type.TEXT,
++ "" + response.getTotalHits());
+ }
+
+ /**
+@@ -343,17 +337,17 @@ public class ElasticsearchInterpreter extends Interpreter {
+ * @return Result of the search request, it contains a tab-formatted string of the matching hits
+ */
+ private InterpreterResult processSearch(String[] urlItems, String data, int size,
+- InterpreterContext interpreterContext) {
++ InterpreterContext interpreterContext) {
+ if (urlItems.length > 2) {
+ return new InterpreterResult(InterpreterResult.Code.ERROR,
+- "Bad URL (it should be /index1,index2,.../type1,type2,...)");
++ "Bad URL (it should be /index1,index2,.../type1,type2,...)");
+ }
+
+ final ActionResponse response = searchData(urlItems, data, size);
+
+ addAngularObject(interpreterContext, "search",
+- (response.getAggregations() != null && response.getAggregations().size() > 0) ?
+- response.getAggregations() : response.getHits());
++ (response.getAggregations() != null && response.getAggregations().size() > 0)
++ ? response.getAggregations() : response.getHits());
+
+ return buildResponseMessage(response);
+ }
+@@ -368,16 +362,16 @@ public class ElasticsearchInterpreter extends Interpreter {
+ private InterpreterResult processIndex(String[] urlItems, String data) {
+ if (urlItems.length < 2 || urlItems.length > 3) {
+ return new InterpreterResult(InterpreterResult.Code.ERROR,
+- "Bad URL (it should be /index/type or /index/type/id)");
++ "Bad URL (it should be /index/type or /index/type/id)");
+ }
+
+ final ActionResponse response = elsClient.index(
+- urlItems[0], urlItems[1], urlItems.length == 2 ? null : urlItems[2], data);
++ urlItems[0], urlItems[1], urlItems.length == 2 ? null : urlItems[2], data);
+
+ return new InterpreterResult(
+- InterpreterResult.Code.SUCCESS,
+- InterpreterResult.Type.TEXT,
+- response.getHit().getId());
++ InterpreterResult.Code.SUCCESS,
++ InterpreterResult.Type.TEXT,
++ response.getHit().getId());
+ }
+
+ /**
+@@ -391,17 +385,17 @@ public class ElasticsearchInterpreter extends Interpreter {
+
+ if (indexTypeId == null) {
+ return new InterpreterResult(InterpreterResult.Code.ERROR,
+- "Bad URL (it should be /index/type/id)");
++ "Bad URL (it should be /index/type/id)");
+ }
+
+ final ActionResponse response =
+- elsClient.delete(indexTypeId[0], indexTypeId[1], indexTypeId[2]);
++ elsClient.delete(indexTypeId[0], indexTypeId[1], indexTypeId[2]);
+
+ if (response.isSucceeded()) {
+ return new InterpreterResult(
+- InterpreterResult.Code.SUCCESS,
+- InterpreterResult.Type.TEXT,
+- response.getHit().getId());
++ InterpreterResult.Code.SUCCESS,
++ InterpreterResult.Type.TEXT,
++ response.getHit().getId());
+ }
+
+ return new InterpreterResult(InterpreterResult.Code.ERROR, "Document not found");
+@@ -428,20 +422,34 @@ public class ElasticsearchInterpreter extends Interpreter {
+ InterpreterResult.Type resType = InterpreterResult.Type.TEXT;
+ String resMsg = "";
+
+- if (agg instanceof InternalMetricsAggregation) {
+- resMsg = XContentHelper.toString((InternalMetricsAggregation) agg).toString();
++ if (agg instanceof InternalNumericMetricsAggregation) {
++ try {
++ XContentBuilder builder = XContentFactory.jsonBuilder();
++ InternalNumericMetricsAggregation tempAgg = (InternalNumericMetricsAggregation) agg;
++ tempAgg.toXContent(builder, ToXContent.EMPTY_PARAMS);
++ resMsg = Strings.toString(builder);
++ } catch (IOException e) {
++ logger.error("Processing bucket: " + e.getMessage(), e);
++ }
+ } else if (agg instanceof InternalSingleBucketAggregation) {
+- resMsg = XContentHelper.toString((InternalSingleBucketAggregation) agg).toString();
++ try {
++ XContentBuilder builder = XContentFactory.jsonBuilder();
++ InternalSingleBucketAggregation tempAgg = (InternalSingleBucketAggregation) agg;
++ tempAgg.toXContent(builder, ToXContent.EMPTY_PARAMS);
++ resMsg = Strings.toString(builder);
++ } catch (IOException e) {
++ logger.error("Processing bucket: " + e.getMessage(), e);
++ }
+ } else if (agg instanceof InternalMultiBucketAggregation) {
+ final Set headerKeys = new HashSet<>();
+ final List> buckets = new LinkedList<>();
+ final InternalMultiBucketAggregation multiBucketAgg = (InternalMultiBucketAggregation) agg;
+-
+- for (final MultiBucketsAggregation.Bucket bucket : multiBucketAgg.getBuckets()) {
++ final List tempBuckets = multiBucketAgg.getBuckets();
++ for (final MultiBucketsAggregation.Bucket bucket : tempBuckets) {
+ try {
+ final XContentBuilder builder = XContentFactory.jsonBuilder();
+ bucket.toXContent(builder, null);
+- final Map bucketMap = JsonFlattener.flattenAsMap(builder.string());
++ final Map bucketMap = JsonFlattener.flattenAsMap(String.valueOf(builder));
+ headerKeys.addAll(bucketMap.keySet());
+ buckets.add(bucketMap);
+ } catch (final IOException e) {
+@@ -474,7 +482,6 @@ public class ElasticsearchInterpreter extends Interpreter {
+
+ private InterpreterResult buildAggResponseMessage(List aggregations) {
+ final InterpreterResult.Type resType = InterpreterResult.Type.TABLE;
+- String resMsg = "";
+
+ final Set headerKeys = new HashSet<>();
+ final List> buckets = new LinkedList<>();
+@@ -501,7 +508,7 @@ public class ElasticsearchInterpreter extends Interpreter {
+ buffer.deleteCharAt(buffer.length() - 1);
+ }
+
+- resMsg = buffer.toString();
++ String resMsg = buffer.toString();
+
+ return new InterpreterResult(InterpreterResult.Code.SUCCESS, resType, resMsg);
+ }
+@@ -527,7 +534,7 @@ public class ElasticsearchInterpreter extends Interpreter {
+ final Matcher fieldNameMatcher = FIELD_NAME_PATTERN.matcher(fieldName);
+ if (fieldNameMatcher.matches()) {
+ flattenMap.put(fieldNameMatcher.group(1) + fieldNameMatcher.group(2),
+- flattenJsonMap.get(fieldName));
++ flattenJsonMap.get(fieldName));
+ } else {
+ flattenMap.put(fieldName, flattenJsonMap.get(fieldName));
+ }
+@@ -571,8 +578,8 @@ public class ElasticsearchInterpreter extends Interpreter {
+ }
+
+ return new InterpreterResult(
+- InterpreterResult.Code.SUCCESS,
+- InterpreterResult.Type.TABLE,
+- buildSearchHitsResponseMessage(response));
++ InterpreterResult.Code.SUCCESS,
++ InterpreterResult.Type.TABLE,
++ buildSearchHitsResponseMessage(response));
+ }
+ }
+diff --git a/elasticsearch/src/main/java/org/apache/zeppelin/elasticsearch/client/HttpBasedClient.java b/elasticsearch/src/main/java/org/apache/zeppelin/elasticsearch/client/HttpBasedClient.java
+index 94528168f..e5c096edc 100644
+--- a/elasticsearch/src/main/java/org/apache/zeppelin/elasticsearch/client/HttpBasedClient.java
++++ b/elasticsearch/src/main/java/org/apache/zeppelin/elasticsearch/client/HttpBasedClient.java
+@@ -51,7 +51,8 @@ import org.apache.zeppelin.elasticsearch.action.HitWrapper;
+ */
+ public class HttpBasedClient implements ElasticsearchClient {
+ private static final String QUERY_STRING_TEMPLATE =
+- "{ \"query\": { \"query_string\": { \"query\": \"_Q_\", \"analyze_wildcard\": \"true\" } } }";
++ "{ \"query\": { \"query_string\": " +
++ "{ \"query\": \"_Q_\", \"analyze_wildcard\": \"true\" } } }";
+
+ private final String host;
+ private final int port;
+@@ -119,7 +120,7 @@ public class HttpBasedClient implements ElasticsearchClient {
+ // There are differences: to avoid problems with some special characters
+ // such as / and # in id, use a "terms" query
+ buffer.append("/_search?source=").append(URLEncoder
+- .encode("{\"query\":{\"terms\":{\"_id\":[\"" + id + "\"]}}}", "UTF-8"));
++ .encode("{\"query\":{\"terms\":{\"_id\":[\"" + id + "\"]}}}", "UTF-8"));
+ }
+ } else {
+ buffer.append("/").append(id);
+@@ -155,27 +156,27 @@ public class HttpBasedClient implements ElasticsearchClient {
+ final JsonNode body = new JsonNode(result.getBody());
+ if (body.getObject().has("_index")) {
+ response = new ActionResponse()
+- .succeeded(true)
+- .hit(new HitWrapper(
+- getFieldAsString(body, "_index"),
+- getFieldAsString(body, "_type"),
+- getFieldAsString(body, "_id"),
+- getFieldAsString(body, "_source")));
++ .succeeded(true)
++ .hit(new HitWrapper(
++ getFieldAsString(body, "_index"),
++ getFieldAsString(body, "_type"),
++ getFieldAsString(body, "_id"),
++ getFieldAsString(body, "_source")));
+ } else {
+ final JSONArray hits = getFieldAsArray(body.getObject(), "hits/hits");
+ final JSONObject hit = (JSONObject) hits.iterator().next();
+ response = new ActionResponse()
+- .succeeded(true)
+- .hit(new HitWrapper(
+- hit.getString("_index"),
+- hit.getString("_type"),
+- hit.getString("_id"),
+- hit.opt("_source").toString()));
++ .succeeded(true)
++ .hit(new HitWrapper(
++ hit.getString("_index"),
++ hit.getString("_type"),
++ hit.getString("_id"),
++ hit.opt("_source").toString()));
+ }
+ } else {
+ if (result.getStatus() == 404) {
+ response = new ActionResponse()
+- .succeeded(false);
++ .succeeded(false);
+ } else {
+ throw new ActionException(result.getBody());
+ }
+@@ -201,12 +202,12 @@ public class HttpBasedClient implements ElasticsearchClient {
+ if (isSucceeded) {
+ final JsonNode body = new JsonNode(result.getBody());
+ response = new ActionResponse()
+- .succeeded(true)
+- .hit(new HitWrapper(
+- getFieldAsString(body, "_index"),
+- getFieldAsString(body, "_type"),
+- getFieldAsString(body, "_id"),
+- null));
++ .succeeded(true)
++ .hit(new HitWrapper(
++ getFieldAsString(body, "_index"),
++ getFieldAsString(body, "_type"),
++ getFieldAsString(body, "_id"),
++ null));
+ } else {
+ throw new ActionException(result.getBody());
+ }
+@@ -227,9 +228,9 @@ public class HttpBasedClient implements ElasticsearchClient {
+ request = Unirest.put(getUrl(index, type, id, false));
+ }
+ request
+- .header("Accept", "application/json")
+- .header("Content-Type", "application/json")
+- .body(data).getHttpRequest();
++ .header("Accept", "application/json")
++ .header("Content-Type", "application/json")
++ .body(data).getHttpRequest();
+ if (StringUtils.isNotEmpty(username)) {
+ request.basicAuth(username, password);
+ }
+@@ -239,12 +240,12 @@ public class HttpBasedClient implements ElasticsearchClient {
+
+ if (isSucceeded) {
+ response = new ActionResponse()
+- .succeeded(true)
+- .hit(new HitWrapper(
+- getFieldAsString(result, "_index"),
+- getFieldAsString(result, "_type"),
+- getFieldAsString(result, "_id"),
+- null));
++ .succeeded(true)
++ .hit(new HitWrapper(
++ getFieldAsString(result, "_index"),
++ getFieldAsString(result, "_type"),
++ getFieldAsString(result, "_id"),
++ null));
+ } else {
+ throw new ActionException(result.getBody().toString());
+ }
+@@ -271,8 +272,8 @@ public class HttpBasedClient implements ElasticsearchClient {
+
+ try {
+ final HttpRequestWithBody request = Unirest
+- .post(getUrl(indices, types) + "/_search?size=" + size)
+- .header("Content-Type", "application/json");
++ .post(getUrl(indices, types) + "/_search?size=" + size)
++ .header("Content-Type", "application/json");
+
+ if (StringUtils.isNoneEmpty(query)) {
+ request.header("Accept", "application/json").body(query);
+@@ -289,8 +290,8 @@ public class HttpBasedClient implements ElasticsearchClient {
+ final long total = getFieldAsLong(result, "hits/total");
+
+ response = new ActionResponse()
+- .succeeded(true)
+- .totalHits(total);
++ .succeeded(true)
++ .totalHits(total);
+
+ if (containsAggs(result)) {
+ JSONObject aggregationsMap = body.getJSONObject("aggregations");
+@@ -305,11 +306,11 @@ public class HttpBasedClient implements ElasticsearchClient {
+ final Iterator buckets = aggResult.getJSONArray("buckets").iterator();
+ while (buckets.hasNext()) {
+ response.addAggregation(
+- new AggWrapper(AggregationType.MULTI_BUCKETS, buckets.next().toString()));
++ new AggWrapper(AggregationType.MULTI_BUCKETS, buckets.next().toString()));
+ }
+ } else {
+ response.addAggregation(
+- new AggWrapper(AggregationType.SIMPLE, aggregationsMap.toString()));
++ new AggWrapper(AggregationType.SIMPLE, aggregationsMap.toString()));
+ }
+ break; // Keep only one aggregation
+ }
+@@ -320,12 +321,12 @@ public class HttpBasedClient implements ElasticsearchClient {
+ while (iter.hasNext()) {
+ final JSONObject hit = (JSONObject) iter.next();
+ final Object data =
+- hit.opt("_source") != null ? hit.opt("_source") : hit.opt("fields");
++ hit.opt("_source") != null ? hit.opt("_source") : hit.opt("fields");
+ response.addHit(new HitWrapper(
+- hit.getString("_index"),
+- hit.getString("_type"),
+- hit.getString("_id"),
+- data.toString()));
++ hit.getString("_index"),
++ hit.getString("_type"),
++ hit.getString("_id"),
++ data.toString()));
+ }
+ }
+ } else {
+@@ -340,8 +341,8 @@ public class HttpBasedClient implements ElasticsearchClient {
+
+ private boolean containsAggs(HttpResponse result) {
+ return result.getBody() != null &&
+- (result.getBody().getObject().has("aggregations") ||
+- result.getBody().getObject().has("aggs"));
++ (result.getBody().getObject().has("aggregations") ||
++ result.getBody().getObject().has("aggs"));
+ }
+
+ @Override
+diff --git a/elasticsearch/src/main/java/org/apache/zeppelin/elasticsearch/client/TransportBasedClient.java b/elasticsearch/src/main/java/org/apache/zeppelin/elasticsearch/client/TransportBasedClient.java
+deleted file mode 100644
+index 2af37bd3c..000000000
+--- a/elasticsearch/src/main/java/org/apache/zeppelin/elasticsearch/client/TransportBasedClient.java
++++ /dev/null
+@@ -1,230 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one or more
+- * contributor license agreements. See the NOTICE file distributed with
+- * this work for additional information regarding copyright ownership.
+- * The ASF licenses this file to You under the Apache License, Version 2.0
+- * (the "License"); you may not use this file except in compliance with
+- * the License. You may obtain a copy of the License at
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS,
+- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+- * See the License for the specific language governing permissions and
+- * limitations under the License.
+- */
+-
+-package org.apache.zeppelin.elasticsearch.client;
+-
+-import com.google.gson.Gson;
+-import com.google.gson.GsonBuilder;
+-import com.google.gson.JsonSyntaxException;
+-
+-import org.apache.commons.lang3.StringUtils;
+-import org.opensearch.action.delete.DeleteResponse;
+-import org.opensearch.action.get.GetResponse;
+-import org.opensearch.action.index.IndexResponse;
+-import org.opensearch.action.search.SearchAction;
+-import org.opensearch.action.search.SearchRequestBuilder;
+-import org.opensearch.action.search.SearchResponse;
+-import org.opensearch.client.Client;
+-import org.opensearch.client.transport.TransportClient;
+-import org.opensearch.common.settings.Settings;
+-import org.opensearch.common.transport.InetSocketTransportAddress;
+-import org.opensearch.common.xcontent.XContentBuilder;
+-import org.opensearch.common.xcontent.XContentFactory;
+-import org.opensearch.common.xcontent.XContentHelper;
+-import org.opensearch.index.query.QueryBuilders;
+-import org.opensearch.search.SearchHit;
+-import org.opensearch.search.SearchHitField;
+-import org.opensearch.search.aggregations.Aggregation;
+-import org.opensearch.search.aggregations.Aggregations;
+-import org.opensearch.search.aggregations.InternalMultiBucketAggregation;
+-import org.opensearch.search.aggregations.bucket.InternalSingleBucketAggregation;
+-import org.opensearch.search.aggregations.bucket.MultiBucketsAggregation;
+-import org.opensearch.search.aggregations.metrics.InternalMetricsAggregation;
+-
+-import java.io.IOException;
+-import java.net.InetAddress;
+-import java.net.UnknownHostException;
+-import java.util.HashMap;
+-import java.util.HashSet;
+-import java.util.LinkedList;
+-import java.util.List;
+-import java.util.Map;
+-import java.util.Properties;
+-import java.util.Set;
+-
+-import org.apache.zeppelin.elasticsearch.ElasticsearchInterpreter;
+-import org.apache.zeppelin.elasticsearch.action.ActionResponse;
+-import org.apache.zeppelin.elasticsearch.action.AggWrapper;
+-import org.apache.zeppelin.elasticsearch.action.HitWrapper;
+-
+-/**
+- * Elasticsearch client using the transport protocol.
+- */
+-public class TransportBasedClient implements ElasticsearchClient {
+- private final Gson gson = new GsonBuilder().setPrettyPrinting().create();
+- private final Client client;
+-
+- public TransportBasedClient(Properties props) throws UnknownHostException {
+- final String host =
+- props.getProperty(ElasticsearchInterpreter.ELASTICSEARCH_HOST);
+- final int port = Integer.parseInt(
+- props.getProperty(ElasticsearchInterpreter.ELASTICSEARCH_PORT));
+- final String clusterName =
+- props.getProperty(ElasticsearchInterpreter.ELASTICSEARCH_CLUSTER_NAME);
+-
+- final Settings settings = Settings.settingsBuilder()
+- .put("cluster.name", clusterName)
+- .put(props)
+- .build();
+-
+- client = TransportClient.builder().settings(settings).build()
+- .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(host), port));
+- }
+-
+- @Override
+- public ActionResponse get(String index, String type, String id) {
+- final GetResponse getResp = client
+- .prepareGet(index, type, id)
+- .get();
+-
+- return new ActionResponse()
+- .succeeded(getResp.isExists())
+- .hit(new HitWrapper(
+- getResp.getIndex(),
+- getResp.getType(),
+- getResp.getId(),
+- getResp.getSourceAsString()));
+- }
+-
+- @Override
+- public ActionResponse delete(String index, String type, String id) {
+- final DeleteResponse delResp = client
+- .prepareDelete(index, type, id)
+- .get();
+-
+- return new ActionResponse()
+- .succeeded(delResp.isFound())
+- .hit(new HitWrapper(
+- delResp.getIndex(),
+- delResp.getType(),
+- delResp.getId(),
+- null));
+- }
+-
+- @Override
+- public ActionResponse index(String index, String type, String id, String data) {
+- final IndexResponse idxResp = client
+- .prepareIndex(index, type, id)
+- .setSource(data)
+- .get();
+-
+- return new ActionResponse()
+- .succeeded(idxResp.isCreated())
+- .hit(new HitWrapper(
+- idxResp.getIndex(),
+- idxResp.getType(),
+- idxResp.getId(),
+- null));
+- }
+-
+- @Override
+- public ActionResponse search(String[] indices, String[] types, String query, int size) {
+- final SearchRequestBuilder reqBuilder = new SearchRequestBuilder(
+- client, SearchAction.INSTANCE);
+- reqBuilder.setIndices();
+-
+- if (indices != null) {
+- reqBuilder.setIndices(indices);
+- }
+- if (types != null) {
+- reqBuilder.setTypes(types);
+- }
+-
+- if (!StringUtils.isEmpty(query)) {
+- // The query can be either JSON-formatted, nor a Lucene query
+- // So, try to parse as a JSON => if there is an error, consider the query a Lucene one
+- try {
+- @SuppressWarnings("rawtypes")
+- final Map source = gson.fromJson(query, Map.class);
+- reqBuilder.setExtraSource(source);
+- } catch (final JsonSyntaxException e) {
+- // This is not a JSON (or maybe not well formatted...)
+- reqBuilder.setQuery(QueryBuilders.queryStringQuery(query).analyzeWildcard(true));
+- }
+- }
+-
+- reqBuilder.setSize(size);
+-
+- final SearchResponse searchResp = reqBuilder.get();
+-
+- final ActionResponse actionResp = new ActionResponse()
+- .succeeded(true)
+- .totalHits(searchResp.getHits().getTotalHits());
+-
+- if (searchResp.getAggregations() != null) {
+- setAggregations(searchResp.getAggregations(), actionResp);
+- } else {
+- for (final SearchHit hit: searchResp.getHits()) {
+- // Fields can be found either in _source, or in fields (it depends on the query)
+- // => specific for elasticsearch's version < 5
+- //
+- String src = hit.getSourceAsString();
+- if (src == null) {
+- final Map hitFields = new HashMap<>();
+- for (final SearchHitField hitField : hit.getFields().values()) {
+- hitFields.put(hitField.getName(), hitField.getValues());
+- }
+- src = gson.toJson(hitFields);
+- }
+- actionResp.addHit(new HitWrapper(hit.getIndex(), hit.getType(), hit.getId(), src));
+- }
+- }
+-
+- return actionResp;
+- }
+-
+- private void setAggregations(Aggregations aggregations, ActionResponse actionResp) {
+- // Only the result of the first aggregation is returned
+- //
+- final Aggregation agg = aggregations.asList().get(0);
+-
+- if (agg instanceof InternalMetricsAggregation) {
+- actionResp.addAggregation(new AggWrapper(AggWrapper.AggregationType.SIMPLE,
+- XContentHelper.toString((InternalMetricsAggregation) agg).toString()));
+- } else if (agg instanceof InternalSingleBucketAggregation) {
+- actionResp.addAggregation(new AggWrapper(AggWrapper.AggregationType.SIMPLE,
+- XContentHelper.toString((InternalSingleBucketAggregation) agg).toString()));
+- } else if (agg instanceof InternalMultiBucketAggregation) {
+- final Set headerKeys = new HashSet<>();
+- final List> buckets = new LinkedList<>();
+- final InternalMultiBucketAggregation multiBucketAgg = (InternalMultiBucketAggregation) agg;
+-
+- for (final MultiBucketsAggregation.Bucket bucket : multiBucketAgg.getBuckets()) {
+- try {
+- final XContentBuilder builder = XContentFactory.jsonBuilder();
+- bucket.toXContent(builder, null);
+- actionResp.addAggregation(
+- new AggWrapper(AggWrapper.AggregationType.MULTI_BUCKETS, builder.string()));
+- } catch (final IOException e) {
+- // Ignored
+- }
+- }
+- }
+- }
+-
+- @Override
+- public void close() {
+- if (client != null) {
+- client.close();
+- }
+- }
+-
+- @Override
+- public String toString() {
+- return "TransportBasedClient []";
+- }
+-}
+diff --git a/elasticsearch/src/test/java/org/apache/zeppelin/elasticsearch/ElasticsearchInterpreterTest.java b/elasticsearch/src/test/java/org/apache/zeppelin/elasticsearch/ElasticsearchInterpreterTest.java
+index a806dc314..4cf42569a 100644
+--- a/elasticsearch/src/test/java/org/apache/zeppelin/elasticsearch/ElasticsearchInterpreterTest.java
++++ b/elasticsearch/src/test/java/org/apache/zeppelin/elasticsearch/ElasticsearchInterpreterTest.java
+@@ -23,10 +23,12 @@ import static org.junit.Assert.assertNotNull;
+
+ import org.apache.commons.lang3.RandomUtils;
+ import org.opensearch.action.admin.indices.delete.DeleteIndexRequest;
++import org.opensearch.action.support.WriteRequest;
+ import org.opensearch.client.Client;
+ import org.opensearch.common.settings.Settings;
++import org.opensearch.env.Environment;
++import org.opensearch.monitor.fs.FsInfo;
+ import org.opensearch.node.Node;
+-import org.opensearch.node.NodeBuilder;
+ import org.junit.AfterClass;
+ import org.junit.Assert;
+ import org.junit.BeforeClass;
+@@ -36,6 +38,7 @@ import org.junit.experimental.theories.Theory;
+ import org.junit.runner.RunWith;
+
+ import java.io.IOException;
++import java.nio.file.Path;
+ import java.util.ArrayList;
+ import java.util.Arrays;
+ import java.util.Date;
+@@ -72,7 +75,8 @@ public class ElasticsearchInterpreterTest {
+
+ @BeforeClass
+ public static void populate() throws IOException {
+- final Settings settings = Settings.settingsBuilder()
++
++ final Settings settings = Settings.builder()
+ .put("cluster.name", ELS_CLUSTER_NAME)
+ .put("network.host", ELS_HOST)
+ .put("http.port", ELS_HTTP_PORT)
+@@ -80,7 +84,8 @@ public class ElasticsearchInterpreterTest {
+ .put("path.home", ELS_PATH)
+ .build();
+
+- elsNode = NodeBuilder.nodeBuilder().settings(settings).node();
++ final Environment env = new Environment(settings, (Path) FsInfo.Path.EMPTY_PARAMS);
++ elsNode = new Node(env);
+ elsClient = elsNode.client();
+
+ elsClient.admin().indices().prepareCreate("logs")
+@@ -93,7 +98,7 @@ public class ElasticsearchInterpreterTest {
+
+ for (int i = 0; i < 48; i++) {
+ elsClient.prepareIndex("logs", "http", "" + i)
+- .setRefresh(true)
++ .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
+ .setSource(jsonBuilder()
+ .startObject()
+ .field("date", new Date())
+@@ -110,7 +115,7 @@ public class ElasticsearchInterpreterTest {
+
+ for (int i = 1; i < 3; i++) {
+ elsClient.prepareIndex("logs", "http", "very/strange/id#" + i)
+- .setRefresh(true)
++ .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
+ .setSource(jsonBuilder()
+ .startObject()
+ .field("date", new Date())
+@@ -141,7 +146,7 @@ public class ElasticsearchInterpreterTest {
+ }
+
+ @AfterClass
+- public static void clean() {
++ public static void clean() throws IOException {
+ if (transportInterpreter != null) {
+ transportInterpreter.close();
+ }
+diff --git a/pom.xml b/pom.xml
+index 7f4ec216b..cef5f418d 100644
+--- a/pom.xml
++++ b/pom.xml
+@@ -19,1824 +19,144 @@
+
+
+- 4.0.0
++ 4.0.0
++
++
++ zeppelin
++ org.apache.zeppelin
++ 0.9.0-preview2
++ ..
++
++
++ org.apache.zeppelin
++ zengine-plugins-parent
++ pom
++ 0.9.0-preview2
++ Zeppelin: Plugins Parent
++ Zeppelin Plugins Parent
++
++
++ provided
++
++
++
++ notebookrepo/s3
++ notebookrepo/github
++ notebookrepo/azure
++ notebookrepo/gcs
++ notebookrepo/zeppelin-hub
++ notebookrepo/filesystem
++ notebookrepo/mongo
++ notebookrepo/oss
++
++ launcher/k8s-standard
++ launcher/cluster
++ launcher/docker
++ launcher/yarn
++ launcher/flink
++
+
+- org.apache.zeppelin
+- zeppelin
+- pom
+- 0.9.0-preview2
+- Zeppelin
+- Zeppelin project
+- https://zeppelin.apache.org
+-
+-
+- org.apache
+- apache
+- 17
+-
+-
+-
+-
+- The Apache Software License, Version 2.0
+- https://www.apache.org/licenses/LICENSE-2.0.txt
+- repo
+-
+-
+-
+-
+- https://git-wip-us.apache.org/repos/asf/zeppelin.git
+- scm:git:https://git-wip-us.apache.org/repos/asf/zeppelin.git
+- scm:git:https://git-wip-us.apache.org/repos/asf/zeppelin.git
+-
+-
+- 2013
+-
+-
+- zeppelin-interpreter-parent
+- zeppelin-interpreter
+- zeppelin-interpreter-shaded
+- zeppelin-zengine
+- zeppelin-display
+- rlang
+- zeppelin-jupyter-interpreter
+- zeppelin-jupyter-interpreter-shaded
+- kotlin
+- groovy
+- spark
+- submarine
+- markdown
+- mongodb
+- angular
+- shell
+- livy
+- hbase
+- pig
+- jdbc
+- file
+- flink
+- ignite
+- influxdb
+- kylin
+- python
+- lens
+- cassandra
+- elasticsearch
+- bigquery
+- alluxio
+- scio
+- neo4j
+- sap
+- scalding
+- java
+- beam
+- hazelcastjet
+- geode
+- ksql
+- sparql
+- zeppelin-web
+- zeppelin-server
+- zeppelin-jupyter
+- zeppelin-plugins
+- zeppelin-distribution
+-
+-
+-
+-
+- 1.8
+- 2.10.5
+- ${scala.2.10.version}
+- 2.10
+- 2.11.8
+- 3.0.7
+- 1.12.5
+-
+-
+- v12.3.1
+- 6.9.0
+- 1.6
+-
+-
+- 1.7.30
+- 1.2.17
+- 0.13.0
+- 2.2
+- 0.2.1
+- 9.4.27.v20200227
+- 4.4.1
+- 4.5.1
+- 4.0.2
+- 1.20
+- 3.10
+- 1.9
+- 1.3
+- 1.14
+- 2.6
+- 3.2.2
+- 1.1.1
+- 1.4
+- 1.4.2
+- 2.9.9
+- 1.60
+-
+- 2.7.7
+- 2.6.5
+- 3.0.3
+- 3.1.3
+- 3.2.0
+- ${hadoop2.7.version}
+-
+- provided
+- 2.3.2
+- 1.4.0
+- 1.13.1
+-
+-
+- 4.12
+- 1.10.19
+- 1.7.0
+- 1.6.4
+-
+-
+- 1.8
+- 3.2.0
+- 1.7.7
+- 1.7
+- 1.4
+- 2.17
+- 3.1.0
+- 2.7
+- 3.8.1
+- 3.1.2
+- 2.8.2
+- 1.3.0
+- 2.8
+- 3.0.0-M3
+- 1.6.0
+- 2.17
+- 4.0.0
+- 1.6
+- 3.0.0-M1
+- 3.2.0
+- 3.2.0
+- 1.8
+- 1.0.0
+- 0.5.0
+- 0.13
+- 1.7.0
+- 3.1.0
+- 1.4
+- 3.4.6
+- 2.15.2
+- 1.7.1
+- 2.0.0
+- 1.11.2
+- 3.2.2
+- 3.2.1
+- 2.17
+- 1.0.2
+-
+- false
+-
+- 512m
+-
+-
+-
+-
+-
+-
+
+-
+-
+- org.slf4j
+- slf4j-api
+- ${slf4j.version}
+-
+-
+-
+- org.slf4j
+- slf4j-log4j12
+- ${slf4j.version}
+-
+-
+-
+- log4j
+- log4j
+- ${log4j.version}
+-
+-
+-
+- org.apache.thrift
+- libthrift
+- ${libthrift.version}
+-
+-
+- javax.annotation
+- javax.annotation-api
+-
+-
+-
+-
+-
+- org.apache.httpcomponents
+- httpcore
+- ${httpcomponents.core.version}
+-
+-
+-
+- org.apache.httpcomponents
+- httpclient
+- ${httpcomponents.client.version}
+-
+-
+-
+- org.apache.httpcomponents
+- httpasyncclient
+- ${httpcomponents.asyncclient.version}
+-
+-
+-
+- org.apache.commons
+- commons-lang3
+- ${commons.lang3.version}
+-
+-
+-
+- org.apache.commons
+- commons-exec
+- ${commons.exec.version}
+-
+-
+-
+- com.google.code.gson
+- gson
+- ${gson.version}
+-
+-
+-
+- org.danilopianini
+- gson-extras
+- ${gson-extras.version}
+-
+-
+-
+- commons-configuration
+- commons-configuration
+- ${commons.configuration.version}
+-
+-
+-
+- commons-codec
+- commons-codec
+- ${commons.codec.version}
+-
+-
+-
+- commons-io
+- commons-io
+- ${commons.io.version}
+-
+-
+-
+- commons-collections
+- commons-collections
+- ${commons.collections.version}
+-
+-
+-
+- commons-logging
+- commons-logging
+- ${commons.logging.version}
+-
+-
+-
+- commons-cli
+- commons-cli
+- ${commons.cli.version}
+-
+-
+-
+- joda-time
+- joda-time
+- ${joda.version}
+-
+-
+-
+-
+- org.apache.shiro
+- shiro-core
+- ${shiro.version}
+-
+-
+- org.apache.shiro
+- shiro-web
+- ${shiro.version}
+-
+-
+- org.apache.shiro
+- shiro-config-core
+- ${shiro.version}
+-
+-
+-
+- org.bouncycastle
+- bcpkix-jdk15on
+- ${bouncycastle.version}
+-
+-
+-
+- com.amazonaws
+- aws-java-sdk-s3
+- ${aws.sdk.s3.version}
+-
+-
+-
+- org.codehaus.jettison
+- jettison
+- ${jettison.version}
+-
+-
+-
+- org.apache.hadoop
+- hadoop-client
+- ${hadoop.version}
+- ${hadoop.deps.scope}
+-
+-
+- com.sun.jersey
+- jersey-core
+-
+-
+- com.sun.jersey
+- jersey-json
+-
+-
+- com.sun.jersey
+- jersey-client
+-
+-
+- com.sun.jersey
+- jersey-server
+-
+-
+- javax.servlet
+- servlet-api
+-
+-
+- org.apache.avro
+- avro
+-
+-
+- org.apache.jackrabbit
+- jackrabbit-webdav
+-
+-
+- io.netty
+- netty
+-
+-
+- io.netty
+- netty-all
+-
+-
+- commons-httpclient
+- commons-httpclient
+-
+-
+- org.eclipse.jgit
+- org.eclipse.jgit
+-
+-
+- com.jcraft
+- jsch
+-
+-
+- org.apache.commons
+- commons-compress
+-
+-
+- xml-apis
+- xml-apis
+-
+-
+- xerces
+- xercesImpl
+-
+-
+- com.google.guava
+- guava
+-
+-
+- com.google.code.findbugs
+- jsr305
+-
+-
+- org.apache.commons
+- commons-math3
+-
+-
+- com.fasterxml.jackson.core
+- jackson-annotations
+-
+-
+- com.nimbusds
+- nimbus-jose-jwt
+-
+-
+- org.eclipse.jetty
+- jetty-xml
+-
+-
+- org.eclipse.jetty
+- jetty-servlet
+-
+-
+- org.eclipse.jetty
+- jetty-util
+-
+-
+- commons-beanutils
+- commons-beanutils
+-
+-
+- org.apache.commons
+- commons-configuration2
+-
+-
+- org.eclipse.jetty
+- jetty-webapp
+-
+-
+- com.fasterxml.jackson.module
+- jackson-module-jaxb-annotations
+-
+-
+- com.fasterxml.jackson.core
+- jackson-core
+-
+-
+- com.fasterxml.jackson.core
+- jackson-databind
+-
+-
+-
+-
+-
+- org.apache.hadoop
+- hadoop-yarn-api
+- ${hadoop.version}
+- ${hadoop.deps.scope}
+-
+-
+- javax.servlet
+- servlet-api
+-
+-
+- org.apache.avro
+- avro
+-
+-
+- org.apache.jackrabbit
+- jackrabbit-webdav
+-
+-
+- io.netty
+- netty
+-
+-
+- commons-httpclient
+- commons-httpclient
+-
+-
+- org.eclipse.jgit
+- org.eclipse.jgit
+-
+-
+- com.jcraft
+- jsch
+-
+-
+- org.apache.commons
+- commons-compress
+-
+-
+- xml-apis
+- xml-apis
+-
+-
+- xerces
+- xercesImpl
+-
+-
+- org.codehaus.jackson
+- jackson-mapper-asl
+-
+-
+- org.codehaus.jackson
+- jackson-core-asl
+-
+-
+- com.google.guava
+- guava
+-
+-
+- com.google.code.findbugs
+- jsr305
+-
+-
+- org.apache.commons
+- commons-math3
+-
+-
+-
+-
+-
+- org.apache.hadoop
+- hadoop-hdfs
+- ${hadoop.version}
+- tests
+- test
+-
+-
+- com.sun.jersey
+- jersey-json
+-
+-
+- com.sun.jersey
+- jersey-client
+-
+-
+- javax.servlet
+- servlet-api
+-
+-
+- org.apache.avro
+- avro
+-
+-
+- org.apache.jackrabbit
+- jackrabbit-webdav
+-
+-
+- io.netty
+- netty
+-
+-
+- commons-httpclient
+- commons-httpclient
+-
+-
+- org.eclipse.jgit
+- org.eclipse.jgit
+-
+-
+- com.jcraft
+- jsch
+-
+-
+- org.apache.commons
+- commons-compress
+-
+-
+- xml-apis
+- xml-apis
+-
+-
+- xerces
+- xercesImpl
+-
+-
+- com.google.guava
+- guava
+-
+-
+- io.netty
+- netty-all
+-
+-
+- org.eclipse.jetty
+- jetty-util
+-
+-
+- com.fasterxml.jackson.core
+- jackson-annotations
+-
+-
+-
+-
+-
+- org.apache.hadoop
+- hadoop-common
+- ${hadoop.version}
+- tests
+- test
+-
+-
+- com.sun.jersey
+- jersey-core
+-
+-
+- com.sun.jersey
+- jersey-json
+-
+-
+- com.sun.jersey
+- jersey-client
+-
+-
+- com.sun.jersey
+- jersey-server
+-
+-
+- javax.servlet
+- servlet-api
+-
+-
+- org.apache.avro
+- avro
+-
+-
+- org.apache.jackrabbit
+- jackrabbit-webdav
+-
+-
+- io.netty
+- netty
+-
+-
+- commons-httpclient
+- commons-httpclient
+-
+-
+- org.eclipse.jgit
+- org.eclipse.jgit
+-
+-
+- com.jcraft
+- jsch
+-
+-
+- org.apache.commons
+- commons-compress
+-
+-
+- xml-apis
+- xml-apis
+-
+-
+- xerces
+- xercesImpl
+-
+-
+- org.codehaus.jackson
+- jackson-mapper-asl
+-
+-
+- org.codehaus.jackson
+- jackson-core-asl
+-
+-
+- com.google.guava
+- guava
+-
+-
+- com.google.code.findbugs
+- jsr305
+-
+-
+- org.apache.commons
+- commons-math3
+-
+-
+- commons-beanutils
+- commons-beanutils
+-
+-
+- org.apache.commons
+- commons-configuration2
+-
+-
+- org.apache.zookeeper
+- zookeeper
+-
+-
+- org.eclipse.jetty
+- jetty-servlet
+-
+-
+- org.eclipse.jetty
+- jetty-util
+-
+-
+- org.eclipse.jetty
+- jetty-webapp
+-
+-
+- org.eclipse.jetty
+- jetty-server
+-
+-
+- com.nimbusds
+- nimbus-jose-jwt
+-
+-
+- com.fasterxml.jackson.core
+- jackson-databind
+-
+-
+-
+-
+-
+- org.apache.hadoop
+- hadoop-yarn-server-tests
+- ${hadoop.version}
+- tests
+- test
+-
+-
+- com.sun.jersey
+- jersey-core
+-
+-
+- com.sun.jersey
+- jersey-client
+-
+-
+- com.sun.jersey
+- jersey-server
+-
+-
+- javax.servlet
+- servlet-api
+-
+-
+- org.apache.avro
+- avro
+-
+-
+- org.apache.jackrabbit
+- jackrabbit-webdav
+-
+-
+- io.netty
+- netty
+-
+-
+- commons-httpclient
+- commons-httpclient
+-
+-
+- org.eclipse.jgit
+- org.eclipse.jgit
+-
+-
+- com.jcraft
+- jsch
+-
+-
+- org.apache.commons
+- commons-compress
+-
+-
+- xml-apis
+- xml-apis
+-
+-
+- xerces
+- xercesImpl
+-
+-
+- org.codehaus.jackson
+- jackson-core-asl
+-
+-
+- org.codehaus.jackson
+- jackson-jaxrs
+-
+-
+- org.codehaus.jackson
+- jackson-xc
+-
+-
+- org.codehaus.jackson
+- jackson-mapper-asl
+-
+-
+- com.google.guava
+- guava
+-
+-
+- javax.xml.bind
+- jaxb-api
+-
+-
+- com.fasterxml.jackson.core
+- jackson-core
+-
+-
+- org.eclipse.jetty
+- jetty-util
+-
+-
+- com.zaxxer
+- HikariCP-java7
+-
+-
+- com.google.inject
+- guice
+-
+-
+- com.fasterxml.jackson.core
+- jackson-annotations
+-
+-
+- com.fasterxml.jackson.module
+- jackson-module-jaxb-annotations
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- junit
+- junit
+- ${junit.version}
+- test
+-
+-
+-
+- org.assertj
+- assertj-core
+- ${assertj.version}
+- test
+-
+-
+-
+- org.mockito
+- mockito-core
+- ${mockito.version}
+- test
+-
+-
+-
+- org.mockito
+- mockito-all
+- ${mockito.version}
+- test
+-
+-
+-
+- org.powermock
+- powermock-api-mockito
+- ${powermock.version}
+- test
+-
+-
+-
+- org.powermock
+- powermock-core
+- ${powermock.version}
+- test
+-
+-
+-
+- org.powermock
+- powermock-module-junit4
+- ${powermock.version}
+- test
+-
+-
+-
+- org.powermock
+- powermock-reflect
+- ${powermock.version}
+- test
+-
++
++ ${project.groupId}
++ zeppelin-zengine
++ ${project.version}
++ provided
++
++
++ com.fasterxml.jackson.core
++ jackson-core
++
++
++
++
++
++ ${project.groupId}
++ zeppelin-zengine
++ ${project.version}
++ tests
++ test
++
++
++
++
++ junit
++ junit
++ test
++
++
++
++ org.mockito
++ mockito-all
++ test
++
+
+-
+-
+-
+-
+-
+-
+- org.apache.maven.plugins
+- maven-compiler-plugin
+- ${plugin.compiler.version}
+-
+- ${java.version}
+- ${java.version}
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- org.apache.maven.plugins
+- maven-checkstyle-plugin
+- ${plugin.checkstyle.version}
+-
+- true
+- false
+- true
+- ${basedir}/src/main/java,${basedir}/src/main/scala
+- ${basedir}/src/test/java
+- _tools/checkstyle.xml
+- ${basedir}/target/checkstyle-output.xml
+- ${project.build.sourceEncoding}
+- ${project.reporting.outputEncoding}
+-
+-
+-
+- checkstyle-fail-build
+- validate
+-
+- check
+-
+-
+- true
+- org/apache/zeppelin/interpreter/thrift/*,org/apache/zeppelin/scio/avro/*,org/apache/zeppelin/python/proto/*
+-
+-
+-
+- checkstyle-gen-html-report
+- install
+-
+- checkstyle-aggregate
+-
+-
+- org/apache/zeppelin/interpreter/thrift/*,org/apache/zeppelin/scio/avro/*,org/apache/zeppelin/python/proto/*
+-
+-
+-
+-
+-
+-
+- org.apache.maven.plugins
+- maven-jar-plugin
+- ${plugin.jar.version}
+-
+-
+-
+- true
+- lib/
+- theMainClass
+-
+-
+-
+-
+-
+-
+- org.apache.maven.plugins
+- maven-remote-resources-plugin
+- ${plugin.remote.resource.version}
+-
+-
+- process-remote-resources
+-
+- process
+-
+-
+-
+- org.apache:apache-jar-resource-bundle:1.0
+-
+-
+-
+-
+-
+-
+-
+- org.apache.maven.plugins
+- maven-scm-plugin
+- ${plugin.scm.version}
+-
+- developerConnection
+- branch-0.1
+- branch
+-
+-
+-
+-
+- org.apache.maven.plugins
+- maven-enforcer-plugin
+- ${plugin.enforcer.version}
+-
+-
+- enforce
+-
+-
+-
+-
+- true
+-
+-
+- enforce
+-
+-
+-
+-
+- enforce-maven
+-
+- enforce
+-
+-
+-
+-
+- [3.1.0,)
+-
+-
+-
+-
+-
+-
+-
+-
+- org.apache.maven.plugins
+- maven-deploy-plugin
+- ${plugin.deploy.version}
+-
+-
+-
+- pl.project13.maven
+- git-commit-id-plugin
+- ${plugin.git.commit.id.version}
+-
+-
+-
+- revision
+-
+-
+-
+-
+- false
+- ${project.basedir}/.git
+- ${plugin.gitcommitid.useNativeGit}
+- true
+- ${project.build.outputDirectory}/git.properties
+- false
+- yyyy-MM-dd HH:mm:ss
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- org.apache.maven.plugins
+- maven-shade-plugin
+- ${plugin.shade.version}
+-
+
+-
+- org.apache.maven.plugins
+- maven-install-plugin
+- ${plugin.install.version}
+-
+-
+-
+- org.apache.maven.plugins
+- maven-checkstyle-plugin
+- ${plugin.checkstyle.version}
+-
+-
+-
+- org.apache.maven.plugins
+- maven-clean-plugin
+- ${plugin.clean.version}
+-
+-
+-
+- net.alchim31.maven
+- scala-maven-plugin
+- ${plugin.scala.alchim31.version}
+-
+-
+-
+- org.apache.maven.plugins
+- maven-surefire-plugin
+- ${plugin.surefire.version}
+-
+- -Xmx2g -Xms1g -Dfile.encoding=UTF-8
+-
+- true
+-
+-
+- ${tests.to.exclude}
+-
+-
+-
+-
+-
+-
+- org.apache.maven.plugins
+- maven-assembly-plugin
+- ${plugin.assembly.version}
+-
+-
+-
+- org.codehaus.mojo
+- exec-maven-plugin
+- ${plugin.exec.version}
+-
+-
+-
+- org.codehaus.mojo
+- cobertura-maven-plugin
+- ${plugin.cobertura.version}
+-
+-
+-
+- org.codehaus.mojo
+- xml-maven-plugin
+- ${plugin.xml.version}
+-
+-
+- verify
+-
+- validate
+-
+-
+-
+-
+-
+-
+- ${project.basedir}
+-
+-
+- pom.xml
+-
+-
+- _tools/maven-4.0.0.xsd
+-
+-
+-
+-
+-
+-
+- com.googlecode.maven-download-plugin
+- download-maven-plugin
+- ${plugin.download.version}
+-
+-
+-
+- org.apache.maven.plugins
+- maven-antrun-plugin
+- ${plugin.antrun.version}
+-
+-
+-
+-
+- org.eclipse.m2e
+- lifecycle-mapping
+- ${plugin.lifecycle.mapping.version}
+-
+-
+-
+-
+-
+-
+- org.apache.maven.plugins
+-
+-
+- maven-dependency-plugin
+-
+-
+- [2.8,)
+-
+-
+- copy-dependencies
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- org.apache.maven.plugins
+-
+-
+- maven-checkstyle-plugin
+-
+-
+- [2.13,)
+-
+-
+- checkstyle
+- check
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- org.apache.maven.plugins
+- maven-eclipse-plugin
+- ${plugin.eclipse.version}
+-
+-
+-
+- org.apache.maven.plugins
+- maven-dependency-plugin
+- ${plugin.dependency.version}
+-
+-
+- copy-dependencies
+- process-test-resources
+-
+- copy-dependencies
+-
+-
+- ${project.build.directory}/lib
+- false
+- false
+- true
+- runtime
+-
+-
+-
+-
+-
+-
+- org.apache.maven.plugins
+- maven-resources-plugin
+- ${plugin.resource.version}
+-
+-
+- copy-resources
+- validate
+-
+- copy-resources
+-
+-
+- ${basedir}/target/site
+-
+-
+- ${basedir}/../_tools/site
+- true
+-
+- **/*
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- org.scalatest
+- scalatest-maven-plugin
+- ${plugin.scalatest.version}
+-
+-
+-
+- org.codehaus.mojo
+- build-helper-maven-plugin
+- ${plugin.buildhelper.version}
+-
+-
+-
+- com.github.eirslett
+- frontend-maven-plugin
+- ${plugin.frontend.version}
+-
+-
+-
+- org.apache.maven.plugins
+- maven-failsafe-plugin
+- ${plugin.failsafe.version}
+-
+-
+-
+- org.xolstice.maven.plugins
+- protobuf-maven-plugin
+- ${plugin.protobuf.version}
+-
+-
+-
+- com.bazaarvoice.maven.plugins
+- s3-upload-maven-plugin
+- ${plugin.s3.upload.version}
+-
+-
+-
+- org.codehaus.mojo
+- buildnumber-maven-plugin
+- ${plugin.buildnumber.version}
+-
+-
+-
+- org.vafer
+- jdeb
+- ${plugin.jdeb.version}
+-
+-
+-
+- org.apache.avro
+- avro-maven-plugin
+- ${plugin.avro.version}
+-
+-
+-
+- org.scalatra.scalate
+- maven-scalate-plugin_${scala.binary.version}
+- ${plugin.scalate.version}
+-
+-
+-
+- org.scala-tools
+- maven-scala-plugin
+- ${plugin.scala.tools.version}
+-
+-
+-
+- org.apache.maven.plugins
+- maven-source-plugin
+- ${plugin.source.version}
+-
+-
+-
+- org.apache.maven.plugins
+- maven-javadoc-plugin
+- ${plugin.javadoc.version}
+-
+-
+-
+- org.apache.maven.plugins
+- maven-gpg-plugin
+- ${plugin.gpg.version}
+-
+-
+-
+- org.apache.rat
+- apache-rat-plugin
+- ${plugin.rat.version}
+-
+-
+-
+-
+-
+-
+-
+-
+- scala-2.10
+-
+- true
+-
+-
+- ${scala.2.10.version}
+- 2.10
+-
+-
+-
+-
+- scala-2.11
+-
+- ${scala.2.11.version}
+- 2.11
+-
+-
+-
+-
+- web-angular
+-
+- zeppelin-web-angular
+-
+-
+-
+-
+- vendor-repo
+-
+-
+- cloudera
+- https://repository.cloudera.com/artifactory/cloudera-repos/
+-
+-
+- hortonworks
+- https://repo.hortonworks.com/content/groups/public/
+-
+-
+-
+-
+-
+- integration
+-
+- zeppelin-integration
+- zeppelin-interpreter-integration
+-
+-
+-
+-
+- examples
+-
+- zeppelin-examples
+-
+-
+-
+-
+- helium-dev
+-
+- helium-dev
+-
+-
+-
+-
+- include-hadoop
+-
+- compile
+-
+-
+-
+-
+- build-distr
+-
+- false
+-
+-
++
+
+-
+-
+- org.apache.maven.plugins
+- maven-surefire-plugin
+-
+- true
+-
+-
+-
+-
+- org.apache.maven.plugins
+- maven-assembly-plugin
+-
+-
+- make-assembly
+- package
+-
+- single
+-
+-
+-
+-
+-
+-
++
++
++ maven-dependency-plugin
++
++
++ copy-plugin-dependencies
++ package
++
++ copy-dependencies
++
++
++ ${project.basedir}/../../../plugins/${plugin.name}
++ false
++ false
++ true
++ runtime
++
++
++
++ copy-plugin-artifact
++ package
++
++ copy
++
++
++ ${project.basedir}/../../../plugins/${plugin.name}
++ false
++ false
++ true
++
++
++ ${project.groupId}
++ ${project.artifactId}
++ ${project.version}
++ ${project.packaging}
++
++
++
++
++
++
++
++ maven-clean-plugin
++
++
++ delete-plugin-dir
++
++ clean
++
++ clean
++
++
++
++ ${project.basedir}/../../../plugins/${plugin.name}
++ true
++ false
++
++
++
++
++
++
++
+
+-
+-
+-
+-
+- publish-distr
+-
+-
+-
+- org.apache.maven.plugins
+- maven-surefire-plugin
+-
+- true
+-
+-
+-
+-
+- org.apache.maven.plugins
+- maven-source-plugin
+-
+-
+- attach-sources
+-
+- jar
+-
+-
+-
+-
+-
+-
+- org.apache.maven.plugins
+- maven-javadoc-plugin
+-
+-
+- attach-javadocs
+-
+- jar
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- release-sign-artifacts
+-
+-
+- performRelease
+- true
+-
+-
+-
+-
+-
+- org.apache.maven.plugins
+- maven-gpg-plugin
+-
+-
+- sign-artifacts
+- verify
+-
+- sign
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- rat
+-
+- !skipRat
+-
+-
+-
+-
+- org.apache.rat
+- apache-rat-plugin
+-
+-
+- **/*.keywords
+- reports/**
+- **/.idea/
+- **/*.iml
+- .git/
+- .github/*
+- .gitignore
+- git.properties
+- .repository/
+- .rat-excludes/
+- .Rhistory
+- **/*.diff
+- **/*.patch
+- **/*.avsc
+- **/*.avro
+- **/*.log
+- **/*.ipynb
+- **/test/resources/**
+- **/.settings/*
+- **/.factorypath
+- **/.classpath
+- **/.project
+- **/target/**
+- **/derby.log
+- **/metastore_db/
+- **/logs/**
+- **/run/**
+- **/interpreter/**
+- **/local-repo/**
+- **/null/**
+- **/notebook/**
+- _tools/site/css/*
+- _tools/maven-4.0.0.xsd
+- **/README.md
+- DEPENDENCIES
+- DEPLOY.md
+- STYLE.md
+- Roadmap.md
+- **/licenses/**
+- **/zeppelin-distribution/src/bin_license/**
+- conf/interpreter.json
+- conf/notebook-authorization.json
+- conf/credentials.json
+- conf/zeppelin-env.sh
+- conf/helium.json
+- spark-*-bin*/**
+- .spark-dist/**
+- **/interpreter-setting.json
+- **/constants.json
+- scripts/**
+- **/**/*.log
+- **/**/logs/**
+-
+-
+- **/test/karma.conf.js
+- **/test/spec/**
+- **/.babelrc
+- **/.bowerrc
+- .editorconfig
+- .eslintrc
+- protractor.conf.js
+- **/.tmp/**
+- **/target/**
+- **/node/**
+- **/node_modules/**
+- **/bower_components/**
+- **/dist/**
+- **/.buildignore
+- **/.npmignore
+- **/.jshintrc
+- **/yarn.lock
+- **/bower.json
+- **/src/fonts/Patua-One*
+- **/src/fonts/patua-one*
+- **/src/fonts/Roboto*
+- **/src/fonts/roboto*
+- **/src/fonts/fontawesome*
+- **/src/fonts/font-awesome*
+- **/src/styles/font-awesome*
+- **/src/fonts/Simple-Line*
+- **/src/fonts/simple-line*
+- **/src/fonts/Source-Code-Pro*
+- **/src/fonts/source-code-pro*
+- **/src/**/**.test.js
+- **/e2e/**/**.spec.js
+- package-lock.json
+-
+-
+- **/*.json
+- **/browserslist
+- **/.prettierrc
+- **/.prettierignore
+- **/.editorconfig
+- **/src/**/*.svg
+- **/.gitkeep
+-
+-
+-
+- **/src/main/java/org/apache/zeppelin/jdbc/SqlCompleter.java
+-
+-
+- docs/assets/themes/zeppelin/bootstrap/**
+- docs/assets/themes/zeppelin/css/style.css
+- docs/assets/themes/zeppelin/js/docs.js
+- docs/assets/themes/zeppelin/js/search.js
+- docs/_includes/themes/zeppelin/_jumbotron.html
+- docs/_includes/themes/zeppelin/_navigation.html
+-
+-
+- docs/404.html
+- docs/_config.yml
+- docs/_includes/JB/**
+- docs/_layouts/**
+- docs/_plugins/**
+- docs/atom.xml
+- docs/_includes/themes/zeppelin/default.html
+- docs/_includes/themes/zeppelin/page.html
+- docs/_includes/themes/zeppelin/post.html
+- docs/_includes/themes/zeppelin/settings.yml
+- docs/Rakefile
+- docs/rss.xml
+- docs/sitemap.txt
+- docs/search_data.json
+- **/dependency-reduced-pom.xml
+-
+-
+- docs/assets/themes/zeppelin/js/anchor.min.js
+-
+-
+- docs/assets/themes/zeppelin/js/toc.js
+-
+-
+- docs/assets/themes/zeppelin/js/lunr.min.js
+-
+-
+- docs/assets/themes/zeppelin/css/syntax.css
+-
+-
+- docs/_site/**
+- docs/Gemfile.lock
+-
+-
+- **/package.json
+-
+-
+- **/R/lib/**
+- **/lib/rzeppelin/**
+-
+-
+-
+- **/R/rzeppelin/R/*.R
+- **/src/main/scala/scala/Console.scala
+- **/src/main/scala/org/apache/zeppelin/rinterpreter/rscala/Package.scala
+- **/src/main/scala/org/apache/zeppelin/rinterpreter/rscala/RClient.scala
+-
+-
+- **/R/rzeppelin/DESCRIPTION
+- **/R/rzeppelin/NAMESPACE
+-
+- zeppelin-jupyter-interpreter/src/main/resources/grpc/jupyter/*.py
+-
+-
+-
+-
+-
+- verify.rat
+- verify
+-
+- check
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- hadoop2
+-
+- ${hadoop2.7.version}
+- 2.13.0
+-
+-
+-
+-
+- hadoop3
+-
+- ${hadoop3.2.version}
+- 2.13.0
+- 2.0.0-M15
+-
+-
+-
+-
+-
++
+
+diff --git a/zeppelin-plugins/pom.xml b/zeppelin-plugins/pom.xml
+index cef5f418d..d9b3e806d 100644
+--- a/zeppelin-plugins/pom.xml
++++ b/zeppelin-plugins/pom.xml
+@@ -41,6 +41,7 @@
+
+
+ notebookrepo/s3
++ notebookrepo/opensearch
+ notebookrepo/github
+ notebookrepo/azure
+ notebookrepo/gcs
+diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/search/LuceneSearch.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/search/LuceneSearch.java
+index 2b3a24c9b..cb634e3b4 100644
+--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/search/LuceneSearch.java
++++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/search/LuceneSearch.java
+@@ -28,7 +28,6 @@ import java.util.Date;
+ import java.util.List;
+ import java.util.Map;
+ import java.util.concurrent.TimeUnit;
+-import java.util.stream.Stream;
+ import javax.inject.Inject;
+
+ import org.apache.lucene.analysis.Analyzer;
+@@ -36,7 +35,7 @@ import org.apache.lucene.analysis.TokenStream;
+ import org.apache.lucene.analysis.standard.StandardAnalyzer;
+ import org.apache.lucene.document.Document;
+ import org.apache.lucene.document.Field;
+-import org.apache.lucene.document.LongField;
++import org.apache.lucene.document.LongPoint;
+ import org.apache.lucene.document.StringField;
+ import org.apache.lucene.document.TextField;
+ import org.apache.lucene.index.DirectoryReader;
+@@ -95,7 +94,7 @@ public class LuceneSearch extends SearchService {
+ logger.info("Use {} for storing lucene search index", this.indexPath);
+ } catch (IOException e) {
+ throw new RuntimeException(
+- "Failed to create index directory for search service. Use memory instead", e);
++ "Failed to create index directory for search service. Use memory instead", e);
+ }
+ } else {
+ this.indexDirectory = new RAMDirectory();
+@@ -116,14 +115,14 @@ public class LuceneSearch extends SearchService {
+ public List> query(String queryStr) {
+ if (null == indexDirectory) {
+ throw new IllegalStateException(
+- "Something went wrong on instance creation time, index dir is null");
++ "Something went wrong on instance creation time, index dir is null");
+ }
+ List> result = Collections.emptyList();
+ try (IndexReader indexReader = DirectoryReader.open(indexDirectory)) {
+ IndexSearcher indexSearcher = new IndexSearcher(indexReader);
+ Analyzer analyzer = new StandardAnalyzer();
+ MultiFieldQueryParser parser =
+- new MultiFieldQueryParser(new String[] {SEARCH_FIELD_TEXT, SEARCH_FIELD_TITLE}, analyzer);
++ new MultiFieldQueryParser(new String[] {SEARCH_FIELD_TEXT, SEARCH_FIELD_TITLE}, analyzer);
+
+ Query query = parser.parse(queryStr);
+ logger.debug("Searching for: " + query.toString(SEARCH_FIELD_TEXT));
+@@ -141,7 +140,7 @@ public class LuceneSearch extends SearchService {
+ }
+
+ private List> doSearch(
+- IndexSearcher searcher, Query query, Analyzer analyzer, Highlighter highlighter) {
++ IndexSearcher searcher, Query query, Analyzer analyzer, Highlighter highlighter) {
+ List> matchingParagraphs = Lists.newArrayList();
+ ScoreDoc[] hits;
+ try {
+@@ -165,8 +164,8 @@ public class LuceneSearch extends SearchService {
+
+ if (text != null) {
+ TokenStream tokenStream =
+- TokenSources.getTokenStream(
+- searcher.getIndexReader(), id, SEARCH_FIELD_TEXT, analyzer);
++ TokenSources.getTokenStream(
++ searcher.getIndexReader(), id, SEARCH_FIELD_TEXT, analyzer);
+ TextFragment[] frag = highlighter.getBestTextFragments(tokenStream, text, true, 3);
+ logger.debug(" {} fragments found for query '{}'", frag.length, query);
+ for (int j = 0; j < frag.length; j++) {
+@@ -179,17 +178,17 @@ public class LuceneSearch extends SearchService {
+
+ if (header != null) {
+ TokenStream tokenTitle =
+- TokenSources.getTokenStream(
+- searcher.getIndexReader(), id, SEARCH_FIELD_TITLE, analyzer);
++ TokenSources.getTokenStream(
++ searcher.getIndexReader(), id, SEARCH_FIELD_TITLE, analyzer);
+ TextFragment[] frgTitle = highlighter.getBestTextFragments(tokenTitle, header, true, 3);
+ header = (frgTitle != null && frgTitle.length > 0) ? frgTitle[0].toString() : "";
+ } else {
+ header = "";
+ }
+ matchingParagraphs.add(
+- ImmutableMap.of(
+- "id", path, // /paragraph/
+- "name", title, "snippet", fragment, "text", text, "header", header));
++ ImmutableMap.of(
++ "id", path, // /paragraph/
++ "name", title, "snippet", fragment, "text", text, "header", header));
+ } else {
+ logger.info("{}. No {} for this document", i + 1, ID_FIELD);
+ }
+@@ -293,7 +292,7 @@ public class LuceneSearch extends SearchService {
+ doc.add(new TextField(SEARCH_FIELD_TITLE, p.getTitle(), Field.Store.YES));
+ }
+ Date date = p.getDateStarted() != null ? p.getDateStarted() : p.getDateCreated();
+- doc.add(new LongField("modified", date.getTime(), Field.Store.NO));
++ doc.add(new LongPoint("modified", date.getTime()));
+ } else {
+ doc.add(new TextField(SEARCH_FIELD_TEXT, noteName, Field.Store.YES));
+ }
+@@ -322,9 +321,9 @@ public class LuceneSearch extends SearchService {
+ }
+ long end = System.nanoTime();
+ logger.info(
+- "Indexing {} notebooks took {}ms",
+- docsIndexed,
+- TimeUnit.NANOSECONDS.toMillis(end - start));
++ "Indexing {} notebooks took {}ms",
++ docsIndexed,
++ TimeUnit.NANOSECONDS.toMillis(end - start));
+ }
+ }
+
+@@ -377,14 +376,14 @@ public class LuceneSearch extends SearchService {
+
+ private void deleteDoc(String noteId, Paragraph p) {
+ String fullNoteOrJustParagraph = formatDeleteId(noteId, p);
+- logger.debug("Deleting note {}, out of: {}", noteId, indexWriter.numDocs());
++ logger.debug("Deleting note {}, out of: {}", noteId, indexWriter.getDocStats());
+ try {
+ indexWriter.deleteDocuments(new WildcardQuery(new Term(ID_FIELD, fullNoteOrJustParagraph)));
+ indexWriter.commit();
+ } catch (IOException e) {
+ logger.error("Failed to delete {} from index by '{}'", noteId, fullNoteOrJustParagraph, e);
+ }
+- logger.debug("Done, index contains {} docs now" + indexWriter.numDocs());
++ logger.debug("Done, index contains {} docs now" + indexWriter.getDocStats());
+ }
+
+ /* (non-Javadoc)
+@@ -415,28 +414,22 @@ public class LuceneSearch extends SearchService {
+
+ /** Indexes a single document: - code of the paragraph (if non-null) - or just a note name */
+ private void indexDoc(IndexWriter w, String noteId, String noteName, Paragraph p)
+- throws IOException {
++ throws IOException {
+ String id = formatId(noteId, p);
+ Document doc = newDocument(id, noteName, p);
+ w.addDocument(doc);
+ }
+
+ @Override
+- public void startRebuildIndex(Stream notes) {
++ public void startRebuildIndex(List notes) {
+ Thread thread = new Thread(() -> {
+ logger.info("Starting rebuild index");
+- notes.forEach(note -> {
++ for (Note note: notes) {
+ addIndexDoc(note);
+- note.unLoad();
+- });
++ }
+ logger.info("Finish rebuild index");
+ });
+ thread.setName("LuceneSearch-RebuildIndex-Thread");
+ thread.start();
+- try {
+- thread.join();
+- } catch (InterruptedException e) {
+- e.printStackTrace();
+- }
+ }
+ }
+
diff --git a/public/components/notebooks/docs/poc/zeppelin/zeppelin-plugins/notebookrepo/opensearch/pom.xml b/public/components/notebooks/docs/poc/zeppelin/zeppelin-plugins/notebookrepo/opensearch/pom.xml
new file mode 100644
index 0000000000..f74423050c
--- /dev/null
+++ b/public/components/notebooks/docs/poc/zeppelin/zeppelin-plugins/notebookrepo/opensearch/pom.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+ 4.0.0
+
+ zengine-plugins-parent
+ org.apache.zeppelin
+ 0.9.0-SNAPSHOT
+ ../../../zeppelin-plugins
+
+
+ org.apache.zeppelin
+ notebookrepo-opensearch
+ jar
+ 0.9.0-SNAPSHOT
+ Zeppelin: Plugin OpenSearchNotebookRepo
+ NotebookRepo implementation based on OpenSearch
+
+
+ 7.8.0
+ NotebookRepo/OpenSearchNotebookRepo
+ true
+
+
+
+
+ org.opensearch.client
+ elasticsearch-rest-high-level-client
+ ${elasticsearch.client.version}
+
+
+ org.apache.logging.log4j
+ log4j-to-slf4j
+ 2.11.1
+
+
+
+
+
+
+ maven-dependency-plugin
+
+
+
+
diff --git a/public/components/notebooks/docs/poc/zeppelin/zeppelin-plugins/notebookrepo/opensearch/src/main/java/org/apache/zeppelin/notebook/repo/OpenSearchNotebookRepo.java b/public/components/notebooks/docs/poc/zeppelin/zeppelin-plugins/notebookrepo/opensearch/src/main/java/org/apache/zeppelin/notebook/repo/OpenSearchNotebookRepo.java
new file mode 100644
index 0000000000..4405c3a6f7
--- /dev/null
+++ b/public/components/notebooks/docs/poc/zeppelin/zeppelin-plugins/notebookrepo/opensearch/src/main/java/org/apache/zeppelin/notebook/repo/OpenSearchNotebookRepo.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.apache.zeppelin.notebook.repo;
+
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import org.apache.http.HttpHost;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
+import org.apache.zeppelin.conf.ZeppelinConfiguration;
+import org.apache.zeppelin.notebook.Note;
+import org.apache.zeppelin.notebook.NoteInfo;
+import org.apache.zeppelin.user.AuthenticationInfo;
+import org.opensearch.ElasticsearchStatusException;
+import org.opensearch.action.DocWriteResponse;
+import org.opensearch.action.delete.DeleteRequest;
+import org.opensearch.action.delete.DeleteResponse;
+import org.opensearch.action.get.GetRequest;
+import org.opensearch.action.get.GetResponse;
+import org.opensearch.action.index.IndexRequest;
+import org.opensearch.action.index.IndexResponse;
+import org.opensearch.action.search.SearchRequest;
+import org.opensearch.action.search.SearchResponse;
+import org.opensearch.client.RequestOptions;
+import org.opensearch.client.RestClient;
+import org.opensearch.client.RestClientBuilder;
+import org.opensearch.client.RestHighLevelClient;
+import org.opensearch.client.indices.CreateIndexRequest;
+import org.opensearch.client.indices.CreateIndexResponse;
+import org.opensearch.common.xcontent.XContentType;
+import org.opensearch.index.query.QueryBuilders;
+import org.opensearch.search.SearchHit;
+import org.opensearch.search.SearchHits;
+import org.opensearch.search.builder.SearchSourceBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * Backend for storing Notebooks on OpenSearch
+ */
+public class OpenSearchNotebookRepo implements NotebookRepo {
+ private static final Logger LOGGER = LoggerFactory.getLogger(OpenSearchNotebookRepo.class);
+
+//
+
+ private RestHighLevelClient OpenSearchClient;
+ private String user;
+ private String password;
+ private String host;
+ private Integer port;
+ private String protocol;
+ private String rootIndex = ".notebooks";
+ private ZeppelinConfiguration conf;
+
+ public OpenSearchNotebookRepo() {
+
+ }
+
+ private RestHighLevelClient client() {
+ // Uncomment to add path for ssl keystore and using https client
+ // Discussion on generating keystore with certificate: https://github.com/opendistro-for-elasticsearch/community/issues/64#issuecomment-493258442
+ // System.setProperty("javax.net.ssl.trustStore", "/path/to/keystore/keystore.jks");
+ final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
+ credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(user, password));
+
+ RestHighLevelClient client = new RestHighLevelClient(
+ RestClient.builder(
+ new HttpHost(host, port, protocol)).setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
+ @Override
+ public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
+ return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
+ }
+ }));
+ return client;
+ }
+
+ private void CreateNotebooksIndex() throws IOException {
+ CreateIndexRequest request = new CreateIndexRequest(rootIndex);
+ try {
+ CreateIndexResponse createIndexResponse = OpenSearchClient.indices().create(request, RequestOptions.DEFAULT);
+ } catch (ElasticsearchStatusException e) {
+ if (!e.getMessage().contains("resource_already_exists_exception")) {
+ throw e;
+ }
+ }
+ }
+
+ @Override
+ public void init(ZeppelinConfiguration conf) throws IOException {
+ this.conf = conf;
+ // Change Client configuration here
+ user = "admin";
+ password = "admin";
+ host = "localhost";
+ port = 9200;
+ protocol = "http";
+ OpenSearchClient = client();
+ CreateNotebooksIndex();
+ }
+
+
+ @Override
+ public Map list(AuthenticationInfo subject) throws IOException {
+ Map notesInfo = new HashMap<>();
+ SearchRequest searchRequest = new SearchRequest(rootIndex);
+ SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
+ searchSourceBuilder.query(QueryBuilders.matchAllQuery());
+ searchRequest.source(searchSourceBuilder);
+ SearchResponse searchResponse = OpenSearchClient.search(searchRequest, RequestOptions.DEFAULT);
+
+ SearchHits hits = searchResponse.getHits();
+
+ if (hits.getHits().length>0) {
+ SearchHit[] searchHits = hits.getHits();
+ for (SearchHit hit : searchHits) {
+ Map noteJson = hit.getSourceAsMap();
+ NoteInfo noteInfo = new NoteInfo(noteJson.get("id").toString(), noteJson.get("path").toString());
+ notesInfo.put(noteJson.get("id").toString(), noteInfo);
+ }
+ }
+ return notesInfo;
+ }
+
+
+ @Override
+ public Note get(String noteId, String notePath, AuthenticationInfo subject) throws IOException {
+ GetRequest getRequest = new GetRequest(rootIndex, noteId);
+ GetResponse getResponse = OpenSearchClient.get(getRequest, RequestOptions.DEFAULT);
+ if (getResponse.isExists()) {
+ String json = getResponse.getSourceAsString();
+ return Note.fromJson(json);
+ } else {
+ throw new IOException("Note '" + noteId + "' in path '" + notePath + "'not found in OpenSearch");
+ }
+ }
+
+ @Override
+ public void save(Note note, AuthenticationInfo subject) throws IOException {
+ // TODO: Other NotebookRepos deal with File paths as a separate kept entity
+ // They don't store path in the notebook itself
+ // Here, we merge path as a notebook property
+ // In the later release we need to decouple this to support folder structures
+
+ JsonObject json = new JsonParser().parse(note.toJson()).getAsJsonObject();
+ json.addProperty("path",note.getPath());
+ try {
+ IndexRequest request = new IndexRequest(rootIndex);
+ request.id(note.getId());
+ request.source(json.toString(), XContentType.JSON);
+ IndexResponse indexResponse = OpenSearchClient.index(request, RequestOptions.DEFAULT);
+ } catch (IOException e) {
+ throw new IOException("Fail to store note: " + note.getPath() + " in OpenSearch", e);
+ }
+ }
+
+ @Override
+ public void move(String noteId, String notePath, String newNotePath,
+ AuthenticationInfo subject) throws IOException {
+ LOGGER.warn("Method not implemented");
+ }
+
+ @Override
+ public void move(String folderPath, String newFolderPath, AuthenticationInfo subject) throws IOException {
+ LOGGER.warn("Method not implemented");
+ }
+
+ @Override
+ public void remove(String noteId, String notePath, AuthenticationInfo subject)
+ throws IOException {
+ DeleteRequest request = new DeleteRequest(rootIndex, noteId);
+ DeleteResponse deleteResponse = OpenSearchClient.delete(request, RequestOptions.DEFAULT);
+ if (deleteResponse.getResult() != DocWriteResponse.Result.NOT_FOUND) {
+ System.out.println(deleteResponse.toString());
+ } else {
+ throw new IOException("Note '" + noteId + "' in path '" + notePath + "'cannot be deleted");
+ }
+ }
+
+ @Override
+ public void remove(String folderPath, AuthenticationInfo subject) throws IOException {
+ LOGGER.warn("Method not implemented");
+ }
+
+ @Override
+ public void close() {
+ try {
+ OpenSearchClient.close();
+ } catch (IOException exception) {
+ exception.printStackTrace();
+ }
+
+ }
+
+ @Override
+ public List getSettings(AuthenticationInfo subject) {
+ LOGGER.warn("Method not implemented");
+ return Collections.emptyList();
+ }
+
+ @Override
+ public void updateSettings(Map settings, AuthenticationInfo subject) {
+ LOGGER.warn("Method not implemented");
+ }
+
+}
+
diff --git a/public/components/notebooks/index.scss b/public/components/notebooks/index.scss
new file mode 100644
index 0000000000..d21d4c8668
--- /dev/null
+++ b/public/components/notebooks/index.scss
@@ -0,0 +1,39 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+.editorArea {
+ font-family: Dank Mono, Source Code Pro, Consolas, Courier New, Courier, monospace;
+ font-size: 1em;
+ border: none;
+ width: 100%;
+ height: 14em;
+}
+
+#notebookArea {
+ max-width: 88vw;
+}
+
+.panel-header-count {
+ color: #687078;
+ font-weight: normal;
+}
+
+.markdown-output-text {
+ font-family: 'Inter UI', -apple-system, system-ui, 'Segoe UI', Helvetica, Arial, sans-serif,
+ 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
+}
+
+.notebooks-paragraph button[aria-label='Expand'] {
+ display: none;
+}
+.notebooks-paragraph-dark .markdown-body {
+ pre.input {
+ background-color: #25262d !important;
+ }
+ code.language-text {
+ color: #e0e5ee !important;
+ background-color: #25262d !important;
+ }
+}
diff --git a/public/components/trace_analytics/components/common/__tests__/__snapshots__/helper_functions.test.tsx.snap b/public/components/trace_analytics/components/common/__tests__/__snapshots__/helper_functions.test.tsx.snap
new file mode 100644
index 0000000000..0d6dad1ca0
--- /dev/null
+++ b/public/components/trace_analytics/components/common/__tests__/__snapshots__/helper_functions.test.tsx.snap
@@ -0,0 +1,146 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Helper functions renders benchmark 1`] = `
+
+
+ 50% ▴
+
+
+`;
+
+exports[`Helper functions renders benchmark 2`] = `
+
+
+ 50% ▾
+
+
+`;
+
+exports[`Helper functions renders benchmark 3`] = `
+
+
+ 0% -
+
+
+`;
+
+exports[`Helper functions renders no match and missing configuration messages 1`] = `
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+ }
+ title={
+
+ No matches
+
+ }
+ />
+
+
+`;
+
+exports[`Helper functions renders no match and missing configuration messages 2`] = `
+
+
+ Learn more
+
+ }
+ body={
+
+ The indices required for trace analytics (otel-v1-apm-span-* and otel-v1-apm-service-map*) do not exist or you do not have permission to access them.
+
+ }
+ title={
+
+ Trace Analytics not set up
+
+ }
+ />
+
+`;
+
+exports[`Helper functions renders panel title 1`] = `
+
+
+ test
+
+
+ (10)
+
+
+`;
+
+exports[`Helper functions renders panel title 2`] = `
+
+
+ test
+
+
+`;
diff --git a/public/components/trace_analytics/components/common/__tests__/__snapshots__/search_bar.test.tsx.snap b/public/components/trace_analytics/components/common/__tests__/__snapshots__/search_bar.test.tsx.snap
new file mode 100644
index 0000000000..1667bfcc87
--- /dev/null
+++ b/public/components/trace_analytics/components/common/__tests__/__snapshots__/search_bar.test.tsx.snap
@@ -0,0 +1,1176 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Search bar components renders date picker 1`] = `
+
+
+
+
+
+
+ }
+ >
+
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="QuickSelectPopover"
+ isOpen={false}
+ ownFocus={true}
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
}
+ iconType={false}
+ isCustom={true}
+ startDateControl={
}
+ >
+
+
+ Last 5 minutes
+
+
+ Show dates
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Search bar components renders search bar 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ >
+
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="QuickSelectPopover"
+ isOpen={false}
+ ownFocus={true}
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
}
+ iconType={false}
+ isCustom={true}
+ startDateControl={
}
+ >
+
+
+ Last 5 minutes
+
+
+ Show dates
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Refresh
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+
+
+
+ + Add filter
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="m"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+ + Add filter
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/trace_analytics/components/common/__tests__/helper_functions.test.tsx b/public/components/trace_analytics/components/common/__tests__/helper_functions.test.tsx
new file mode 100644
index 0000000000..730db77b5a
--- /dev/null
+++ b/public/components/trace_analytics/components/common/__tests__/helper_functions.test.tsx
@@ -0,0 +1,169 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount, shallow } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { TEST_SERVICE_MAP, TEST_SERVICE_MAP_GRAPH } from '../../../../../../test/constants';
+import {
+ calculateTicks,
+ filtersToDsl,
+ fixedIntervalToMilli,
+ fixedIntervalToTickFormat,
+ getPercentileFilter,
+ getServiceMapGraph,
+ getServiceMapScaleColor,
+ getServiceMapTargetResources,
+ milliToNanoSec,
+ minFixedInterval,
+ MissingConfigurationMessage,
+ nanoToMilliSec,
+ NoMatchMessage,
+ PanelTitle,
+ renderBenchmark,
+} from '../helper_functions';
+
+describe('Helper functions', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders panel title', () => {
+ const title = shallow( );
+ const titleZeroCount = shallow( );
+ expect(title).toMatchSnapshot();
+ expect(titleZeroCount).toMatchSnapshot();
+ });
+
+ it('renders no match and missing configuration messages', () => {
+ const noMatchMessage = shallow( );
+ const missingConfigurationMessage = shallow( );
+ expect(noMatchMessage).toMatchSnapshot();
+ expect(missingConfigurationMessage).toMatchSnapshot();
+ });
+
+ it('renders benchmark', () => {
+ // @ts-ignore
+ const benchmarkPositive = mount(renderBenchmark(50));
+ // @ts-ignore
+ const benchmarkNegative = mount(renderBenchmark(-50));
+ // @ts-ignore
+ const benchmarkZero = mount(renderBenchmark(0));
+ expect(benchmarkPositive).toMatchSnapshot();
+ expect(benchmarkNegative).toMatchSnapshot();
+ expect(benchmarkZero).toMatchSnapshot();
+ });
+
+ it('converts nanoseconds and milliseconds', () => {
+ const ms = nanoToMilliSec(123456789);
+ expect(ms).toEqual(123.456789);
+ const ns = milliToNanoSec(123.456789);
+ expect(ns).toEqual(123456789);
+ // @ts-ignore
+ const invalidMs = nanoToMilliSec('abc');
+ expect(invalidMs).toEqual(0);
+ // @ts-ignore
+ const invalidNs = milliToNanoSec('abc');
+ expect(invalidNs).toEqual(0);
+ });
+
+ it('returns service map scale color', () => {
+ const color = getServiceMapScaleColor(0.5, 'latency');
+ expect(color).toEqual('134, 105, 173');
+ });
+
+ it('returns service map graph', () => {
+ const serviceMapGraph = getServiceMapGraph(TEST_SERVICE_MAP, 'latency', [
+ 0,
+ 50,
+ 100,
+ 150,
+ 200,
+ 250,
+ ]);
+ expect(serviceMapGraph).toEqual(TEST_SERVICE_MAP_GRAPH);
+ });
+
+ it('returns target resources by service name', () => {
+ const targetResources = getServiceMapTargetResources(TEST_SERVICE_MAP, 'order');
+ expect(targetResources).toEqual(['clear_order', 'update_order', 'get_order', 'pay_order']);
+ });
+
+ it('calculates ticks', () => {
+ const ticks = calculateTicks(500, 200);
+ const ticks2 = calculateTicks(0, 200, 10);
+ expect(ticks).toEqual([0, 50, 100, 150, 200]);
+ expect(ticks2).toEqual([0, 20, 40, 60, 80, 100, 120, 140, 160, 180, 200]);
+ });
+
+ it('calculates fixed_interval for date_histograms', () => {
+ const fixedInterval = minFixedInterval('now-5y', 'now');
+ expect(fixedInterval).toEqual('365d');
+ const ms = fixedIntervalToMilli('1h');
+ expect(ms).toEqual(3600000);
+ const tickFormat = fixedIntervalToTickFormat('1h');
+ expect(tickFormat).toEqual('');
+ });
+
+ it('returns percentile filter DSL', () => {
+ const DSL = getPercentileFilter(
+ [{ traceGroupName: 'order', durationFilter: { gte: 1000 } }],
+ '>= 95th'
+ );
+ expect(DSL).toEqual(
+ JSON.parse(
+ `{"field":"Latency percentile within trace group","operator":"","value":">= 95th","inverted":false,"disabled":false,"custom":{"query":{"bool":{"must":[],"filter":[],"should":[{"bool":{"must":[{"term":{"traceGroup":{"value":"order"}}},{"range":{"traceGroupFields.durationInNanos":{"gte":1000}}}]}}],"must_not":[],"minimum_should_match":1}}}}`
+ )
+ );
+ });
+
+ it('converts filters to DSL', () => {
+ const getTestDslFromFilters = (field = 'traceGroup', operator = 'exists') =>
+ filtersToDsl(
+ [
+ {
+ field,
+ operator,
+ value: { from: '100', to: '\u221E' },
+ inverted: false,
+ disabled: false,
+ },
+ ],
+ 'order',
+ 'now-5m',
+ 'now'
+ );
+ const existsDSL = getTestDslFromFilters();
+ expect(JSON.stringify(existsDSL)).toEqual(
+ '{"query":{"bool":{"must":[{"range":{"startTime":{"gte":"now-5m","lte":"now"}}},{"query_string":{"query":"order"}},{"exists":{"field":"traceGroup"}}],"filter":[],"should":[],"must_not":[]}},"custom":{"timeFilter":[{"range":{"startTime":{"gte":"now-5m","lte":"now"}}}],"serviceNames":[],"serviceNamesExclude":[],"traceGroup":[],"traceGroupExclude":[],"percentiles":{"query":{"bool":{"should":[]}}}}}'
+ );
+
+ const isDSL = getTestDslFromFilters('traceGroup', 'is');
+ expect(JSON.stringify(isDSL)).toEqual(
+ '{"query":{"bool":{"must":[{"range":{"startTime":{"gte":"now-5m","lte":"now"}}},{"query_string":{"query":"order"}},{"term":{"traceGroup":{"from":"100","to":"∞"}}}],"filter":[],"should":[],"must_not":[]}},"custom":{"timeFilter":[{"range":{"startTime":{"gte":"now-5m","lte":"now"}}}],"serviceNames":[],"serviceNamesExclude":[],"traceGroup":[],"traceGroupExclude":[],"percentiles":{"query":{"bool":{"should":[]}}}}}'
+ );
+ const isBetweenDSL = getTestDslFromFilters('durationInNanos', 'is between');
+ expect(JSON.stringify(isBetweenDSL)).toEqual(
+ `{"query":{"bool":{"must":[{"range":{"startTime":{"gte":"now-5m","lte":"now"}}},{"query_string":{"query":"order"}},{"range":{"durationInNanos":{"gte":"100"}}}],"filter":[],"should":[],"must_not":[]}},"custom":{"timeFilter":[{"range":{"startTime":{"gte":"now-5m","lte":"now"}}}],"serviceNames":[],"serviceNamesExclude":[],"traceGroup":[],"traceGroupExclude":[],"percentiles":{"query":{"bool":{"should":[]}}}}}`
+ );
+
+ const customDSL = filtersToDsl(
+ [
+ {
+ field: 'serviceName',
+ operator: 'is',
+ value: 'order',
+ inverted: false,
+ disabled: false,
+ custom: { query: { bool: { should: ['test'], minimum_should_match: 1 } } },
+ },
+ ],
+ 'order',
+ 'now-5m',
+ 'now'
+ );
+ expect(JSON.stringify(customDSL)).toEqual(
+ `{"query":{"bool":{"must":[{"range":{"startTime":{"gte":"now-5m","lte":"now"}}},{"query_string":{"query":"order"}}],"filter":[],"should":["test"],"must_not":[],"minimum_should_match":1}},"custom":{"timeFilter":[{"range":{"startTime":{"gte":"now-5m","lte":"now"}}}],"serviceNames":[],"serviceNamesExclude":[],"traceGroup":[],"traceGroupExclude":[],"percentiles":{"query":{"bool":{"should":["test"],"minimum_should_match":1}}}}}`
+ );
+ });
+});
diff --git a/public/components/trace_analytics/components/common/__tests__/search_bar.test.tsx b/public/components/trace_analytics/components/common/__tests__/search_bar.test.tsx
new file mode 100644
index 0000000000..9e0c8ed124
--- /dev/null
+++ b/public/components/trace_analytics/components/common/__tests__/search_bar.test.tsx
@@ -0,0 +1,54 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import sinon from 'sinon';
+import { renderDatePicker, SearchBar } from '../search_bar';
+
+describe('Search bar components', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders date picker', () => {
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const wrapper = mount(renderDatePicker('now-5m', setStartTime, 'now', setEndTime));
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it('renders search bar', () => {
+ const clock = sinon.useFakeTimers();
+
+ const refresh = jest.fn();
+ const setQuery = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const setFilters = jest.fn();
+ const wrapper = mount(
+
+ );
+ expect(wrapper).toMatchSnapshot();
+
+ wrapper
+ .find('input[data-test-subj="search-bar-input-box"]')
+ .simulate('change', { target: { value: 'queryTest' } });
+
+ clock.tick(100);
+ expect(setQuery).toBeCalledWith('queryTest');
+ });
+});
diff --git a/public/components/trace_analytics/components/common/color_palette.ts b/public/components/trace_analytics/components/common/color_palette.ts
new file mode 100644
index 0000000000..e07be70f9a
--- /dev/null
+++ b/public/components/trace_analytics/components/common/color_palette.ts
@@ -0,0 +1,314 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const serviceMapColorPalette = {
+ latency: [
+ '218, 214, 227',
+ '216, 212, 226',
+ '215, 209, 226',
+ '213, 207, 225',
+ '212, 205, 224',
+ '210, 202, 224',
+ '208, 200, 223',
+ '207, 198, 222',
+ '205, 195, 222',
+ '203, 193, 221',
+ '202, 191, 220',
+ '200, 189, 219',
+ '198, 186, 218',
+ '197, 184, 217',
+ '195, 182, 216',
+ '193, 180, 216',
+ '192, 177, 215',
+ '190, 175, 214',
+ '188, 173, 213',
+ '187, 171, 212',
+ '185, 169, 211',
+ '183, 166, 210',
+ '182, 164, 209',
+ '180, 162, 207',
+ '178, 160, 206',
+ '177, 158, 205',
+ '175, 155, 204',
+ '173, 153, 203',
+ '171, 151, 202',
+ '170, 149, 201',
+ '168, 147, 200',
+ '166, 145, 198',
+ '165, 143, 197',
+ '163, 140, 196',
+ '161, 138, 195',
+ '160, 136, 193',
+ '158, 134, 192',
+ '156, 132, 191',
+ '154, 130, 190',
+ '153, 128, 188',
+ '151, 126, 187',
+ '149, 124, 186',
+ '148, 122, 184',
+ '146, 120, 183',
+ '144, 118, 182',
+ '142, 116, 180',
+ '141, 114, 179',
+ '139, 111, 177',
+ '137, 109, 176',
+ '136, 107, 175',
+ '134, 105, 173',
+ '132, 103, 172',
+ '131, 101, 170',
+ '129, 99, 169',
+ '127, 97, 167',
+ '125, 95, 166',
+ '124, 93, 164',
+ '122, 91, 163',
+ '120, 90, 161',
+ '119, 88, 160',
+ '117, 86, 158',
+ '115, 84, 157',
+ '113, 82, 155',
+ '112, 80, 154',
+ '110, 78, 152',
+ '108, 76, 151',
+ '107, 74, 149',
+ '105, 72, 148',
+ '103, 70, 146',
+ '102, 68, 144',
+ '100, 66, 143',
+ '98, 64, 141',
+ '97, 63, 140',
+ '95, 61, 138',
+ '93, 59, 136',
+ '91, 57, 135',
+ '90, 55, 133',
+ '88, 53, 132',
+ '86, 51, 130',
+ '85, 49, 128',
+ '83, 47, 127',
+ '81, 46, 125',
+ '80, 44, 123',
+ '78, 42, 122',
+ '76, 40, 120',
+ '75, 38, 119',
+ '73, 36, 117',
+ '71, 34, 115',
+ '70, 32, 114',
+ '68, 31, 112',
+ '66, 29, 110',
+ '65, 27, 108',
+ '63, 25, 107',
+ '61, 23, 105',
+ '59, 21, 103',
+ '58, 19, 102',
+ '56, 17, 100',
+ '54, 15, 98',
+ '53, 12, 97',
+ '51, 10, 95',
+ ],
+ error_rate: [
+ '239, 224, 230',
+ '239, 222, 228',
+ '240, 219, 226',
+ '240, 217, 224',
+ '240, 214, 222',
+ '240, 212, 221',
+ '240, 209, 219',
+ '240, 207, 217',
+ '240, 204, 215',
+ '240, 202, 213',
+ '240, 200, 211',
+ '240, 197, 209',
+ '240, 195, 208',
+ '239, 192, 206',
+ '239, 190, 204',
+ '239, 188, 202',
+ '238, 185, 200',
+ '238, 183, 198',
+ '238, 181, 196',
+ '237, 178, 195',
+ '237, 176, 193',
+ '236, 174, 191',
+ '236, 172, 189',
+ '235, 169, 187',
+ '234, 167, 185',
+ '234, 165, 184',
+ '233, 163, 182',
+ '232, 160, 180',
+ '232, 158, 178',
+ '231, 156, 176',
+ '230, 154, 174',
+ '229, 151, 173',
+ '228, 149, 171',
+ '227, 147, 169',
+ '226, 145, 167',
+ '225, 143, 165',
+ '224, 141, 164',
+ '223, 139, 162',
+ '222, 136, 160',
+ '221, 134, 158',
+ '220, 132, 156',
+ '219, 130, 155',
+ '218, 128, 153',
+ '217, 126, 151',
+ '216, 124, 149',
+ '214, 122, 147',
+ '213, 120, 146',
+ '212, 118, 144',
+ '211, 116, 142',
+ '209, 114, 140',
+ '208, 112, 139',
+ '207, 110, 137',
+ '205, 108, 135',
+ '204, 106, 133',
+ '202, 104, 132',
+ '201, 102, 130',
+ '199, 100, 128',
+ '198, 98, 126',
+ '196, 96, 125',
+ '195, 95, 123',
+ '193, 93, 121',
+ '192, 91, 119',
+ '190, 89, 118',
+ '189, 87, 116',
+ '187, 85, 114',
+ '186, 84, 113',
+ '184, 82, 111',
+ '182, 80, 109',
+ '181, 78, 107',
+ '179, 76, 106',
+ '177, 75, 104',
+ '175, 73, 102',
+ '174, 71, 101',
+ '172, 70, 99',
+ '170, 68, 97',
+ '168, 66, 96',
+ '167, 65, 94',
+ '165, 63, 92',
+ '163, 61, 91',
+ '161, 60, 89',
+ '159, 58, 87',
+ '157, 56, 86',
+ '156, 55, 84',
+ '154, 53, 83',
+ '152, 52, 81',
+ '150, 50, 79',
+ '148, 49, 78',
+ '146, 47, 76',
+ '144, 46, 74',
+ '142, 44, 73',
+ '140, 43, 71',
+ '138, 41, 70',
+ '136, 40, 68',
+ '134, 38, 66',
+ '132, 37, 65',
+ '130, 35, 63',
+ '128, 34, 62',
+ '126, 33, 60',
+ '124, 31, 59',
+ '122, 30, 57',
+ ],
+ throughput: [
+ '216, 218, 225',
+ '214, 216, 225',
+ '211, 214, 226',
+ '209, 212, 226',
+ '206, 210, 226',
+ '204, 208, 226',
+ '202, 206, 226',
+ '199, 204, 226',
+ '197, 202, 226',
+ '195, 199, 226',
+ '193, 197, 226',
+ '190, 195, 225',
+ '188, 193, 225',
+ '186, 191, 225',
+ '184, 189, 224',
+ '181, 187, 224',
+ '179, 185, 223',
+ '177, 183, 223',
+ '175, 181, 222',
+ '173, 179, 221',
+ '171, 177, 221',
+ '168, 175, 220',
+ '166, 173, 219',
+ '164, 171, 218',
+ '162, 169, 218',
+ '160, 167, 217',
+ '158, 165, 216',
+ '156, 164, 215',
+ '154, 162, 214',
+ '152, 160, 213',
+ '150, 158, 212',
+ '148, 156, 211',
+ '146, 154, 210',
+ '144, 152, 209',
+ '142, 150, 208',
+ '140, 148, 207',
+ '138, 146, 206',
+ '136, 144, 205',
+ '134, 142, 204',
+ '132, 140, 203',
+ '130, 138, 202',
+ '128, 137, 200',
+ '126, 135, 199',
+ '124, 133, 198',
+ '122, 131, 197',
+ '120, 129, 196',
+ '118, 127, 194',
+ '116, 125, 193',
+ '114, 123, 192',
+ '112, 122, 191',
+ '110, 120, 189',
+ '108, 118, 188',
+ '106, 116, 187',
+ '105, 114, 186',
+ '103, 112, 184',
+ '101, 110, 183',
+ '99, 109, 182',
+ '97, 107, 180',
+ '95, 105, 179',
+ '93, 103, 178',
+ '91, 101, 176',
+ '89, 100, 175',
+ '88, 98, 173',
+ '86, 96, 172',
+ '84, 94, 171',
+ '82, 92, 169',
+ '80, 91, 168',
+ '78, 89, 166',
+ '76, 87, 165',
+ '74, 85, 163',
+ '72, 84, 162',
+ '70, 82, 161',
+ '68, 80, 159',
+ '67, 78, 158',
+ '65, 77, 156',
+ '63, 75, 155',
+ '61, 73, 153',
+ '59, 72, 152',
+ '57, 70, 150',
+ '55, 68, 149',
+ '53, 66, 147',
+ '51, 65, 146',
+ '49, 63, 144',
+ '47, 61, 143',
+ '45, 60, 141',
+ '42, 58, 140',
+ '40, 56, 138',
+ '38, 55, 137',
+ '36, 53, 135',
+ '34, 51, 134',
+ '31, 50, 132',
+ '29, 48, 130',
+ '26, 47, 129',
+ '23, 45, 127',
+ '20, 43, 126',
+ '17, 42, 124',
+ '14, 40, 123',
+ '9, 39, 121',
+ '5, 37, 120',
+ '1, 36, 118',
+
+ ],
+};
diff --git a/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filter_edit_popover.test.tsx.snap b/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filter_edit_popover.test.tsx.snap
new file mode 100644
index 0000000000..30c60dba19
--- /dev/null
+++ b/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filter_edit_popover.test.tsx.snap
@@ -0,0 +1,697 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Filter popover component renders filter popover 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+ Field
+
+
+
+
+
+
+
+
+
+
+
+
+ Select a field first
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Operator
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Save
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filter_helpers.test.tsx.snap b/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filter_helpers.test.tsx.snap
new file mode 100644
index 0000000000..48b5ff946e
--- /dev/null
+++ b/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filter_helpers.test.tsx.snap
@@ -0,0 +1,209 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Filter helper functions renders range field filter 1`] = `
+Array [
+
+
+ ,
+
+
+
+
+
+ Value
+
+
+
+
+
+ }
+ id="random_html_id"
+ onBlur={[Function]}
+ onFocus={[Function]}
+ startControl={
+
+ }
+ >
+
+
+
+
+
+
+ ,
+]
+`;
+
+exports[`Filter helper functions renders textfield filter 1`] = `
+Array [
+
+
+ ,
+
+
+ ,
+]
+`;
diff --git a/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filters.test.tsx.snap b/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filters.test.tsx.snap
new file mode 100644
index 0000000000..811b7c5c9e
--- /dev/null
+++ b/public/components/trace_analytics/components/common/filters/__tests__/__snapshots__/filters.test.tsx.snap
@@ -0,0 +1,198 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Filter component renders filters 1`] = `
+
+
+
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+
+
+
+ + Add filter
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="m"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+ + Add filter
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/trace_analytics/components/common/filters/__tests__/filter_edit_popover.test.tsx b/public/components/trace_analytics/components/common/filters/__tests__/filter_edit_popover.test.tsx
new file mode 100644
index 0000000000..4d2b0f401c
--- /dev/null
+++ b/public/components/trace_analytics/components/common/filters/__tests__/filter_edit_popover.test.tsx
@@ -0,0 +1,44 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { render } from '@testing-library/react';
+import { configure, mount, shallow } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import { FilterEditPopover } from '../filter_edit_popover';
+import { getFilterFields } from '../filter_helpers';
+
+describe('Filter popover component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders filter popover', () => {
+ const setFilter = jest.fn();
+ const closePopover = jest.fn();
+ const filterFieldOptions = getFilterFields('dashboard').map((field) => ({ label: field }));
+ const wrapper = mount(
+
+ );
+ expect(wrapper).toMatchSnapshot();
+
+ wrapper
+ .find('input')
+ .at(0)
+ .simulate('change', [{ label: 'traceGroup' }]);
+ wrapper
+ .find('input')
+ .at(1)
+ .simulate('change', [{ label: 'exists' }]);
+ wrapper.find('button[data-test-subj="filter-popover-cancel-button"]').simulate('click');
+
+ expect(closePopover).toBeCalled();
+
+ wrapper.find('button[data-test-subj="comboBoxToggleListButton"]').at(0).simulate('click');
+ });
+});
diff --git a/public/components/trace_analytics/components/common/filters/__tests__/filter_helpers.test.tsx b/public/components/trace_analytics/components/common/filters/__tests__/filter_helpers.test.tsx
new file mode 100644
index 0000000000..9084e4207c
--- /dev/null
+++ b/public/components/trace_analytics/components/common/filters/__tests__/filter_helpers.test.tsx
@@ -0,0 +1,111 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import {
+ getFilterFields,
+ getInvertedOperator,
+ getOperatorOptions,
+ getValidFilterFields,
+ getValueComponent,
+} from '../filter_helpers';
+
+describe('Filter helper functions', () => {
+ configure({ adapter: new Adapter() });
+
+ it('returns fields by page', () => {
+ const fields = getFilterFields('dashboard');
+ expect(fields).toEqual([
+ 'traceGroup',
+ 'serviceName',
+ 'error',
+ 'status.message',
+ 'latency',
+ ]);
+ });
+
+ it('returns valid fields by page', () => {
+ const dashboardFields = getValidFilterFields('dashboard');
+ const servicesFields = getValidFilterFields('services');
+ expect(dashboardFields).toEqual([
+ 'traceGroup',
+ 'serviceName',
+ 'error',
+ 'status.message',
+ 'latency',
+ 'Latency percentile within trace group',
+ ]);
+ expect(servicesFields).toEqual([
+ 'traceGroup',
+ 'serviceName',
+ 'error',
+ 'status.message',
+ 'latency',
+ ]);
+ });
+
+ it('returns inverted operators', () => {
+ const invertedBetween = getInvertedOperator('is between', true);
+ const invertedExist = getInvertedOperator('exists', true);
+ const invertedIs = getInvertedOperator('is', true);
+ expect(invertedBetween).toEqual('is not between');
+ expect(invertedExist).toEqual('does not exist');
+ expect(invertedIs).toEqual('is not');
+ });
+
+ it('returns operator options by field', () => {
+ const options = getOperatorOptions('durationInNanos');
+ expect(options).toEqual([
+ {
+ label: 'is',
+ },
+ {
+ label: 'is not',
+ },
+ {
+ label: 'is between',
+ },
+ {
+ label: 'is not between',
+ },
+ {
+ label: 'exists',
+ },
+ {
+ label: 'does not exist',
+ },
+ ]);
+ });
+
+ it('renders textfield filter', () => {
+ const setValue = jest.fn((v) => {});
+ const wrapper = mount(getValueComponent('serviceName', 'is', 0, setValue));
+ expect(wrapper).toMatchSnapshot();
+
+ wrapper.find('input').simulate('change', { target: { value: '100' } });
+ expect(setValue).toBeCalledWith('100');
+ });
+
+ it('renders range field filter', () => {
+ const setValue = jest.fn((v) => {});
+ const wrapper = mount(
+ getValueComponent('latency', 'is not between', { from: '0', to: '100' }, setValue)
+ );
+ expect(wrapper).toMatchSnapshot();
+
+ wrapper
+ .find('input')
+ .at(0)
+ .simulate('change', { target: { value: '50' } });
+ expect(setValue).toBeCalledWith({ from: '50', to: '100' });
+
+ wrapper
+ .find('input')
+ .at(1)
+ .simulate('change', { target: { value: '200' } });
+ expect(setValue).toBeCalledWith({ from: '0', to: '200' });
+ });
+});
diff --git a/public/components/trace_analytics/components/common/filters/__tests__/filters.test.tsx b/public/components/trace_analytics/components/common/filters/__tests__/filters.test.tsx
new file mode 100644
index 0000000000..c66a15df59
--- /dev/null
+++ b/public/components/trace_analytics/components/common/filters/__tests__/filters.test.tsx
@@ -0,0 +1,22 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { render } from '@testing-library/react';
+import { configure, mount, shallow } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import { Filters } from '../filters';
+
+describe('Filter component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders filters', () => {
+ const setFilters = jest.fn();
+ const wrapper = mount(
+
+ );
+ expect(wrapper).toMatchSnapshot();
+ });
+});
diff --git a/public/components/trace_analytics/components/common/filters/filter_edit_popover.tsx b/public/components/trace_analytics/components/common/filters/filter_edit_popover.tsx
new file mode 100644
index 0000000000..7f08827397
--- /dev/null
+++ b/public/components/trace_analytics/components/common/filters/filter_edit_popover.tsx
@@ -0,0 +1,128 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ EuiButton,
+ EuiButtonEmpty,
+ EuiComboBox,
+ EuiComboBoxOptionOption,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiFormRow,
+ EuiSpacer,
+} from '@elastic/eui';
+import React, { useState } from 'react';
+import { FilterType } from './filters';
+import { getInvertedOperator, getOperatorOptions, getValueComponent } from './filter_helpers';
+
+export function FilterEditPopover(props: {
+ filter?: FilterType;
+ index: number;
+ setFilter: (newFilter: FilterType, index: number) => void;
+ closePopover: () => void;
+ filterFieldOptions: Array<{ label: string }>;
+}) {
+ const [selectedFieldOptions, setSelectedFieldOptions] = useState<
+ Array>
+ >(props.filter ? [{ label: props.filter.field }] : []);
+ const [selectedOperatorOptions, setSelectedOperatorOptions] = useState<
+ Array>
+ >(
+ props.filter
+ ? [{ label: getInvertedOperator(props.filter.operator, props.filter.inverted) }]
+ : []
+ );
+ const [filterValue, setFilterValue] = useState(props.filter?.value || '');
+
+ return (
+
+ {/* invisible button workaround to prevent auto focus on context menu panel switch */}
+
+
+
+
+ {
+ setSelectedFieldOptions(e);
+ setSelectedOperatorOptions([]);
+ setFilterValue('');
+ }}
+ singleSelection={{ asPlainText: true }}
+ />
+
+
+
+
+ {
+ setSelectedOperatorOptions(e);
+ setFilterValue('');
+ }}
+ singleSelection={{ asPlainText: true }}
+ />
+
+
+
+ {selectedOperatorOptions.length > 0 &&
+ getValueComponent(
+ selectedFieldOptions[0].label,
+ selectedOperatorOptions[0].label,
+ filterValue,
+ setFilterValue
+ )}
+
+
+
+
+ Cancel
+
+
+
+ {
+ props.closePopover();
+ props.setFilter(
+ {
+ field: selectedFieldOptions[0].label,
+ operator: selectedOperatorOptions[0].label,
+ value: selectedOperatorOptions[0].label.includes('exist')
+ ? 'exists'
+ : filterValue,
+ inverted: selectedOperatorOptions[0].label.includes('not'),
+ disabled: props.filter ? props.filter.disabled : false,
+ },
+ props.index
+ );
+ }}
+ >
+ Save
+
+
+
+
+ );
+}
diff --git a/public/components/trace_analytics/components/common/filters/filter_helpers.tsx b/public/components/trace_analytics/components/common/filters/filter_helpers.tsx
new file mode 100644
index 0000000000..1410bfea00
--- /dev/null
+++ b/public/components/trace_analytics/components/common/filters/filter_helpers.tsx
@@ -0,0 +1,221 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ EuiComboBox,
+ EuiFieldText,
+ EuiFormControlLayoutDelimited,
+ EuiFormRow,
+ EuiSpacer,
+} from '@elastic/eui';
+import _ from 'lodash';
+import React from 'react';
+
+const getFields = (page: 'dashboard' | 'traces' | 'services' | 'app') =>
+ ({
+ dashboard: ['traceGroup', 'serviceName', 'error', 'status.message', 'latency'],
+ traces: ['traceId', 'traceGroup', 'serviceName', 'error', 'status.message', 'latency'],
+ services: ['traceGroup', 'serviceName', 'error', 'status.message', 'latency'],
+ app: ['traceId', 'traceGroup', 'serviceName'],
+ }[page]);
+// filters will take effect and can be manually added
+export const getFilterFields = (page: 'dashboard' | 'traces' | 'services' | 'app') => getFields(page);
+// filters will take effect
+export const getValidFilterFields = (page: 'dashboard' | 'traces' | 'services' | 'app') => {
+ const fields = getFields(page);
+ if (page !== 'services') return [...fields, 'Latency percentile within trace group'];
+ return fields;
+};
+
+const getType = (field: string): string | null => {
+ const typeMapping = {
+ attributes: {
+ host: {
+ port: 'long',
+ },
+ http: {
+ response_content_length: 'long',
+ status_code: 'long',
+ },
+ net: {
+ port: 'long',
+ },
+ },
+ attributes_host: {
+ port: 'long',
+ },
+ attributes_http: {
+ response_content_length: 'long',
+ status_code: 'long',
+ },
+ attributes_net: {
+ port: 'long',
+ },
+ durationInNanos: 'long',
+ latency: 'long',
+ endTime: 'date_nanos',
+ startTime: 'date_nanos',
+ };
+ const type = _.get(typeMapping, field, 'keyword');
+ return typeof type === 'string' ? type : null;
+};
+
+export const getInvertedOperator = (operator: string, inverted: boolean) => {
+ if (operator.includes('between')) return inverted ? 'is not between' : 'is between';
+ else if (operator.includes('exist')) return inverted ? 'does not exist' : 'exists';
+ else if (operator === 'is' || operator === 'is not') return inverted ? 'is not' : 'is';
+};
+
+export const getOperatorOptions = (field: string) => {
+ const type = getType(field);
+ const operatorMapping = {
+ long: [
+ {
+ label: 'is between',
+ },
+ {
+ label: 'is not between',
+ },
+ ],
+ date_nanos: [
+ {
+ label: 'is between',
+ },
+ {
+ label: 'is not between',
+ },
+ ],
+ keyword: [],
+ default_first: [
+ {
+ label: 'is',
+ },
+ {
+ label: 'is not',
+ },
+ ],
+ default_last: [
+ {
+ label: 'exists',
+ },
+ {
+ label: 'does not exist',
+ },
+ ],
+ };
+ const operators = [
+ ...operatorMapping.default_first,
+ ..._.get(operatorMapping, type),
+ ...operatorMapping.default_last,
+ ];
+ return operators;
+};
+
+export const getValueComponent = (
+ field: string,
+ operator: string,
+ value: any,
+ setValue: (v: any) => void
+) => {
+ const textField = (
+ <>
+
+
+ setValue(e.target.value)}
+ />
+
+ >
+ );
+
+ const getRangeField = () => {
+ const getFromValue = () => {
+ if (value?.from) {
+ return value.from.includes('\u221E') ? '' : value.from;
+ }
+ return '';
+ };
+ const getToValue = () => {
+ if (value?.to) {
+ return value.to.includes('\u221E') ? '' : value.to;
+ }
+ return '';
+ };
+ const setFromValue = (from: string) => {
+ setValue({ from: from || '-\u221E', to: getToValue() || '\u221E' });
+ };
+ const setToValue = (to: string) => {
+ setValue({ from: getFromValue() || '-\u221E', to: to || '\u221E' });
+ };
+ return (
+ <>
+
+
+ setFromValue(e.target.value)}
+ />
+ }
+ endControl={
+ setToValue(e.target.value)}
+ />
+ }
+ />
+
+ >
+ );
+ };
+
+ const getComboBoxField = () => {
+ return (
+ <>
+
+
+
+
+ >
+ );
+ };
+
+ if (field === 'error' && (operator === 'is' || operator === 'is not')) {
+ return getComboBoxField();
+ }
+
+ const valueMapping = {
+ is: textField,
+ 'is not': textField,
+ 'is between': getRangeField(),
+ 'is not between': getRangeField(),
+ exists: null,
+ 'does not exist': null,
+ };
+
+ return valueMapping[operator];
+};
diff --git a/public/components/trace_analytics/components/common/filters/filters.tsx b/public/components/trace_analytics/components/common/filters/filters.tsx
new file mode 100644
index 0000000000..d5a296b151
--- /dev/null
+++ b/public/components/trace_analytics/components/common/filters/filters.tsx
@@ -0,0 +1,320 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ EuiBadge,
+ EuiButtonEmpty,
+ EuiButtonIcon,
+ EuiContextMenu,
+ EuiContextMenuPanelDescriptor,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiIcon,
+ EuiPopover,
+ EuiPopoverTitle,
+ EuiTextColor,
+} from '@elastic/eui';
+import React, { useMemo, useState } from 'react';
+import { FilterEditPopover } from './filter_edit_popover';
+import { getFilterFields, getValidFilterFields } from './filter_helpers';
+
+export interface FilterType {
+ field: string;
+ operator: string;
+ value: any;
+ inverted: boolean;
+ disabled: boolean;
+ custom?: any;
+ locked?: boolean;
+}
+
+export interface FiltersProps {
+ filters: FilterType[];
+ appConfigs?: FilterType[];
+ setFilters: (filters: FilterType[]) => void;
+}
+
+interface FiltersOwnProps extends FiltersProps {
+ page: 'dashboard' | 'traces' | 'services' | 'app';
+}
+
+export function Filters(props: FiltersOwnProps) {
+ // set a filter at an index. if newFilter doesn't exist, remove filter at the index
+ // if index doesn't exist, append newFilter to the end
+ const setFilter = (newFilter: FilterType, index: number) => {
+ const newFilters = [...props.filters];
+ if (newFilter) newFilters.splice(index, 1, newFilter);
+ else newFilters.splice(index, 1);
+ props.setFilters(newFilters);
+ };
+
+ const validFilterFields = useMemo(() => getValidFilterFields(props.page), [props.page]);
+ const filterFieldOptions = useMemo(
+ () => getFilterFields(props.page).map((field) => ({ label: field })),
+ [props.page]
+ );
+
+ const globalPopoverPanels = [
+ {
+ id: 0,
+ title: 'Change all filters',
+ items: [
+ {
+ name: 'Enable all',
+ icon: ,
+ onClick: () => {
+ props.setFilters(
+ props.filters.map((filter) => ({
+ ...filter,
+ disabled: filter.locked ? filter.disabled : false,
+ }))
+ );
+ },
+ },
+ {
+ name: 'Disable all',
+ icon: ,
+ onClick: () => {
+ props.setFilters(
+ props.filters.map((filter) => ({
+ ...filter,
+ disabled: filter.locked ? filter.disabled : true,
+ }))
+ );
+ },
+ },
+ {
+ name: 'Invert inclusion',
+ icon: ,
+ onClick: () => {
+ props.setFilters(
+ // if filter.custom.query exists, it's a customized filter and "inverted" is alwasy false
+ props.filters.map((filter) => ({
+ ...filter,
+ inverted: filter.locked
+ ? filter.inverted
+ : filter.custom?.query
+ ? false
+ : !filter.inverted,
+ }))
+ );
+ },
+ },
+ {
+ name: 'Invert enabled/disabled',
+ icon: ,
+ onClick: () => {
+ props.setFilters(
+ props.filters.map((filter) => ({
+ ...filter,
+ disabled: filter.locked ? filter.disabled : !filter.disabled,
+ }))
+ );
+ },
+ },
+ {
+ name: 'Remove all',
+ icon: ,
+ onClick: () => {
+ props.setFilters([]);
+ },
+ },
+ ],
+ },
+ ];
+
+ const getFilterPopoverPanels = (
+ filter: FilterType,
+ index: number,
+ closePopover: () => void
+ ): EuiContextMenuPanelDescriptor[] => [
+ {
+ id: 0,
+ items: [
+ {
+ name: 'Edit filter',
+ icon: ,
+ disabled: !!filter.custom?.query || validFilterFields.indexOf(filter.field) === -1,
+ panel: 1,
+ },
+ {
+ name: `${filter.inverted ? 'Include' : 'Exclude'} results`,
+ icon: ,
+ disabled: !!filter.custom?.query || validFilterFields.indexOf(filter.field) === -1,
+ onClick: () => {
+ filter.inverted = !filter.inverted;
+ setFilter(filter, index);
+ },
+ },
+ {
+ name: filter.disabled ? 'Re-enable' : 'Temporarily disable',
+ icon: ,
+ disabled: validFilterFields.indexOf(filter.field) === -1,
+ onClick: () => {
+ filter.disabled = !filter.disabled;
+ setFilter(filter, index);
+ },
+ },
+ {
+ name: 'Delete',
+ icon: ,
+ onClick: () => setFilter(null, index),
+ },
+ ],
+ },
+ {
+ id: 1,
+ width: 430,
+ title: 'Edit filter',
+ content: (
+
+
+
+ ),
+ },
+ ];
+
+ const GlobalFilterButton = () => {
+ const [isPopoverOpen, setIsPopoverOpen] = useState(false);
+ return (
+ setIsPopoverOpen(false)}
+ button={
+ setIsPopoverOpen(true)}
+ iconType="filter"
+ title="Change all filters"
+ aria-label="Change all filters"
+ />
+ }
+ anchorPosition="rightUp"
+ panelPaddingSize="none"
+ withTitle
+ >
+
+
+ );
+ };
+
+ const AddFilterButton = () => {
+ const [isPopoverOpen, setIsPopoverOpen] = useState(false);
+ const button = (
+ {
+ setIsPopoverOpen(true);
+ }}
+ >
+ + Add filter
+
+ );
+
+ return (
+ setIsPopoverOpen(false)}
+ anchorPosition="downLeft"
+ withTitle
+ >
+ {'Add filter'}
+ setIsPopoverOpen(false)}
+ />
+
+ );
+ };
+
+ const renderFilters = () => {
+ const FilterBadge = ({ filter, index }: { filter: FilterType; index: number }) => {
+ const [isPopoverOpen, setIsPopoverOpen] = useState(false);
+ const disabled = filter.locked || filter.disabled;
+ const className =
+ 'globalFilterItem' +
+ (disabled ? ' globalFilterItem-isDisabled' : '') +
+ (filter.inverted ? ' globalFilterItem-isExcluded' : '');
+ const value =
+ typeof filter.value === 'string'
+ ? filter.value
+ : Array.isArray(filter.value) // combo box
+ ? filter.value[0].label
+ : `${filter.value.from} to ${filter.value.to}`; // range selector
+ const filterLabel = filter.inverted ? (
+ <>
+ {'NOT '}
+ {`${filter.field}: ${value}`}
+ >
+ ) : (
+ `${filter.field}: ${value}`
+ );
+
+ const badge = (
+ setIsPopoverOpen(true)}
+ onClickAriaLabel="Open filter settings"
+ color={disabled ? '#e7e9f0' : 'hollow'}
+ iconType="cross"
+ iconSide="right"
+ iconOnClick={() => {
+ setFilter(null, index);
+ }}
+ iconOnClickAriaLabel="Remove filter"
+ data-test-subj="filterBadge"
+ >
+ {filterLabel}
+
+ );
+ return (
+
+ setIsPopoverOpen(false)}
+ panelPaddingSize="none"
+ button={badge}
+ >
+ setIsPopoverOpen(false))}
+ />
+
+
+ );
+ };
+
+ return (
+ <>
+ {props.filters.length > 0
+ ? props.filters.map((filter, i) => )
+ : null}
+ >
+ );
+ };
+
+ const filterComponents = useMemo(() => renderFilters(), [props.filters]);
+
+ return (
+
+
+
+
+ {filterComponents}
+
+
+
+
+ );
+}
diff --git a/public/components/trace_analytics/components/common/helper_functions.tsx b/public/components/trace_analytics/components/common/helper_functions.tsx
new file mode 100644
index 0000000000..5bd437df84
--- /dev/null
+++ b/public/components/trace_analytics/components/common/helper_functions.tsx
@@ -0,0 +1,431 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable radix */
+
+import dateMath from '@elastic/datemath';
+import { EuiButton, EuiEmptyPrompt, EuiSpacer, EuiText } from '@elastic/eui';
+import { SpacerSize } from '@elastic/eui/src/components/spacer/spacer';
+import { isEmpty, round } from 'lodash';
+import React from 'react';
+import {
+ DATA_PREPPER_INDEX_NAME,
+ DATA_PREPPER_SERVICE_INDEX_NAME,
+ TRACE_ANALYTICS_DOCUMENTATION_LINK,
+} from '../../../../../common/constants/trace_analytics';
+import { uiSettingsService } from '../../../../../common/utils';
+import { serviceMapColorPalette } from './color_palette';
+import { FilterType } from './filters/filters';
+import { ServiceObject } from './plots/service_map';
+
+export function PanelTitle({ title, totalItems }: { title: string; totalItems?: number }) {
+ return (
+
+ {title}
+ {totalItems === 0 || totalItems ? (
+ {` (${totalItems})`}
+ ) : null}
+
+ );
+}
+
+export function NoMatchMessage(props: { size: SpacerSize }) {
+ return (
+ <>
+
+ No matches}
+ body={
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to
+ see more results.
+
+ }
+ />
+
+ >
+ );
+}
+
+export function MissingConfigurationMessage() {
+ return (
+ <>
+ Trace Analytics not set up}
+ body={
+
+ {`The indices required for trace analytics (${DATA_PREPPER_INDEX_NAME} and ${DATA_PREPPER_SERVICE_INDEX_NAME}) do not exist or you do not have permission to access them.`}
+
+ }
+ actions={
+ window.open(TRACE_ANALYTICS_DOCUMENTATION_LINK, '_blank')}
+ >
+ Learn more
+
+ }
+ />
+ >
+ );
+}
+
+export function renderBenchmark(value: number) {
+ if (typeof value !== 'number') return null;
+ const benchmarkColor = value === 0 ? '#9ea8a9' : value > 0 ? '#c23f25' : '#3f7e23';
+ const benchmarkArrow = value === 0 ? '-' : value > 0 ? '\u25B4' : '\u25BE';
+ return (
+
+ {`${Math.abs(value)}% ${benchmarkArrow}`}
+
+ );
+}
+
+export function nanoToMilliSec(nano: number) {
+ if (typeof nano !== 'number') return 0;
+ return nano / 1000000;
+}
+
+export function milliToNanoSec(ms: number) {
+ if (typeof ms !== 'number') return 0;
+ return ms * 1000000;
+}
+
+export function getServiceMapScaleColor(
+ percent: number,
+ idSelected: 'latency' | 'error_rate' | 'throughput'
+) {
+ return serviceMapColorPalette[idSelected][Math.min(99, Math.max(0, Math.floor(percent * 100)))];
+}
+
+// construct vis-js graph from ServiceObject
+export function getServiceMapGraph(
+ map: ServiceObject,
+ idSelected: 'latency' | 'error_rate' | 'throughput',
+ ticks: number[],
+ currService?: string,
+ relatedServices?: string[]
+) {
+ if (!relatedServices) relatedServices = Object.keys(map);
+
+ const nodes = Object.keys(map).map((service) => {
+ const value = map[service][idSelected];
+ let styleOptions;
+ if (value || value === 0) {
+ const percent = (value - ticks[0]) / (ticks[ticks.length - 1] - ticks[0]);
+ const color = getServiceMapScaleColor(percent, idSelected);
+ styleOptions = {
+ borderWidth: 0,
+ color: relatedServices!.indexOf(service) >= 0 ? `rgba(${color}, 1)` : `rgba(${color}, 0.2)`,
+ font: {
+ color:
+ relatedServices!.indexOf(service) >= 0
+ ? `rgba(72, 122, 180, 1)`
+ : `rgba(72, 122, 180, 0.2)`,
+ },
+ };
+ } else {
+ // service nodes that are not matched under traceGroup filter
+ styleOptions = {
+ borderWidth: 1.5,
+ chosen: false,
+ color: {
+ border: '#DADADC',
+ background: '#FFFFFF',
+ },
+ shapeProperties: {
+ borderDashes: [2, 2],
+ },
+ };
+ }
+
+ let hover = service;
+ hover += `\n\nAverage latency: ${
+ map[service].latency! >= 0 ? map[service].latency + 'ms' : 'N/A'
+ }`;
+ hover += `\nError rate: ${
+ map[service].error_rate! >= 0 ? map[service].error_rate + '%' : 'N/A'
+ }`;
+ hover += `\nThroughput: ${map[service].throughput! >= 0 ? map[service].throughput : 'N/A'}`;
+ if (map[service].throughputPerMinute != null)
+ hover += ` (${map[service].throughputPerMinute} per minute)`;
+
+ return {
+ id: map[service].id,
+ label: service,
+ size: service === currService ? 30 : 15,
+ title: hover,
+ ...styleOptions,
+ };
+ });
+ const edges: Array<{ from: number; to: number; color: string }> = [];
+ const edgeColor = uiSettingsService.get('theme:darkMode') ? '255, 255, 255' : '0, 0, 0';
+ Object.keys(map).map((service) => {
+ map[service].targetServices
+ .filter((target) => map[target])
+ .map((target) => {
+ edges.push({
+ from: map[service].id,
+ to: map[target].id,
+ color:
+ relatedServices!.indexOf(service) >= 0 && relatedServices!.indexOf(target) >= 0
+ ? `rgba(${edgeColor}, 1)`
+ : `rgba(${edgeColor}, 0.2)`,
+ });
+ });
+ });
+ return { graph: { nodes, edges } };
+}
+
+// returns flattened targetResource as an array for all traceGroups
+export function getServiceMapTargetResources(map: ServiceObject, serviceName: string) {
+ return ([] as string[]).concat.apply(
+ [],
+ [...map[serviceName].traceGroups.map((traceGroup) => [...traceGroup.targetResource])]
+ );
+}
+
+export function calculateTicks(min: number, max: number, numTicks = 5): number[] {
+ if (min >= max) return calculateTicks(0, Math.max(1, max), numTicks);
+ min = Math.floor(min);
+ max = Math.ceil(max);
+
+ const range = max - min;
+ const minInterval = range / numTicks;
+ const magnitude = Math.pow(10, Math.floor(Math.log10(minInterval)));
+ const residue = Math.ceil(minInterval / magnitude);
+
+ let tick = magnitude;
+ if (residue > 5) tick *= 10;
+ else if (residue > 2) tick *= 5;
+ else if (residue > 1) tick *= 2;
+
+ let curr = Math.max(0, Math.floor((min - 1) / tick) * tick);
+ const ticks = [curr];
+ while (curr < max) {
+ curr = round(curr + tick, 1);
+ ticks.push(curr);
+ }
+
+ return ticks;
+}
+
+// calculates the minimum fixed_interval for date_histogram from time filter
+export const minFixedInterval = (startTime: string, endTime: string) => {
+ if (startTime?.length === 0 || endTime?.length === 0 || startTime === endTime) return '1d';
+ const momentStart = dateMath.parse(startTime)!;
+ const momentEnd = dateMath.parse(endTime)!;
+ const diffSeconds = momentEnd.unix() - momentStart.unix();
+
+ if (diffSeconds <= 1) return '1ms'; // less than 1 second
+ if (diffSeconds <= 60 * 2) return '1s'; // less than 2 minutes
+ if (diffSeconds <= 3600 * 2) return '1m'; // less than 2 hours
+ if (diffSeconds <= 86400 * 2) return '1h'; // less than 2 days
+ if (diffSeconds <= 86400 * 62) return '1d'; // less than 2 months
+ if (diffSeconds <= 86400 * 366) return '30d'; // less than 1 year
+ return '365d';
+};
+
+export const fixedIntervalToMilli = (fixedInterval: string) => {
+ return {
+ '1ms': 1,
+ '1s': 1000,
+ '1m': 60000,
+ '1h': 3600000,
+ '1d': 86400000,
+ '30d': 86400000 * 30,
+ '365d': 86400000 * 365,
+ }[fixedInterval];
+};
+
+export const fixedIntervalToTickFormat = (fixedInterval: string) => {
+ if (fixedInterval === '1d') return '%b %e, %Y';
+ if (fixedInterval === '30d') return '%b %Y';
+ if (fixedInterval === '365d') return '%Y';
+ return '';
+};
+
+export const getPercentileFilter = (
+ percentileMaps: Array<{ traceGroupName: string; durationFilter: { gte?: number; lte?: number } }>,
+ conditionString: string // >= 95th, < 95th
+): FilterType => {
+ const DSL: any = {
+ query: {
+ bool: {
+ must: [],
+ filter: [],
+ should: [],
+ must_not: [],
+ minimum_should_match: 1,
+ },
+ },
+ };
+ percentileMaps.forEach((map) => {
+ DSL.query.bool.should.push({
+ bool: {
+ must: [
+ {
+ term: {
+ traceGroup: {
+ value: map.traceGroupName,
+ },
+ },
+ },
+ {
+ range: {
+ 'traceGroupFields.durationInNanos': map.durationFilter,
+ },
+ },
+ ],
+ },
+ });
+ });
+ return {
+ field: 'Latency percentile within trace group',
+ operator: '',
+ value: conditionString,
+ inverted: false,
+ disabled: false,
+ custom: DSL,
+ };
+};
+
+export const filtersToDsl = (
+ filters: FilterType[],
+ query: string,
+ startTime: string,
+ endTime: string,
+ page?: string,
+ appConfigs: FilterType[] = []
+) => {
+ const DSL: any = {
+ query: {
+ bool: {
+ must: [],
+ filter: [],
+ should: [],
+ must_not: [],
+ },
+ },
+ custom: {
+ timeFilter: [],
+ serviceNames: [],
+ serviceNamesExclude: [],
+ traceGroup: [],
+ traceGroupExclude: [],
+ percentiles: {
+ query: {
+ bool: {
+ should: [],
+ },
+ },
+ },
+ },
+ };
+ const timeFilter = {
+ range: {
+ startTime: {
+ gte: startTime,
+ lte: endTime,
+ },
+ },
+ };
+ DSL.query.bool.must.push(timeFilter);
+ DSL.custom.timeFilter.push(timeFilter);
+ if (query.length > 0) {
+ DSL.query.bool.must.push({
+ query_string: {
+ query,
+ },
+ });
+ }
+
+ filters
+ .filter((filter) => !filter.disabled && !filter.locked)
+ .forEach((filter) => {
+ if (filter.custom?.query) {
+ // add percentile filter
+ DSL.query.bool.should.push(...filter.custom.query.bool.should);
+ DSL.custom.percentiles.query.bool.should.push(...filter.custom.query.bool.should);
+ DSL.query.bool.minimum_should_match = filter.custom.query.bool.minimum_should_match;
+ DSL.custom.percentiles.query.bool.minimum_should_match =
+ filter.custom.query.bool.minimum_should_match;
+ return;
+ }
+
+ let filterQuery = {};
+ let field = filter.field;
+ if (field === 'latency') field = 'traceGroupFields.durationInNanos';
+ else if (field === 'error') field = 'traceGroupFields.statusCode';
+ let value;
+
+ switch (filter.operator) {
+ case 'exists':
+ case 'does not exist':
+ filterQuery = {
+ exists: {
+ field,
+ },
+ };
+ break;
+
+ case 'is':
+ case 'is not':
+ value = filter.value;
+ // latency and error are not actual fields, need to convert first
+ if (field === 'traceGroupFields.durationInNanos') {
+ value = milliToNanoSec(value);
+ } else if (field === 'traceGroupFields.statusCode') {
+ value = value[0].label === 'true' ? '2' : '0';
+ }
+
+ filterQuery = {
+ term: {
+ [field]: value,
+ },
+ };
+ break;
+
+ case 'is between':
+ case 'is not between':
+ const range: { gte?: string; lte?: string } = {};
+ if (!filter.value.from.includes('\u221E')) range.gte = filter.value.from;
+ if (!filter.value.to.includes('\u221E')) range.lte = filter.value.to;
+ if (field === 'traceGroupFields.durationInNanos') {
+ if (range.lte) range.lte = milliToNanoSec(parseInt(range.lte || '')).toString();
+ if (range.gte) range.gte = milliToNanoSec(parseInt(range.gte || '')).toString();
+ }
+ filterQuery = {
+ range: {
+ [field]: range,
+ },
+ };
+ break;
+
+ default:
+ break;
+ }
+ DSL.query.bool[filter.inverted ? 'must_not' : 'must'].push(filterQuery);
+ });
+
+ if (page === 'app' && !isEmpty(appConfigs)) {
+ DSL.query.bool.minimum_should_match = 1;
+ appConfigs.forEach((config) => {
+ let appQuery = {};
+ const appField = config.field;
+ const appValue = config.value;
+ appQuery = {
+ term: {
+ [appField]: appValue,
+ },
+ };
+ DSL.query.bool.minimum_should_match = 1;
+ DSL.query.bool.should.push(appQuery);
+ });
+ }
+
+ return DSL;
+};
diff --git a/public/components/trace_analytics/components/common/plots/__tests__/__snapshots__/box_plt.test.tsx.snap b/public/components/trace_analytics/components/common/plots/__tests__/__snapshots__/box_plt.test.tsx.snap
new file mode 100644
index 0000000000..7d7595e665
--- /dev/null
+++ b/public/components/trace_analytics/components/common/plots/__tests__/__snapshots__/box_plt.test.tsx.snap
@@ -0,0 +1,169 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Box plot component renders box plot 1`] = `
+
+
+
+
+
+ Latency <95 percentile
+
+
+
+
+
+
+ 20ms - 50ms
+
+
+
+
+
+
+ Latency >=95 percentile
+
+
+
+
+
+
+ 50ms - 80ms
+
+
+
+
+ }
+ delay="regular"
+ onMouseOut={[Function]}
+ position="bottom"
+ >
+
+
+
+`;
diff --git a/public/components/trace_analytics/components/common/plots/__tests__/__snapshots__/error_rate_plt_.test.tsx.snap b/public/components/trace_analytics/components/common/plots/__tests__/__snapshots__/error_rate_plt_.test.tsx.snap
new file mode 100644
index 0000000000..a996b25431
--- /dev/null
+++ b/public/components/trace_analytics/components/common/plots/__tests__/__snapshots__/error_rate_plt_.test.tsx.snap
@@ -0,0 +1,102 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Error rate plot component renders error rate plot 1`] = `
+
+
+
+
+ Error rate: %{y} ",
+ "marker": Object {
+ "color": "#fad963",
+ },
+ "text": Array [
+ "Dec 19, 2019 16:00:00 - Dec 18, 2020 16:00:00",
+ ],
+ "type": "bar",
+ "x": Array [
+ 1576800000000,
+ ],
+ "y": Array [
+ 22.22,
+ ],
+ },
+ ]
+ }
+ layout={
+ Object {
+ "annotations": Array [
+ Object {
+ "arrowhead": 0,
+ "arrowwidth": 0.7,
+ "ax": 0,
+ "ay": -160,
+ "borderpad": 10,
+ "showarrow": true,
+ "text": "Now: 22.22%",
+ "x": 1576800000000,
+ "xref": "x",
+ "y": 0,
+ "yref": "y",
+ },
+ ],
+ "height": 217,
+ "margin": Object {
+ "b": 50,
+ "l": 57,
+ "pad": 4,
+ "r": 5,
+ "t": 30,
+ },
+ "showlegend": false,
+ "xaxis": Object {
+ "color": "#899195",
+ "fixedrange": true,
+ "showgrid": false,
+ "tickformat": "%Y",
+ "type": "date",
+ "visible": true,
+ },
+ "yaxis": Object {
+ "color": "#899195",
+ "fixedrange": true,
+ "gridcolor": "#d9d9d9",
+ "range": Array [
+ 0,
+ 26.663999999999998,
+ ],
+ "showgrid": true,
+ "ticksuffix": "%",
+ "title": Object {
+ "font": Object {
+ "size": 12,
+ },
+ "standoff": 10,
+ "text": "Error rate (%)",
+ },
+ "visible": true,
+ },
+ }
+ }
+ onClickHandler={[Function]}
+ />
+
+
+`;
diff --git a/public/components/trace_analytics/components/common/plots/__tests__/__snapshots__/latency_trend_plt.test.tsx.snap b/public/components/trace_analytics/components/common/plots/__tests__/__snapshots__/latency_trend_plt.test.tsx.snap
new file mode 100644
index 0000000000..0acd3301f8
--- /dev/null
+++ b/public/components/trace_analytics/components/common/plots/__tests__/__snapshots__/latency_trend_plt.test.tsx.snap
@@ -0,0 +1,138 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Latency trend plot component renders dash 1`] = `
+
+ -
+
+`;
+
+exports[`Latency trend plot component renders latency plot 1`] = `
+
+ Average latency: %{y} ",
+ "line": Object {
+ "color": "#987dcb",
+ },
+ "marker": Object {
+ "color": "#987dcb",
+ "size": 8,
+ },
+ "mode": "lines+markers",
+ "type": "scatter",
+ "x": Array [
+ 1605027600000,
+ ],
+ "y": Array [
+ 284.47,
+ ],
+ },
+ ]
+ }
+ layout={
+ Object {
+ "annotations": Array [
+ Object {
+ "arrowhead": 0,
+ "arrowwidth": 0.7,
+ "ax": 0,
+ "ay": -140,
+ "borderpad": 10,
+ "showarrow": true,
+ "text": "Now: 284.47ms",
+ "x": 1605027600000,
+ "xref": "x",
+ "y": 0,
+ "yref": "y",
+ },
+ ],
+ "height": 200,
+ "margin": Object {
+ "b": 50,
+ "l": 50,
+ "pad": 0,
+ "r": 30,
+ "t": 30,
+ },
+ "width": 400,
+ "xaxis": Object {
+ "color": "#899195",
+ "showgrid": false,
+ "tickmode": "auto",
+ "type": "date",
+ },
+ "yaxis": Object {
+ "color": "#899195",
+ "gridcolor": "#d9d9d9",
+ "title": Object {
+ "font": Object {
+ "size": 12,
+ },
+ "text": "Hourly latency (ms)",
+ },
+ },
+ }
+ }
+ />
+
+`;
+
+exports[`Latency trend plot component renders line plot 1`] = `
+
+`;
diff --git a/public/components/trace_analytics/components/common/plots/__tests__/__snapshots__/service_map.test.tsx.snap b/public/components/trace_analytics/components/common/plots/__tests__/__snapshots__/service_map.test.tsx.snap
new file mode 100644
index 0000000000..ec80b8296d
--- /dev/null
+++ b/public/components/trace_analytics/components/common/plots/__tests__/__snapshots__/service_map.test.tsx.snap
@@ -0,0 +1,361 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Service map component renders service map 1`] = `
+
+
+
+
+
+
+
+
+
+ Focus on
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/trace_analytics/components/common/plots/__tests__/__snapshots__/service_map_scale.test.tsx.snap b/public/components/trace_analytics/components/common/plots/__tests__/__snapshots__/service_map_scale.test.tsx.snap
new file mode 100644
index 0000000000..f89aac7e88
--- /dev/null
+++ b/public/components/trace_analytics/components/common/plots/__tests__/__snapshots__/service_map_scale.test.tsx.snap
@@ -0,0 +1,328 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Service map scale component renders service map scale plot 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/trace_analytics/components/common/plots/__tests__/__snapshots__/throughput_plt.test.tsx.snap b/public/components/trace_analytics/components/common/plots/__tests__/__snapshots__/throughput_plt.test.tsx.snap
new file mode 100644
index 0000000000..49b00d65e1
--- /dev/null
+++ b/public/components/trace_analytics/components/common/plots/__tests__/__snapshots__/throughput_plt.test.tsx.snap
@@ -0,0 +1,95 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Throughput plot component renders throughput plot 1`] = `
+
+
+
+
+ Error rate: %{y} ",
+ "marker": Object {
+ "color": "#fad963",
+ },
+ "text": Array [
+ "Dec 19, 2019 16:00:00 - Dec 18, 2020 16:00:00",
+ ],
+ "type": "bar",
+ "x": Array [
+ 1576800000000,
+ ],
+ "y": Array [
+ 22.22,
+ ],
+ },
+ ]
+ }
+ layout={
+ Object {
+ "annotations": Array [
+ Object {
+ "arrowhead": 0,
+ "arrowwidth": 0.7,
+ "ax": 0,
+ "ay": -160,
+ "borderpad": 10,
+ "showarrow": true,
+ "text": "Now: 22.22",
+ "x": 1576800000000,
+ "xref": "x",
+ "y": 0,
+ "yref": "y",
+ },
+ ],
+ "height": 217,
+ "margin": Object {
+ "b": 50,
+ "l": 50,
+ "pad": 4,
+ "r": 5,
+ "t": 30,
+ },
+ "xaxis": Object {
+ "color": "#899195",
+ "fixedrange": true,
+ "showgrid": false,
+ "tickformat": "%Y",
+ "type": "date",
+ "visible": true,
+ },
+ "yaxis": Object {
+ "color": "#899195",
+ "fixedrange": true,
+ "gridcolor": "#d9d9d9",
+ "showgrid": true,
+ "title": Object {
+ "font": Object {
+ "size": 12,
+ },
+ "text": "Throughput (n)",
+ },
+ "visible": true,
+ },
+ }
+ }
+ onClickHandler={[Function]}
+ />
+
+
+`;
diff --git a/public/components/trace_analytics/components/common/plots/__tests__/box_plt.test.tsx b/public/components/trace_analytics/components/common/plots/__tests__/box_plt.test.tsx
new file mode 100644
index 0000000000..e5598e26a9
--- /dev/null
+++ b/public/components/trace_analytics/components/common/plots/__tests__/box_plt.test.tsx
@@ -0,0 +1,32 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { render } from '@testing-library/react';
+import { configure, mount, shallow } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import { BoxPlt } from '../box_plt';
+
+describe('Box plot component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders box plot', () => {
+ const addFilter = jest.fn();
+ const wrapper = shallow(
+
+ );
+ expect(wrapper).toMatchSnapshot();
+ });
+});
diff --git a/public/components/trace_analytics/components/common/plots/__tests__/error_rate_plt_.test.tsx b/public/components/trace_analytics/components/common/plots/__tests__/error_rate_plt_.test.tsx
new file mode 100644
index 0000000000..3203fbe82d
--- /dev/null
+++ b/public/components/trace_analytics/components/common/plots/__tests__/error_rate_plt_.test.tsx
@@ -0,0 +1,42 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { render } from '@testing-library/react';
+import { configure, mount, shallow } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import { ErrorRatePlt } from '../error_rate_plt';
+
+describe('Error rate plot component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders error rate plot', () => {
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const items = {
+ items: [
+ {
+ x: [1576800000000],
+ y: [22.22],
+ marker: {
+ color: '#fad963',
+ },
+ type: 'bar',
+ text: ['Dec 19, 2019 16:00:00 - Dec 18, 2020 16:00:00'],
+ hoverlabel: {
+ align: 'left',
+ },
+ hovertemplate: '%{text} Error rate: %{y} ',
+ },
+ ] as Plotly.Data[],
+ fixedInterval: '365d',
+ };
+ const wrapper = shallow(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+});
diff --git a/public/components/trace_analytics/components/common/plots/__tests__/latency_trend_plt.test.tsx b/public/components/trace_analytics/components/common/plots/__tests__/latency_trend_plt.test.tsx
new file mode 100644
index 0000000000..ee5d786e9e
--- /dev/null
+++ b/public/components/trace_analytics/components/common/plots/__tests__/latency_trend_plt.test.tsx
@@ -0,0 +1,78 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { render } from '@testing-library/react';
+import { configure, mount, shallow } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import { ErrorRatePlt } from '../error_rate_plt';
+import { LatencyPlt, LinePlt } from '../latency_trend_plt';
+
+describe('Latency trend plot component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders line plot', () => {
+ const data = [
+ {
+ x: [1605027600000, 1605027700000],
+ y: [78.16, 100],
+ type: 'scatter',
+ mode: 'lines',
+ hoverinfo: 'none',
+ line: {
+ color: '#000000',
+ width: 1,
+ },
+ },
+ ] as Plotly.Data[];
+ const wrapper = shallow( );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it('renders dash', () => {
+ const data = [
+ {
+ x: [1605027600000],
+ y: [78.16],
+ type: 'scatter',
+ mode: 'lines',
+ hoverinfo: 'none',
+ line: {
+ color: '#000000',
+ width: 1,
+ },
+ },
+ ] as Plotly.Data[];
+ const wrapper = shallow( );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it('renders latency plot', () => {
+ const data = [
+ {
+ x: [1605027600000],
+ y: [284.47],
+ type: 'scatter',
+ mode: 'lines+markers',
+ hovertemplate: '%{x} Average latency: %{y} ',
+ hoverlabel: {
+ bgcolor: '#d7c2ff',
+ },
+ marker: {
+ color: '#987dcb',
+ size: 8,
+ },
+ line: {
+ color: '#987dcb',
+ },
+ },
+ ] as Plotly.Data[];
+ const wrapper = shallow( );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+});
diff --git a/public/components/trace_analytics/components/common/plots/__tests__/service_map.test.tsx b/public/components/trace_analytics/components/common/plots/__tests__/service_map.test.tsx
new file mode 100644
index 0000000000..b7d505fb8f
--- /dev/null
+++ b/public/components/trace_analytics/components/common/plots/__tests__/service_map.test.tsx
@@ -0,0 +1,27 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, shallow } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { TEST_SERVICE_MAP } from '../../../../../../../test/constants';
+import { ServiceMap } from '../service_map';
+
+describe('Service map component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders service map', async () => {
+ const setServiceMapIdSelected = jest.fn((e) => {});
+ const wrapper = shallow(
+
+ );
+ expect(wrapper).toMatchSnapshot();
+ });
+});
diff --git a/public/components/trace_analytics/components/common/plots/__tests__/service_map_scale.test.tsx b/public/components/trace_analytics/components/common/plots/__tests__/service_map_scale.test.tsx
new file mode 100644
index 0000000000..811cc1920f
--- /dev/null
+++ b/public/components/trace_analytics/components/common/plots/__tests__/service_map_scale.test.tsx
@@ -0,0 +1,26 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { render } from '@testing-library/react';
+import { configure, mount, shallow } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import { ServiceMapScale } from '../service_map_scale';
+
+describe('Service map scale component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders service map scale plot', () => {
+ const wrapper = mount(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+});
diff --git a/public/components/trace_analytics/components/common/plots/__tests__/throughput_plt.test.tsx b/public/components/trace_analytics/components/common/plots/__tests__/throughput_plt.test.tsx
new file mode 100644
index 0000000000..c5f8d1b0f6
--- /dev/null
+++ b/public/components/trace_analytics/components/common/plots/__tests__/throughput_plt.test.tsx
@@ -0,0 +1,41 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { render } from '@testing-library/react';
+import { configure, mount, shallow } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import { ThroughputPlt } from '../throughput_plt';
+
+describe('Throughput plot component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders throughput plot', () => {
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const items = {
+ items: [
+ {
+ x: [1576800000000],
+ y: [22.22],
+ marker: {
+ color: '#fad963',
+ },
+ type: 'bar',
+ text: ['Dec 19, 2019 16:00:00 - Dec 18, 2020 16:00:00'],
+ hoverlabel: {
+ align: 'left',
+ },
+ hovertemplate: '%{text} Error rate: %{y} ',
+ },
+ ] as Plotly.Data[],
+ fixedInterval: '365d',
+ };
+ const wrapper = shallow(
+
+ );
+ expect(wrapper).toMatchSnapshot();
+ });
+});
diff --git a/public/components/trace_analytics/components/common/plots/box_plt.tsx b/public/components/trace_analytics/components/common/plots/box_plt.tsx
new file mode 100644
index 0000000000..d3c04f1cb5
--- /dev/null
+++ b/public/components/trace_analytics/components/common/plots/box_plt.tsx
@@ -0,0 +1,154 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { EuiFlexGrid, EuiFlexItem, EuiText, EuiToolTip } from '@elastic/eui';
+import React, { useMemo, useState } from 'react';
+import { Plt } from '../../../../visualizations/plotly/plot';
+
+interface PlotParamsType {
+ min: number;
+ max: number;
+ left: number;
+ mid: number;
+ right: number;
+ currPercentileFilter: string;
+ addFilter: (condition: 'gte' | 'lte') => void;
+}
+
+export function BoxPlt({ plotParams }: { plotParams: PlotParamsType }) {
+ const [hovered, setHovered] = useState('');
+
+ const getLayout = () =>
+ ({
+ plot_bgcolor: 'rgba(0, 0, 0, 0)',
+ paper_bgcolor: 'rgba(0, 0, 0, 0)',
+ xaxis: {
+ range: [plotParams.min, plotParams.max],
+ fixedrange: true,
+ showgrid: false,
+ visible: false,
+ },
+ yaxis: {
+ range: [-0.6, 0.6],
+ fixedrange: true,
+ showgrid: false,
+ visible: false,
+ },
+ margin: {
+ l: 0,
+ r: 0,
+ b: 0,
+ t: 0,
+ pad: 0,
+ },
+ height: 15,
+ width: 250,
+ } as Partial);
+
+ const getData = () =>
+ [
+ {
+ x: [plotParams.left],
+ y: [0],
+ type: 'bar',
+ orientation: 'h',
+ width: 1,
+ marker: { color: 'rgba(0, 0, 0, 0)' },
+ hoverinfo: 'none',
+ showlegend: false,
+ },
+ {
+ x: [plotParams.mid - plotParams.left],
+ y: [0],
+ type: 'bar',
+ orientation: 'h',
+ width: 1,
+ marker: {
+ color: plotParams.currPercentileFilter === '< 95th' ? '#fcfcfc' : '#ffffff',
+ line: {
+ color:
+ plotParams.currPercentileFilter === '< 95th'
+ ? '#eceded'
+ : hovered === 'lower'
+ ? '#2e73b5'
+ : '#957ac9',
+ width: hovered === 'lower' ? 3 : 1,
+ },
+ },
+ },
+ {
+ x: [plotParams.right - plotParams.mid],
+ y: [0],
+ type: 'bar',
+ orientation: 'h',
+ width: 1,
+ marker: {
+ color: plotParams.currPercentileFilter === '>= 95th' ? '#aea4d1' : '#957ac9',
+ line: {
+ color: hovered === 'upper' ? '#2e73b5' : '#957ac9',
+ width: hovered === 'upper' ? 3 : 1,
+ },
+ },
+ },
+ ] as Plotly.Data[];
+
+ const renderTooltip = () => {
+ return (
+
+
+
+ Latency <95 percentile
+
+
+
+
+ {`${Math.round(plotParams.left)}ms - ${Math.round(plotParams.mid)}ms`}
+
+
+
+
+ Latency >=95 percentile
+
+
+
+
+ {`${Math.round(plotParams.mid)}ms - ${Math.round(plotParams.right)}ms`}
+
+
+
+ );
+ };
+
+ const layout = useMemo(() => getLayout(), [plotParams]);
+ const data = useMemo(() => getData(), [plotParams, hovered]);
+ const tooltip = useMemo(() => renderTooltip(), [plotParams, hovered]);
+
+ const onHoverHandler = (e) => {
+ if (plotParams.currPercentileFilter) return;
+ const mouseX = e.xvals[0];
+ if (plotParams.left <= mouseX && mouseX <= plotParams.mid) setHovered('lower');
+ else if (plotParams.mid <= mouseX && mouseX <= plotParams.right) setHovered('upper');
+ else setHovered('');
+ };
+
+ const onClickHandler = (e) => {
+ if (plotParams.currPercentileFilter) return;
+ if (e.points[0].fullData.index === 1) plotParams.addFilter('lte');
+ else if (e.points[0].fullData.index === 2) plotParams.addFilter('gte');
+ };
+
+ return (
+ <>
+ setHovered('')}>
+
+
+ >
+ );
+}
diff --git a/public/components/trace_analytics/components/common/plots/error_rate_plt.tsx b/public/components/trace_analytics/components/common/plots/error_rate_plt.tsx
new file mode 100644
index 0000000000..7486245361
--- /dev/null
+++ b/public/components/trace_analytics/components/common/plots/error_rate_plt.tsx
@@ -0,0 +1,102 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { EuiHorizontalRule, EuiPanel } from '@elastic/eui';
+import moment from 'moment';
+import React, { useMemo } from 'react';
+import { Plt } from '../../../../visualizations/plotly/plot';
+import {
+ fixedIntervalToMilli,
+ fixedIntervalToTickFormat,
+ NoMatchMessage,
+ PanelTitle,
+} from '../helper_functions';
+
+export function ErrorRatePlt(props: {
+ items: { items: Plotly.Data[]; fixedInterval: string };
+ setStartTime: (startTime: string) => void;
+ setEndTime: (endTime: string) => void;
+}) {
+ const getLayout = () =>
+ ({
+ height: 217,
+ margin: {
+ l: 57,
+ r: 5,
+ b: 50,
+ t: 30,
+ pad: 4,
+ },
+ annotations: props.items.items.length > 0 && [
+ {
+ x: props.items.items[0]?.x[props.items.items[0]?.x.length - 1],
+ y: 0,
+ showarrow: true,
+ arrowhead: 0,
+ xref: 'x',
+ yref: 'y',
+ text: `Now: ${props.items.items[0]?.y[props.items.items[0]?.y.length - 1]}%`,
+ ax: 0,
+ ay: -160,
+ borderpad: 10,
+ arrowwidth: 0.7,
+ },
+ ],
+ showlegend: false,
+ xaxis: {
+ fixedrange: true,
+ showgrid: false,
+ visible: true,
+ type: 'date',
+ tickformat: fixedIntervalToTickFormat(props.items.fixedInterval),
+ color: '#899195',
+ },
+ yaxis: {
+ title: {
+ text: 'Error rate (%)',
+ font: {
+ size: 12,
+ },
+ standoff: 10,
+ },
+ range: [
+ 0,
+ Math.min(100, Math.max(...(props.items.items[0]?.y.map((y) => y * 1.2) || []), 1)),
+ ],
+ fixedrange: true,
+ ticksuffix: '%',
+ gridcolor: '#d9d9d9',
+ showgrid: true,
+ visible: true,
+ color: '#899195',
+ },
+ } as Partial);
+
+ const layout = useMemo(() => getLayout(), [props.items]);
+
+ const onClick = (event: any) => {
+ if (!event?.points) return;
+ const point = event.points[0];
+ const start = point.data.x[point.pointNumber];
+ const end = start + fixedIntervalToMilli(props.items.fixedInterval);
+ props.setStartTime(moment(start).toISOString());
+ props.setEndTime(moment(end).toISOString());
+ window.scrollTo({ left: 0, top: 0, behavior: 'smooth' });
+ };
+
+ return (
+ <>
+
+
+
+ {props.items?.items?.length > 0 ? (
+
+ ) : (
+
+ )}
+
+ >
+ );
+}
diff --git a/public/components/trace_analytics/components/common/plots/latency_trend_plt.tsx b/public/components/trace_analytics/components/common/plots/latency_trend_plt.tsx
new file mode 100644
index 0000000000..6589fe8d68
--- /dev/null
+++ b/public/components/trace_analytics/components/common/plots/latency_trend_plt.tsx
@@ -0,0 +1,94 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import _ from 'lodash';
+import React, { useMemo } from 'react';
+import { Plt } from '../../../../visualizations/plotly/plot';
+
+export function LinePlt(props: { data: Plotly.Data[] }) {
+ const maxY = props.data[0]?.y ? Math.max(...props.data[0].y) : 0;
+ const layout = useMemo(
+ () => ({
+ plot_bgcolor: 'rgba(0, 0, 0, 0)',
+ paper_bgcolor: 'rgba(0, 0, 0, 0)',
+ xaxis: {
+ fixedrange: true,
+ showgrid: false,
+ visible: false,
+ },
+ yaxis: {
+ fixedrange: true,
+ showgrid: false,
+ visible: false,
+ range: [0, maxY * 1.1],
+ },
+ margin: {
+ l: 0,
+ r: 0,
+ b: 0,
+ t: 0,
+ pad: 0,
+ },
+ height: 20,
+ width: 60,
+ }),
+ [props.data]
+ );
+ return props.data[0].x.length > 1 ? : -
;
+}
+
+export function LatencyPlt(props: { data: Plotly.Data[] }) {
+ const layout = useMemo(
+ () =>
+ ({
+ xaxis: {
+ showgrid: false,
+ type: 'date',
+ tickmode: 'auto',
+ color: '#899195',
+ },
+ yaxis: {
+ title: {
+ text: 'Hourly latency (ms)',
+ font: {
+ size: 12,
+ },
+ },
+ gridcolor: '#d9d9d9',
+ color: '#899195',
+ },
+ annotations: [
+ {
+ x: props.data[0].x[props.data[0].x.length - 1],
+ y: 0,
+ showarrow: true,
+ arrowhead: 0,
+ xref: 'x',
+ yref: 'y',
+ text: `Now: ${_.round(props.data[0].y[props.data[0].y.length - 1] as number, 2)}ms`,
+ ax: 0,
+ ay: -140,
+ borderpad: 10,
+ arrowwidth: 0.7,
+ },
+ ],
+ margin: {
+ l: 50,
+ r: 30,
+ b: 50,
+ t: 30,
+ pad: 0,
+ },
+ height: 200,
+ width: 400,
+ } as Partial),
+ [props.data]
+ );
+ return (
+ <>
+
+ >
+ );
+}
diff --git a/public/components/trace_analytics/components/common/plots/service_map.tsx b/public/components/trace_analytics/components/common/plots/service_map.tsx
new file mode 100644
index 0000000000..a636049682
--- /dev/null
+++ b/public/components/trace_analytics/components/common/plots/service_map.tsx
@@ -0,0 +1,233 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ EuiButtonGroup,
+ EuiFieldSearch,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiHorizontalRule,
+ EuiPanel,
+ EuiSpacer,
+ EuiText,
+} from '@elastic/eui';
+import React, { useEffect, useState } from 'react';
+// @ts-ignore
+import Graph from 'react-graph-vis';
+import { FilterType } from '../filters/filters';
+import {
+ calculateTicks,
+ getServiceMapGraph,
+ NoMatchMessage,
+ PanelTitle,
+} from '../helper_functions';
+import { ServiceMapScale } from './service_map_scale';
+
+export interface ServiceObject {
+ [key: string]: {
+ serviceName: string;
+ id: number;
+ traceGroups: Array<{ traceGroup: string; targetResource: string[] }>;
+ targetServices: string[];
+ destServices: string[];
+ latency?: number;
+ error_rate?: number;
+ throughput?: number;
+ throughputPerMinute?: number;
+ relatedServices?: string[]; // services appear in the same traces this service appears
+ };
+}
+
+export function ServiceMap({
+ serviceMap,
+ idSelected,
+ setIdSelected,
+ addFilter,
+ currService,
+ page,
+}: {
+ serviceMap: ServiceObject;
+ idSelected: 'latency' | 'error_rate' | 'throughput';
+ setIdSelected: (newId: 'latency' | 'error_rate' | 'throughput') => void;
+ addFilter?: (filter: FilterType) => void;
+ currService?: string;
+ page:
+ | 'app'
+ | 'appCreate'
+ | 'dashboard'
+ | 'traces'
+ | 'services'
+ | 'serviceView'
+ | 'detailFlyout'
+ | 'traceView';
+}) {
+ const [invalid, setInvalid] = useState(false);
+ const [network, setNetwork] = useState(null);
+ const [ticks, setTicks] = useState([]);
+ const [items, setItems] = useState({});
+ const [query, setQuery] = useState('');
+ const toggleButtons = [
+ {
+ id: 'latency',
+ label: 'Latency',
+ },
+ {
+ id: 'error_rate',
+ label: 'Error rate',
+ },
+ {
+ id: 'throughput',
+ label: 'Throughput',
+ },
+ ];
+
+ const options = {
+ layout: {
+ hierarchical: false,
+ },
+ edges: {
+ arrows: {
+ to: {
+ enabled: false,
+ },
+ },
+ physics: false,
+ },
+ nodes: {
+ shape: 'dot',
+ color: '#adadad',
+ borderWidth: 0,
+ font: {
+ size: 17,
+ color: '#387ab9',
+ },
+ },
+ interaction: {
+ hover: true,
+ tooltipDelay: 30,
+ selectable: true,
+ },
+ manipulation: {
+ enabled: false,
+ },
+ height: '434px',
+ width: '100%',
+ autoResize: true,
+ };
+
+ const events = {
+ select: (event: any) => {
+ const { nodes, edges } = event;
+ if (!addFilter || !nodes) return;
+ const serviceName = items?.graph.nodes.find((node: any) => node.id === nodes[0])?.label;
+ if (serviceName) {
+ addFilter({
+ field: 'serviceName',
+ operator: 'is',
+ value: serviceName,
+ inverted: false,
+ disabled: false,
+ });
+ if (!['appCreate', 'detailFlyout'].includes(page)) {
+ window.scrollTo({ left: 0, top: 0, behavior: 'smooth' });
+ }
+ }
+ },
+ hoverNode: (event: any) => {},
+ };
+
+ const onFocus = (service: string, networkInstance?: any) => {
+ if (service.length === 0) {
+ setInvalid(false);
+ } else if (serviceMap[service]) {
+ if (!networkInstance) networkInstance = network;
+ networkInstance.focus(serviceMap[service].id, { animation: true });
+ setInvalid(false);
+ } else {
+ setInvalid(true);
+ }
+ };
+
+ useEffect(() => {
+ if (Object.keys(serviceMap).length === 0) return;
+ const values = Object.keys(serviceMap)
+ .filter((service) => serviceMap[service][idSelected])
+ .map((service) => serviceMap[service][idSelected]!);
+ const min = Math.min(...values);
+ const max = Math.max(...values);
+ const calculatedTicks = calculateTicks(min, max);
+ setTicks(calculatedTicks);
+ setItems(
+ getServiceMapGraph(
+ serviceMap,
+ idSelected,
+ calculatedTicks,
+ currService,
+ serviceMap[currService!]?.relatedServices
+ )
+ );
+ }, [serviceMap, idSelected]);
+
+ return (
+ <>
+
+ {page === 'app' ? (
+
+ ) : (
+
+ )}
+
+ setIdSelected(id as 'latency' | 'error_rate' | 'throughput')}
+ buttonSize="s"
+ color="text"
+ />
+
+
+
+ Focus on
+
+
+ setQuery(e.target.value)}
+ onSearch={(service) => onFocus(service)}
+ isInvalid={query.length > 0 && invalid}
+ />
+
+
+
+
+ {Object.keys(serviceMap).length > 0 ? (
+
+
+ {items?.graph && (
+ {
+ setNetwork(networkInstance);
+ if (currService) onFocus(currService, networkInstance);
+ }}
+ />
+ )}
+
+
+
+
+
+ ) : (
+
+
+
+ )}
+
+ >
+ );
+}
diff --git a/public/components/trace_analytics/components/common/plots/service_map_scale.tsx b/public/components/trace_analytics/components/common/plots/service_map_scale.tsx
new file mode 100644
index 0000000000..86d11b7ec2
--- /dev/null
+++ b/public/components/trace_analytics/components/common/plots/service_map_scale.tsx
@@ -0,0 +1,132 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText } from '@elastic/eui';
+import _ from 'lodash';
+import React, { useEffect, useState } from 'react';
+import { Plt } from '../../../../visualizations/plotly/plot';
+import unmatchedNode from '../../../images/unmatched_node.png';
+import { getServiceMapScaleColor } from '../helper_functions';
+import { ServiceObject } from './service_map';
+
+export function ServiceMapScale(props: {
+ idSelected: 'latency' | 'error_rate' | 'throughput';
+ serviceMap: ServiceObject;
+ ticks: number[];
+}) {
+ const [scaleProps, setScaleProps] = useState({});
+ const getScaleData = () => {
+ const ticks = props.ticks;
+ const delta = ticks[1] - ticks[0];
+ const title = { latency: 'Latency (ms)', error_rate: 'Error rate', throughput: 'Throughput' }[
+ props.idSelected
+ ];
+ const percentInterval = 1 / Math.max(ticks.length - 1, 1);
+ const percents = Array.from({ length: ticks.length - 1 }, (v, i) => percentInterval * i);
+ const color = percents
+ .map((percent) => getServiceMapScaleColor(percent, props.idSelected))
+ .map((rgb) => `rgb(${rgb})`);
+
+ const result = {
+ data: {
+ y: [delta + ticks[0], ...Array.from({ length: ticks.length - 1 }, () => delta)],
+ marker: {
+ color,
+ },
+ },
+ layout: {
+ yaxis: {
+ range: [ticks[0], ticks[ticks.length - 1]],
+ ticksuffix: props.idSelected === 'error_rate' ? '%' : '',
+ title: {
+ text: title,
+ standoff: 15,
+ },
+ },
+ },
+ };
+ return result;
+ };
+
+ const getScaleProps = () => {
+ const result = getScaleData();
+ const data = [
+ {
+ x: Array.from({ length: result.data.y.length }, () => 0),
+ type: 'bar',
+ orientation: 'v',
+ width: 0.4,
+ hoverinfo: 'none',
+ showlegend: false,
+ ...result.data,
+ },
+ ] as Plotly.Data;
+
+ const layout = _.merge(
+ {
+ plot_bgcolor: 'rgba(0, 0, 0, 0)',
+ paper_bgcolor: 'rgba(0, 0, 0, 0)',
+ xaxis: {
+ range: [-0.35, 0.35],
+ fixedrange: true,
+ showgrid: false,
+ showline: false,
+ zeroline: false,
+ showticklabels: false,
+ },
+ yaxis: {
+ side: 'right',
+ fixedrange: true,
+ showgrid: false,
+ showline: false,
+ zeroline: false,
+ showticklabels: true,
+ tickvals: props.ticks,
+ ticktexts: props.ticks,
+ },
+ margin: {
+ l: 0,
+ r: 60,
+ b: 10,
+ t: 10,
+ pad: 0,
+ },
+ height: 270,
+ width: 77,
+ },
+ result.layout
+ ) as Partial;
+ return { data, layout };
+ };
+
+ useEffect(() => {
+ if (Object.keys(props.ticks).length > 0) setScaleProps(getScaleProps());
+ }, [props.idSelected, props.serviceMap, props.ticks]);
+
+ return (
+
+ {Object.keys(props.ticks).length > 0 && (
+ <>
+
+
+
+
+
+
+
+
+ No match
+
+
+
+ >
+ )}
+
+ );
+}
diff --git a/public/components/trace_analytics/components/common/plots/throughput_plt.tsx b/public/components/trace_analytics/components/common/plots/throughput_plt.tsx
new file mode 100644
index 0000000000..aba6bb2833
--- /dev/null
+++ b/public/components/trace_analytics/components/common/plots/throughput_plt.tsx
@@ -0,0 +1,98 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { EuiHorizontalRule, EuiPanel } from '@elastic/eui';
+import moment from 'moment';
+import React, { useMemo } from 'react';
+import { Plt } from '../../../../visualizations/plotly/plot';
+import {
+ fixedIntervalToMilli,
+ fixedIntervalToTickFormat,
+ NoMatchMessage,
+ PanelTitle,
+} from '../helper_functions';
+
+export function ThroughputPlt(props: {
+ items: { items: Plotly.Data[]; fixedInterval: string };
+ setStartTime: (startTime: string) => void;
+ setEndTime: (endTime: string) => void;
+}) {
+ const layout = useMemo(
+ () =>
+ ({
+ height: 217,
+ margin: {
+ l: 50,
+ r: 5,
+ b: 50,
+ t: 30,
+ pad: 4,
+ },
+ annotations: props.items.items.length > 0 && [
+ {
+ x: props.items.items[0].x[props.items.items[0].x.length - 1],
+ y: 0,
+ showarrow: true,
+ arrowhead: 0,
+ xref: 'x',
+ yref: 'y',
+ text: `Now: ${props.items.items[0].y[props.items.items[0].y.length - 1]?.toLocaleString(
+ undefined
+ )}`,
+ ax: 0,
+ ay: -160,
+ borderpad: 10,
+ arrowwidth: 0.7,
+ },
+ ],
+ xaxis: {
+ fixedrange: true,
+ showgrid: false,
+ visible: true,
+ type: 'date',
+ tickformat: fixedIntervalToTickFormat(props.items.fixedInterval),
+ color: '#899195',
+ },
+ yaxis: {
+ title: {
+ text: 'Throughput (n)',
+ font: {
+ size: 12,
+ },
+ },
+ fixedrange: true,
+ gridcolor: '#d9d9d9',
+ showgrid: true,
+ visible: true,
+ color: '#899195',
+ },
+ } as Partial),
+ [props.items]
+ );
+
+ const onClick = (event) => {
+ if (!event?.points) return;
+ const point = event.points[0];
+ const start = point.data.x[point.pointNumber];
+ const end = start + fixedIntervalToMilli(props.items.fixedInterval);
+ props.setStartTime(moment(start).toISOString());
+ props.setEndTime(moment(end).toISOString());
+ window.scrollTo({ left: 0, top: 0, behavior: 'smooth' });
+ };
+
+ return (
+ <>
+
+
+
+ {props.items?.items?.length > 0 ? (
+
+ ) : (
+
+ )}
+
+ >
+ );
+}
diff --git a/public/components/trace_analytics/components/common/search_bar.tsx b/public/components/trace_analytics/components/common/search_bar.tsx
new file mode 100644
index 0000000000..b67b8864eb
--- /dev/null
+++ b/public/components/trace_analytics/components/common/search_bar.tsx
@@ -0,0 +1,105 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ EuiButton,
+ EuiFieldSearch,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiSpacer,
+ EuiSuperDatePicker,
+} from '@elastic/eui';
+import _ from 'lodash';
+import React, { useState } from 'react';
+import { uiSettingsService } from '../../../../../common/utils';
+import { Filters, FiltersProps } from './filters/filters';
+
+export const renderDatePicker = (
+ startTime: string,
+ setStartTime: (startTime: string) => void,
+ endTime: string,
+ setEndTime: (endTime: string) => void
+) => {
+ return (
+ {
+ setStartTime(e.start);
+ setEndTime(e.end);
+ }}
+ />
+ );
+};
+
+export interface SearchBarProps extends FiltersProps {
+ query: string;
+ setQuery: (query: string) => void;
+ startTime: string;
+ setStartTime: (startTime: string) => void;
+ endTime: string;
+ setEndTime: (endTime: string) => void;
+}
+
+interface SearchBarOwnProps extends SearchBarProps {
+ refresh: () => void;
+ page: 'dashboard' | 'traces' | 'services' | 'app';
+ datepickerOnly?: boolean;
+}
+
+export function SearchBar(props: SearchBarOwnProps) {
+ // use another query state to avoid typing delay
+ const [query, setQuery] = useState(props.query);
+ const setGlobalQuery = _.debounce((q) => props.setQuery(q), 50);
+
+ return (
+ <>
+
+ {!props.datepickerOnly && (
+
+ {
+ setQuery(e.target.value);
+ setGlobalQuery(e.target.value);
+ }}
+ onSearch={props.refresh}
+ />
+
+ )}
+
+ {renderDatePicker(props.startTime, props.setStartTime, props.endTime, props.setEndTime)}
+
+
+
+ Refresh
+
+
+
+
+ {!props.datepickerOnly && (
+ <>
+
+
+ >
+ )}
+ >
+ );
+}
diff --git a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/dashboard.test.tsx.snap b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/dashboard.test.tsx.snap
new file mode 100644
index 0000000000..be5cacf4a3
--- /dev/null
+++ b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/dashboard.test.tsx.snap
@@ -0,0 +1,3228 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Dashboard component renders dashboard 1`] = `
+
+
+
+ Dashboard
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ >
+
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="QuickSelectPopover"
+ isOpen={false}
+ ownFocus={true}
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
}
+ iconType={false}
+ isCustom={true}
+ startDateControl={
}
+ >
+
+
+ Last 5 minutes
+
+
+ Show dates
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Refresh
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+
+
+
+ + Add filter
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="m"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+ + Add filter
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latency by trace group
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ □
+
+ < 95 percentile
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ■
+
+ >= 95 percentile
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+ }
+ title={
+
+ No matches
+
+ }
+ >
+
+
+
+
+
+ No matches
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Service map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+ }
+ title={
+
+ No matches
+
+ }
+ >
+
+
+
+
+
+ No matches
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace error rate over time
+
+
+
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+ }
+ title={
+
+ No matches
+
+ }
+ >
+
+
+
+
+
+ No matches
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Traces over time
+
+
+
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+ }
+ title={
+
+ No matches
+
+ }
+ >
+
+
+
+
+
+ No matches
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Dashboard component renders empty dashboard 1`] = `
+
+
+
+ Dashboard
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ >
+
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="QuickSelectPopover"
+ isOpen={false}
+ ownFocus={true}
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
}
+ iconType={false}
+ isCustom={true}
+ startDateControl={
}
+ >
+
+
+ Last 5 minutes
+
+
+ Show dates
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Refresh
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+
+
+
+ + Add filter
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="m"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+ + Add filter
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Learn more
+
+ }
+ body={
+
+ The indices required for trace analytics (otel-v1-apm-span-* and otel-v1-apm-service-map*) do not exist or you do not have permission to access them.
+
+ }
+ title={
+
+ Trace Analytics not set up
+
+ }
+ >
+
+
+
+
+
+ Trace Analytics not set up
+
+
+
+
+
+
+
+
+
+ The indices required for trace analytics (otel-v1-apm-span-* and otel-v1-apm-service-map*) do not exist or you do not have permission to access them.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Learn more
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/dashboard_table.test.tsx.snap b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/dashboard_table.test.tsx.snap
new file mode 100644
index 0000000000..eca701df5f
--- /dev/null
+++ b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/dashboard_table.test.tsx.snap
@@ -0,0 +1,3479 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Dashboard table component renders dashboard table 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+ Latency by trace group
+
+
+ (1)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ □
+
+ < 95 percentile
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ■
+
+ >= 95 percentile
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Traces of all requests that share a common API and operation at the start of distributed tracing instrumentation.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Trace group name
+
+
+
+
+
+
+
+ ,
+ "render": [Function],
+ "sortable": true,
+ },
+ Object {
+ "align": "center",
+ "field": "dashboard_latency_variance",
+ "name":
+
+ Range of latencies for traces within a trace group in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+ Latency variance (ms)
+
+
+
+
+
+ 0 100 200 300 400
+
+ ,
+ "render": [Function],
+ "sortable": [Function],
+ "width": "300px",
+ },
+ Object {
+ "align": "right",
+ "dataType": "number",
+ "field": "dashboard_average_latency",
+ "name":
+ Average latency of traces within a trace group in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Average latency (ms)
+
+
+
+
+
+
+
+ ,
+ "render": [Function],
+ "sortable": true,
+ },
+ Object {
+ "align": "right",
+ "field": "24_hour_latency_trend",
+ "name":
+ 24 hour time series view of hourly average, hourly percentile, and hourly range of latency for traces within a trace group.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ 24-hour latency trend
+
+
+
+
+
+
+
+ ,
+ "render": [Function],
+ "sortable": false,
+ },
+ Object {
+ "align": "right",
+ "field": "dashboard_error_rate",
+ "name":
+ Error rate based on count of trace errors within a trace group in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Error rate
+
+
+
+
+
+
+
+ ,
+ "render": [Function],
+ "sortable": true,
+ },
+ Object {
+ "align": "right",
+ "field": "dashboard_traces",
+ "name":
+ Count of traces with unique trace identifiers in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Traces
+
+
+
+
+
+
+
+ ,
+ "render": [Function],
+ "sortable": true,
+ },
+ ]
+ }
+ data-test-subj="dashboardTable"
+ items={
+ Array [
+ Object {
+ "24_hour_latency_trend": null,
+ "dashboard_average_latency": 187.27,
+ "dashboard_error_rate": 14.285714285714285,
+ "dashboard_latency_variance": Array [
+ 26.43,
+ 325.4,
+ 325.4,
+ ],
+ "dashboard_trace_group_name": "client_create_order",
+ "dashboard_traces": 7,
+ },
+ ]
+ }
+ loading={false}
+ onTableChange={[Function]}
+ pagination={
+ Object {
+ "initialPageSize": 10,
+ "pageSizeOptions": Array [
+ 5,
+ 10,
+ 15,
+ ],
+ }
+ }
+ responsive={true}
+ sorting={
+ Object {
+ "sort": Object {
+ "direction": "desc",
+ "field": "dashboard_latency_variance",
+ },
+ }
+ }
+ tableLayout="auto"
+ >
+
+ Traces of all requests that share a common API and operation at the start of distributed tracing instrumentation.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Trace group name
+
+
+
+
+
+
+
+ ,
+ "render": [Function],
+ "sortable": true,
+ },
+ Object {
+ "align": "center",
+ "field": "dashboard_latency_variance",
+ "name":
+
+ Range of latencies for traces within a trace group in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+ Latency variance (ms)
+
+
+
+
+
+ 0 100 200 300 400
+
+ ,
+ "render": [Function],
+ "sortable": [Function],
+ "width": "300px",
+ },
+ Object {
+ "align": "right",
+ "dataType": "number",
+ "field": "dashboard_average_latency",
+ "name":
+ Average latency of traces within a trace group in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Average latency (ms)
+
+
+
+
+
+
+
+ ,
+ "render": [Function],
+ "sortable": true,
+ },
+ Object {
+ "align": "right",
+ "field": "24_hour_latency_trend",
+ "name":
+ 24 hour time series view of hourly average, hourly percentile, and hourly range of latency for traces within a trace group.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ 24-hour latency trend
+
+
+
+
+
+
+
+ ,
+ "render": [Function],
+ "sortable": false,
+ },
+ Object {
+ "align": "right",
+ "field": "dashboard_error_rate",
+ "name":
+ Error rate based on count of trace errors within a trace group in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Error rate
+
+
+
+
+
+
+
+ ,
+ "render": [Function],
+ "sortable": true,
+ },
+ Object {
+ "align": "right",
+ "field": "dashboard_traces",
+ "name":
+ Count of traces with unique trace identifiers in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Traces
+
+
+
+
+
+
+
+ ,
+ "render": [Function],
+ "sortable": true,
+ },
+ ]
+ }
+ data-test-subj="dashboardTable"
+ items={
+ Array [
+ Object {
+ "24_hour_latency_trend": null,
+ "dashboard_average_latency": 187.27,
+ "dashboard_error_rate": 14.285714285714285,
+ "dashboard_latency_variance": Array [
+ 26.43,
+ 325.4,
+ 325.4,
+ ],
+ "dashboard_trace_group_name": "client_create_order",
+ "dashboard_traces": 7,
+ },
+ ]
+ }
+ loading={false}
+ noItemsMessage="No items found"
+ onChange={[Function]}
+ pagination={
+ Object {
+ "hidePerPageOptions": undefined,
+ "pageIndex": 0,
+ "pageSize": 10,
+ "pageSizeOptions": Array [
+ 5,
+ 10,
+ 15,
+ ],
+ "totalItemCount": 1,
+ }
+ }
+ responsive={true}
+ sorting={
+ Object {
+ "allowNeutralSort": true,
+ "sort": Object {
+ "direction": "desc",
+ "field":
+
+ Range of latencies for traces within a trace group in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+ Latency variance (ms)
+
+
+
+
+
+ 0 100 200 300 400
+
+ ,
+ },
+ }
+ }
+ tableLayout="auto"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+ Traces of all requests that share a common API and operation at the start of distributed tracing instrumentation.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Trace group name
+
+
+
+
+
+
+
+ ,
+ "onSort": [Function],
+ },
+ Object {
+ "isSortAscending": false,
+ "isSorted": true,
+ "key": "_data_s_dashboard_latency_variance_1",
+ "name":
+
+ Range of latencies for traces within a trace group in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+ Latency variance (ms)
+
+
+
+
+
+ 0 100 200 300 400
+
+ ,
+ "onSort": [Function],
+ },
+ Object {
+ "isSortAscending": undefined,
+ "isSorted": false,
+ "key": "_data_s_dashboard_average_latency_2",
+ "name":
+ Average latency of traces within a trace group in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Average latency (ms)
+
+
+
+
+
+
+
+ ,
+ "onSort": [Function],
+ },
+ Object {
+ "isSortAscending": undefined,
+ "isSorted": false,
+ "key": "_data_s_dashboard_error_rate_4",
+ "name":
+ Error rate based on count of trace errors within a trace group in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Error rate
+
+
+
+
+
+
+
+ ,
+ "onSort": [Function],
+ },
+ Object {
+ "isSortAscending": undefined,
+ "isSorted": false,
+ "key": "_data_s_dashboard_traces_5",
+ "name":
+ Count of traces with unique trace identifiers in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Traces
+
+
+
+
+
+
+
+ ,
+ "onSort": [Function],
+ },
+ ]
+ }
+ >
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelPaddingSize="none"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sorting
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Traces of all requests that share a common API and operation at the start of distributed tracing instrumentation.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Trace group name
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Click to sort in ascending order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Range of latencies for traces within a trace group in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Latency variance (ms)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0 100 200 300 400
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Click to unsort
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Average latency of traces within a trace group in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Average latency (ms)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Click to sort in ascending order
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 24 hour time series view of hourly average, hourly percentile, and hourly range of latency for traces within a trace group.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ 24-hour latency trend
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Error rate based on count of trace errors within a trace group in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Error rate
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Click to sort in ascending order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Count of traces with unique trace identifiers in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Traces
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Click to sort in ascending order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Traces of all requests that share a common API and operation at the start of distributed tracing instrumentation.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Trace group name
+
+
+
+
+
+
+
+ ,
+ "render": undefined,
+ }
+ }
+ setScopeRow={false}
+ textOnly={false}
+ >
+
+
+
+ Traces of all requests that share a common API and operation at the start of distributed tracing instrumentation.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Trace group name
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ client_create_order
+
+
+
+
+
+
+
+ Range of latencies for traces within a trace group in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+ Latency variance (ms)
+
+
+
+
+
+ 0 100 200 300 400
+
+ ,
+ "render": undefined,
+ }
+ }
+ setScopeRow={false}
+ textOnly={false}
+ width="300px"
+ >
+
+
+
+ Range of latencies for traces within a trace group in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Latency variance (ms)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0 100 200 300 400
+
+
+
+
+
+
+
+
+
+
+
+ Latency <95 percentile
+
+
+
+
+
+
+ 26ms - 325ms
+
+
+
+
+
+
+ Latency >=95 percentile
+
+
+
+
+
+
+ 325ms - 325ms
+
+
+
+
+ }
+ delay="regular"
+ onMouseOut={[Function]}
+ position="bottom"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Average latency of traces within a trace group in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Average latency (ms)
+
+
+
+
+
+
+
+ ,
+ "render": undefined,
+ }
+ }
+ setScopeRow={false}
+ textOnly={false}
+ >
+
+
+
+ Average latency of traces within a trace group in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Average latency (ms)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 187.27
+
+
+
+
+ 24 hour time series view of hourly average, hourly percentile, and hourly range of latency for traces within a trace group.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ 24-hour latency trend
+
+
+
+
+
+
+
+ ,
+ "render": undefined,
+ }
+ }
+ setScopeRow={false}
+ textOnly={false}
+ >
+
+
+
+ 24 hour time series view of hourly average, hourly percentile, and hourly range of latency for traces within a trace group.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ 24-hour latency trend
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+ Error rate based on count of trace errors within a trace group in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Error rate
+
+
+
+
+
+
+
+ ,
+ "render": undefined,
+ }
+ }
+ setScopeRow={false}
+ textOnly={false}
+ >
+
+
+
+ Error rate based on count of trace errors within a trace group in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Error rate
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Count of traces with unique trace identifiers in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Traces
+
+
+
+
+
+
+
+ ,
+ "render": undefined,
+ }
+ }
+ setScopeRow={false}
+ textOnly={false}
+ >
+
+
+
+ Count of traces with unique trace identifiers in the selected time range.
+
+ }
+ delay="regular"
+ position="top"
+ >
+
+
+ Traces
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ :
+ 10
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Rows per page
+
+ :
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Dashboard table component renders empty dashboard table message 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+ Latency by trace group
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ □
+
+ < 95 percentile
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ■
+
+ >= 95 percentile
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+ }
+ title={
+
+ No matches
+
+ }
+ >
+
+
+
+
+
+ No matches
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/latency_trend_cell.test.tsx.snap b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/latency_trend_cell.test.tsx.snap
new file mode 100644
index 0000000000..4cd62867a0
--- /dev/null
+++ b/public/components/trace_analytics/components/dashboard/__tests__/__snapshots__/latency_trend_cell.test.tsx.snap
@@ -0,0 +1,185 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Latency trend cell component renders latency trend cell 1`] = `
+Average latency: %{y} ",
+ "line": Object {
+ "color": "#987dcb",
+ "size": 2,
+ },
+ "marker": Object {
+ "color": "#987dcb",
+ "size": 8,
+ },
+ "mode": "lines+markers",
+ "type": "scatter",
+ "x": Array [
+ 1605027600000,
+ ],
+ "y": Array [
+ 154.71,
+ ],
+ },
+ ],
+ "trendData": Array [
+ Object {
+ "hoverinfo": "none",
+ "line": Object {
+ "color": "#000000",
+ "width": 1,
+ },
+ "mode": "lines",
+ "type": "scatter",
+ "x": Array [
+ 1605027600000,
+ ],
+ "y": Array [
+ 154.71,
+ ],
+ },
+ ],
+ }
+ }
+ traceGroupName="order"
+>
+
+
+
+
+
+
+
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/trace_analytics/components/dashboard/__tests__/dashboard.test.tsx b/public/components/trace_analytics/components/dashboard/__tests__/dashboard.test.tsx
new file mode 100644
index 0000000000..0f5c169188
--- /dev/null
+++ b/public/components/trace_analytics/components/dashboard/__tests__/dashboard.test.tsx
@@ -0,0 +1,104 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { Dashboard } from '..';
+import { CoreStart } from '../../../../../../../../src/core/public';
+import { coreStartMock } from '../../../../../../test/__mocks__/coreMocks';
+
+describe('Dashboard component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders empty dashboard', () => {
+ const core = coreStartMock;
+ const setQuery = jest.fn();
+ const setFilters = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const wrapper = mount(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it('renders dashboard', () => {
+ const core = coreStartMock;
+ const setQuery = jest.fn();
+ const setFilters = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const wrapper = mount(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+
+ wrapper.find('button[data-test-subj="dashboard-table-percentile-button-1"]').simulate('click');
+ wrapper.find('button[data-test-subj="dashboard-table-percentile-button-2"]').simulate('click');
+ });
+});
diff --git a/public/components/trace_analytics/components/dashboard/__tests__/dashboard_table.test.tsx b/public/components/trace_analytics/components/dashboard/__tests__/dashboard_table.test.tsx
new file mode 100644
index 0000000000..58c569d45f
--- /dev/null
+++ b/public/components/trace_analytics/components/dashboard/__tests__/dashboard_table.test.tsx
@@ -0,0 +1,79 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { DashboardTable } from '../dashboard_table';
+
+describe('Dashboard table component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders empty dashboard table message', () => {
+ const addFilter = jest.fn();
+ const addPercentileFilter = jest.fn();
+ const setRedirect = jest.fn();
+ const wrapper = mount(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it('renders dashboard table', () => {
+ const tableItems = [
+ {
+ dashboard_trace_group_name: 'client_create_order',
+ dashboard_average_latency: 187.27,
+ dashboard_traces: 7,
+ dashboard_latency_variance: [26.43, 325.4, 325.4],
+ dashboard_error_rate: 14.285714285714285,
+ '24_hour_latency_trend': null,
+ },
+ ];
+ const addFilter = jest.fn();
+ const addPercentileFilter = jest.fn();
+ const setRedirect = jest.fn();
+ const wrapper = mount(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+
+ wrapper.find('button[data-test-subj="dashboard-table-percentile-button-1"]').simulate('click');
+ wrapper.find('button[data-test-subj="dashboard-table-percentile-button-2"]').simulate('click');
+ expect(addPercentileFilter).toBeCalledTimes(2);
+ wrapper
+ .find('button[data-test-subj="dashboard-table-trace-group-name-button"]')
+ .simulate('click');
+ expect(addFilter).toBeCalled();
+ wrapper.find('button[data-test-subj="dashboard-table-traces-button"]').simulate('click');
+ expect(setRedirect).toBeCalledWith(true);
+ });
+});
diff --git a/public/components/trace_analytics/components/dashboard/__tests__/latency_trend_cell.test.tsx b/public/components/trace_analytics/components/dashboard/__tests__/latency_trend_cell.test.tsx
new file mode 100644
index 0000000000..6b924d9317
--- /dev/null
+++ b/public/components/trace_analytics/components/dashboard/__tests__/latency_trend_cell.test.tsx
@@ -0,0 +1,24 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { LatencyTrendCell } from '../latency_trend_cell';
+
+describe('Latency trend cell component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders latency trend cell', () => {
+ const item = JSON.parse(
+ `{"trendData":[{"x":[1605027600000],"y":[154.71],"type":"scatter","mode":"lines","hoverinfo":"none","line":{"color":"#000000","width":1}}],"popoverData":[{"x":[1605027600000],"y":[154.71],"type":"scatter","mode":"lines+markers","hovertemplate":"%{x} Average latency: %{y} ","hoverlabel":{"bgcolor":"#d7c2ff"},"marker":{"color":"#987dcb","size":8},"line":{"color":"#987dcb","size":2}}]}`
+ );
+ const wrapper = mount( );
+ expect(wrapper).toMatchSnapshot();
+
+ wrapper.find('button[aria-label="Open popover"]').simulate('click');
+ wrapper.find('button[aria-label="Close popover"]').simulate('click');
+ });
+});
diff --git a/public/components/trace_analytics/components/dashboard/dashboard.tsx b/public/components/trace_analytics/components/dashboard/dashboard.tsx
new file mode 100644
index 0000000000..c5bf0a501f
--- /dev/null
+++ b/public/components/trace_analytics/components/dashboard/dashboard.tsx
@@ -0,0 +1,25 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { EuiBreadcrumb, EuiTitle } from '@elastic/eui';
+import React from 'react';
+import { TraceAnalyticsComponentDeps } from '../../home';
+import { DashboardContent } from './dashboard_content';
+
+export interface DashboardProps extends TraceAnalyticsComponentDeps {
+ childBreadcrumbs: EuiBreadcrumb[];
+ page: 'dashboard' | 'app';
+}
+
+export function Dashboard(props: DashboardProps) {
+ return (
+ <>
+
+ Dashboard
+
+
+ >
+ );
+}
diff --git a/public/components/trace_analytics/components/dashboard/dashboard_content.tsx b/public/components/trace_analytics/components/dashboard/dashboard_content.tsx
new file mode 100644
index 0000000000..64182d1209
--- /dev/null
+++ b/public/components/trace_analytics/components/dashboard/dashboard_content.tsx
@@ -0,0 +1,250 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable react-hooks/exhaustive-deps */
+
+import dateMath from '@elastic/datemath';
+import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
+import _ from 'lodash';
+import React, { useEffect, useState } from 'react';
+import {
+ handleDashboardErrorRatePltRequest,
+ handleDashboardRequest,
+ handleDashboardThroughputPltRequest,
+} from '../../requests/dashboard_request_handler';
+import { handleServiceMapRequest } from '../../requests/services_request_handler';
+import { FilterType } from '../common/filters/filters';
+import { getValidFilterFields } from '../common/filters/filter_helpers';
+import {
+ filtersToDsl,
+ getPercentileFilter,
+ milliToNanoSec,
+ minFixedInterval,
+ MissingConfigurationMessage,
+} from '../common/helper_functions';
+import { ErrorRatePlt } from '../common/plots/error_rate_plt';
+import { ServiceMap, ServiceObject } from '../common/plots/service_map';
+import { ThroughputPlt } from '../common/plots/throughput_plt';
+import { SearchBar } from '../common/search_bar';
+import { DashboardProps } from './dashboard';
+import { DashboardTable } from './dashboard_table';
+
+export function DashboardContent(props: DashboardProps) {
+ const {
+ http,
+ chrome,
+ page,
+ query,
+ appConfigs,
+ startTime,
+ endTime,
+ childBreadcrumbs,
+ parentBreadcrumbs,
+ filters,
+ indicesExist,
+ setStartTime,
+ setEndTime,
+ setQuery,
+ setFilters,
+ } = props;
+ const [tableItems, setTableItems] = useState([]);
+ const [throughputPltItems, setThroughputPltItems] = useState({ items: [], fixedInterval: '1h' });
+ const [errorRatePltItems, setErrorRatePltItems] = useState({ items: [], fixedInterval: '1h' });
+ const [serviceMap, setServiceMap] = useState({});
+ const [serviceMapIdSelected, setServiceMapIdSelected] = useState<
+ 'latency' | 'error_rate' | 'throughput'
+ >('latency');
+ const [percentileMap, setPercentileMap] = useState<{ [traceGroup: string]: number[] }>({});
+ const [filteredService, setFilteredService] = useState('');
+ const [redirect, setRedirect] = useState(true);
+ const [loading, setLoading] = useState(false);
+
+ useEffect(() => {
+ chrome.setBreadcrumbs([...parentBreadcrumbs, ...childBreadcrumbs]);
+ const validFilters = getValidFilterFields(page);
+ setFilters([
+ ...filters.map((filter) => ({
+ ...filter,
+ locked: validFilters.indexOf(filter.field) === -1,
+ })),
+ ]);
+ setRedirect(false);
+ }, []);
+
+ useEffect(() => {
+ let newFilteredService = '';
+ for (const filter of filters) {
+ if (filter.field === 'serviceName') {
+ newFilteredService = filter.value;
+ break;
+ }
+ }
+ setFilteredService(newFilteredService);
+ if (!redirect && indicesExist) refresh(newFilteredService);
+ }, [filters, startTime, endTime, appConfigs]);
+
+ const refresh = async (currService?: string) => {
+ setLoading(true);
+ const DSL = filtersToDsl(filters, query, startTime, endTime, page, appConfigs);
+ const timeFilterDSL = filtersToDsl([], '', startTime, endTime, page, appConfigs);
+ const latencyTrendStartTime = dateMath.parse(endTime)?.subtract(24, 'hours').toISOString()!;
+ const latencyTrendDSL = filtersToDsl(
+ filters,
+ query,
+ latencyTrendStartTime,
+ endTime,
+ page,
+ appConfigs
+ );
+ const fixedInterval = minFixedInterval(startTime, endTime);
+
+ handleDashboardRequest(
+ http,
+ DSL,
+ timeFilterDSL,
+ latencyTrendDSL,
+ tableItems,
+ setTableItems,
+ setPercentileMap
+ ).then(() => setLoading(false));
+ handleDashboardThroughputPltRequest(
+ http,
+ DSL,
+ fixedInterval,
+ throughputPltItems,
+ setThroughputPltItems
+ );
+ handleDashboardErrorRatePltRequest(
+ http,
+ DSL,
+ fixedInterval,
+ errorRatePltItems,
+ setErrorRatePltItems
+ );
+ // service map should not be filtered by service name (https://github.com/opensearch-project/observability/issues/442)
+ const serviceMapDSL = _.cloneDeep(DSL);
+ serviceMapDSL.query.bool.must = serviceMapDSL.query.bool.must.filter(
+ (must: any) => must?.term?.serviceName == null
+ );
+ handleServiceMapRequest(http, serviceMapDSL, setServiceMap, currService || filteredService);
+ };
+
+ const addFilter = (filter: FilterType) => {
+ for (let i = 0; i < filters.length; i++) {
+ const addedFilter = filters[i];
+ if (addedFilter.field === filter.field) {
+ if (addedFilter.operator === filter.operator && addedFilter.value === filter.value) return;
+ const newFilters = [...filters];
+ newFilters.splice(i, 1, filter);
+ setFilters(newFilters);
+ return;
+ }
+ }
+ const newFilters = [...filters, filter];
+ setFilters(newFilters);
+ };
+
+ const addPercentileFilter = (condition = 'gte', additionalFilters = [] as FilterType[]) => {
+ if (tableItems.length === 0 || Object.keys(percentileMap).length === 0) return;
+ for (let i = 0; i < filters.length; i++) {
+ if (filters[i].custom) {
+ const newFilter = JSON.parse(JSON.stringify(filters[i]));
+ newFilter.custom.query.bool.should.forEach((should: any) =>
+ should.bool.must.forEach((must: any) => {
+ const range = must?.range?.['traceGroupFields.durationInNanos'];
+ if (range) {
+ const duration = range.lt || range.lte || range.gt || range.gte;
+ if (duration || duration === 0) {
+ must.range['traceGroupFields.durationInNanos'] = {
+ [condition]: duration,
+ };
+ }
+ }
+ })
+ );
+ newFilter.value = condition === 'gte' ? '>= 95th' : '< 95th';
+ const newFilters = [...filters, ...additionalFilters];
+ newFilters.splice(i, 1, newFilter);
+ setFilters(newFilters);
+ return;
+ }
+ }
+
+ const percentileMaps = Object.keys(percentileMap).map((traceGroup) => ({
+ traceGroupName: traceGroup,
+ durationFilter: { [condition]: milliToNanoSec(percentileMap[traceGroup][1]) },
+ }));
+ const percentileFilter = getPercentileFilter(
+ percentileMaps,
+ condition === 'gte' ? '>= 95th' : '< 95th'
+ );
+ const newFilters = [...filters, percentileFilter, ...additionalFilters];
+ setFilters(newFilters);
+ };
+
+ return (
+ <>
+
+
+ {indicesExist ? (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ ) : (
+
+ )}
+ >
+ );
+}
diff --git a/public/components/trace_analytics/components/dashboard/dashboard_table.tsx b/public/components/trace_analytics/components/dashboard/dashboard_table.tsx
new file mode 100644
index 0000000000..cba1740883
--- /dev/null
+++ b/public/components/trace_analytics/components/dashboard/dashboard_table.tsx
@@ -0,0 +1,422 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiHorizontalRule,
+ EuiI18nNumber,
+ EuiIcon,
+ EuiInMemoryTable,
+ EuiLink,
+ EuiPanel,
+ EuiSpacer,
+ EuiTableFieldDataColumnType,
+ EuiText,
+ EuiToolTip,
+ PropertySort,
+} from '@elastic/eui';
+import { CriteriaWithPagination } from '@elastic/eui/src/components/basic_table/basic_table';
+import _ from 'lodash';
+import React, { useMemo, useState } from 'react';
+import { FilterType } from '../common/filters/filters';
+import { calculateTicks, NoMatchMessage, PanelTitle } from '../common/helper_functions';
+import { BoxPlt } from '../common/plots/box_plt';
+import { LatencyTrendCell } from './latency_trend_cell';
+
+export function DashboardTable(props: {
+ items: any[];
+ filters: FilterType[];
+ addFilter: (filter: FilterType) => void;
+ addPercentileFilter: (condition?: 'gte' | 'lte', additionalFilters?: FilterType[]) => void;
+ setRedirect: (redirect: boolean) => void;
+ loading: boolean;
+ page: 'dashboard' | 'traces' | 'services' | 'app';
+}) {
+ const getVarianceProps = (items: any[]) => {
+ if (items.length === 0) {
+ return { minRange: 0, maxRange: 0, ticks: [0, 0], scale: '' };
+ }
+ const variances = [].concat(
+ ...items
+ .filter((item) => item.dashboard_latency_variance)
+ .map((item) => item.dashboard_latency_variance)
+ );
+ const minRange = Math.min(...variances);
+ const maxRange = Math.max(...variances);
+ const ticks = calculateTicks(minRange, maxRange);
+
+ const maxDigits = ticks[ticks.length - 1].toString().length;
+
+ // pads spaces (\u00A0) in between ticks to construct a scale
+ // width of a character equals the width of two spaces, maximum 39 characters in a scale
+ const scale = ticks
+ .map((tick) => {
+ const tickStr = tick.toString();
+ return tickStr.padEnd(tickStr.length + 2 * (maxDigits - tickStr.length), '\u00A0');
+ })
+ .join(
+ '\u00A0'.repeat(
+ Math.max(
+ 1,
+ Math.floor((2 * (39 - ticks.length * maxDigits)) / Math.max(1, ticks.length - 1))
+ )
+ )
+ );
+
+ return { minRange, maxRange, ticks, scale };
+ };
+
+ const getColumns = () =>
+ [
+ {
+ field: 'dashboard_trace_group_name',
+ name: (
+
+ Traces of all requests that share a common API and operation at the start of
+ distributed tracing instrumentation.
+
+ }
+ >
+ <>
+
+ Trace group name{' '}
+
+
+
+ >
+
+ ),
+ align: 'left',
+ sortable: true,
+ render: (item) =>
+ item ? (
+
+ props.addFilter({
+ field: 'traceGroup',
+ operator: 'is',
+ value: item,
+ inverted: false,
+ disabled: false,
+ })
+ }
+ >
+ {item.length < 48 ? (
+ decodeURI(item)
+ ) : (
+ {_.truncate(decodeURI(item), { length: 48 })}
+ )}
+
+ ) : (
+ '-'
+ ),
+ },
+ {
+ field: 'dashboard_latency_variance',
+ name: (
+ <>
+
+ Range of latencies for traces within a trace group in the selected time range.
+
+ }
+ >
+
+ Latency variance (ms){' '}
+
+
+
+ {varianceProps && (
+
+ {varianceProps.scale}
+
+ )}
+ >
+ ),
+ align: 'center',
+ sortable: ({ dashboard_latency_variance }) =>
+ dashboard_latency_variance?.length > 0
+ ? dashboard_latency_variance[2] - dashboard_latency_variance[0]
+ : 0,
+ width: '300px',
+ render: (item, row) => {
+ const filter = props.filters.find(
+ (f) => f.field === 'Latency percentile within trace group'
+ );
+ const currPercentileFilter = filter ? filter.value : '';
+ return item ? (
+ // expand plot ranges to accommodate scale
+ 1
+ ? varianceProps.ticks[0]
+ : varianceProps.ticks[0] / 1.03,
+ max: varianceProps.ticks[varianceProps.ticks.length - 1] * 1.03,
+ left: item[0],
+ mid: item[1],
+ right: item[2],
+ currPercentileFilter,
+ addFilter: (condition?: 'lte' | 'gte') => {
+ const traceGroupFilter = {
+ field: 'traceGroup',
+ operator: 'is',
+ value: row.dashboard_trace_group_name,
+ inverted: false,
+ disabled: false,
+ };
+ const additionalFilters = [traceGroupFilter];
+ for (const addedFilter of props.filters) {
+ if (
+ addedFilter.field === traceGroupFilter.field &&
+ addedFilter.operator === traceGroupFilter.operator &&
+ addedFilter.value === traceGroupFilter.value
+ ) {
+ additionalFilters.pop();
+ }
+ }
+ props.addPercentileFilter(condition, additionalFilters);
+ },
+ }}
+ />
+ ) : (
+ '-'
+ );
+ },
+ },
+ {
+ field: 'dashboard_average_latency',
+ name: (
+
+ Average latency of traces within a trace group in the selected time range.
+
+ }
+ >
+ <>
+ {/* Average
*/}
+
+ Average latency (ms){' '}
+
+
+
+ >
+
+ ),
+ align: 'right',
+ sortable: true,
+ dataType: 'number',
+ render: (item) => (item === 0 || item ? _.round(item, 2) : '-'),
+ },
+ {
+ field: '24_hour_latency_trend',
+ name: (
+
+ 24 hour time series view of hourly average, hourly percentile, and hourly range of
+ latency for traces within a trace group.
+
+ }
+ >
+ <>
+ {/* 24-hour
*/}
+
+ 24-hour latency trend{' '}
+
+
+
+ >
+
+ ),
+ align: 'right',
+ sortable: false,
+ render: (item, row) =>
+ item ? (
+
+ ) : (
+ '-'
+ ),
+ },
+ {
+ field: 'dashboard_error_rate',
+ name: (
+
+ Error rate based on count of trace errors within a trace group in the selected time
+ range.
+
+ }
+ >
+ <>
+
+ Error rate{' '}
+
+
+
+ >
+
+ ),
+ align: 'right',
+ sortable: true,
+ render: (item) =>
+ item === 0 || item ? {`${_.round(item, 2)}%`} : '-',
+ },
+ {
+ field: 'dashboard_traces',
+ name: (
+
+ Count of traces with unique trace identifiers in the selected time range.
+
+ }
+ >
+ <>
+
+ Traces{' '}
+
+
+
+ >
+
+ ),
+ align: 'right',
+ sortable: true,
+ render: (item, row) => (
+ {
+ props.addFilter({
+ field: 'traceGroup',
+ operator: 'is',
+ value: row.dashboard_trace_group_name,
+ inverted: false,
+ disabled: false,
+ });
+ if (props.page !== 'app') {
+ props.setRedirect(true);
+ location.assign('#/trace_analytics/traces');
+ }
+ }}
+ >
+
+
+ ),
+ },
+ ] as Array>;
+
+ const renderTitleBar = (totalItems: number) => {
+ return (
+
+
+
+
+
+ props.addPercentileFilter('lte')}
+ >
+
+ □ < 95 percentile
+
+
+
+
+
+ props.addPercentileFilter('gte')}
+ >
+
+ ■ >= 95 percentile
+
+
+
+
+
+ );
+ };
+
+ const varianceProps = useMemo(() => getVarianceProps(props.items), [props.items]);
+ const columns = useMemo(() => getColumns(), [props.items, props.filters]);
+ const titleBar = useMemo(() => renderTitleBar(props.items?.length), [props.items]);
+
+ const [sorting, setSorting] = useState<{ sort: PropertySort }>({
+ sort: {
+ field: 'dashboard_latency_variance',
+ direction: 'desc',
+ },
+ });
+
+ const onTableChange = async ({ page, sort }: CriteriaWithPagination) => {
+ if (typeof sort?.field !== 'string') return;
+ setSorting({ sort } as { sort: PropertySort });
+ };
+
+ return (
+ <>
+
+ {titleBar}
+
+
+ {props.items?.length > 0 ? (
+
+ ) : (
+
+ )}
+
+ >
+ );
+}
diff --git a/public/components/trace_analytics/components/dashboard/index.ts b/public/components/trace_analytics/components/dashboard/index.ts
new file mode 100644
index 0000000000..346331a326
--- /dev/null
+++ b/public/components/trace_analytics/components/dashboard/index.ts
@@ -0,0 +1,6 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { Dashboard } from './dashboard';
diff --git a/public/components/trace_analytics/components/dashboard/latency_trend_cell.tsx b/public/components/trace_analytics/components/dashboard/latency_trend_cell.tsx
new file mode 100644
index 0000000000..2422c4d18d
--- /dev/null
+++ b/public/components/trace_analytics/components/dashboard/latency_trend_cell.tsx
@@ -0,0 +1,62 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiPopover, EuiText } from '@elastic/eui';
+import _ from 'lodash';
+import React, { useState } from 'react';
+import { LatencyPlt, LinePlt } from '../common/plots/latency_trend_plt';
+
+export function LatencyTrendCell({
+ item,
+ traceGroupName,
+}: {
+ item: {
+ popoverData: Plotly.Data[];
+ trendData: Plotly.Data[];
+ };
+ traceGroupName: string;
+}) {
+ const [isPopoverOpen, setIsPopoverOpen] = useState(false);
+ return (
+
+
+
+
+
+
+ setIsPopoverOpen(true)}
+ iconType="magnifyWithPlus"
+ size="s"
+ />
+ }
+ isOpen={isPopoverOpen}
+ closePopover={() => setIsPopoverOpen(false)}
+ >
+
+
+ 24-hour latency trend
+ {traceGroupName}
+
+
+ setIsPopoverOpen(false)}
+ />
+
+
+
+
+
+
+ );
+}
diff --git a/public/components/trace_analytics/components/services/__tests__/__snapshots__/service_view.test.tsx.snap b/public/components/trace_analytics/components/services/__tests__/__snapshots__/service_view.test.tsx.snap
new file mode 100644
index 0000000000..40b856fb8f
--- /dev/null
+++ b/public/components/trace_analytics/components/services/__tests__/__snapshots__/service_view.test.tsx.snap
@@ -0,0 +1,252 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Service view component renders service view 1`] = `
+
+
+
+
+
+
+
+ order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name
+
+
+ order
+
+
+
+
+ Number of connected services
+
+
+ 0
+
+
+
+
+ Connected services
+
+
+ -
+
+
+
+
+
+
+
+
+ Average latency (ms)
+
+
+ -
+
+
+
+
+ Error rate
+
+
+ -
+
+
+
+
+ Throughput
+
+
+ -
+
+
+
+
+ Traces
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/trace_analytics/components/services/__tests__/__snapshots__/services.test.tsx.snap b/public/components/trace_analytics/components/services/__tests__/__snapshots__/services.test.tsx.snap
new file mode 100644
index 0000000000..f52278b5f1
--- /dev/null
+++ b/public/components/trace_analytics/components/services/__tests__/__snapshots__/services.test.tsx.snap
@@ -0,0 +1,3458 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Services component renders empty services page 1`] = `
+
+
+
+ Services
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ >
+
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="QuickSelectPopover"
+ isOpen={false}
+ ownFocus={true}
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
}
+ iconType={false}
+ isCustom={true}
+ startDateControl={
}
+ >
+
+
+ Last 5 minutes
+
+
+ Show dates
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Refresh
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+
+
+
+ + Add filter
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="m"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+ + Add filter
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Services
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Learn more
+
+ }
+ body={
+
+ The indices required for trace analytics (otel-v1-apm-span-* and otel-v1-apm-service-map*) do not exist or you do not have permission to access them.
+
+ }
+ title={
+
+ Trace Analytics not set up
+
+ }
+ >
+
+
+
+
+
+ Trace Analytics not set up
+
+
+
+
+
+
+
+
+
+ The indices required for trace analytics (otel-v1-apm-span-* and otel-v1-apm-service-map*) do not exist or you do not have permission to access them.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Learn more
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Service map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+ }
+ title={
+
+ No matches
+
+ }
+ >
+
+
+
+
+
+ No matches
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Services component renders services page 1`] = `
+
+
+
+ Services
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ >
+
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="QuickSelectPopover"
+ isOpen={false}
+ ownFocus={true}
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
}
+ iconType={false}
+ isCustom={true}
+ startDateControl={
}
+ >
+
+
+ Last 5 minutes
+
+
+ Show dates
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Refresh
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+
+
+
+ + Add filter
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="m"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+ + Add filter
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Services
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+ }
+ title={
+
+ No matches
+
+ }
+ >
+
+
+
+
+
+ No matches
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Service map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+ }
+ title={
+
+ No matches
+
+ }
+ >
+
+
+
+
+
+ No matches
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/trace_analytics/components/services/__tests__/__snapshots__/services_table.test.tsx.snap b/public/components/trace_analytics/components/services/__tests__/__snapshots__/services_table.test.tsx.snap
new file mode 100644
index 0000000000..3fc805b3e4
--- /dev/null
+++ b/public/components/trace_analytics/components/services/__tests__/__snapshots__/services_table.test.tsx.snap
@@ -0,0 +1,1859 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Services table component renders empty services table message 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+ Services
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+ }
+ title={
+
+ No matches
+
+ }
+ >
+
+
+
+
+
+ No matches
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Services table component renders services table 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+ Services
+
+
+ (1)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelPaddingSize="none"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sorting
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Click to sort in descending order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Average latency (ms)
+
+
+
+
+
+
+ Click to sort in ascending order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Error rate
+
+
+
+
+
+
+ Click to sort in ascending order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Throughput
+
+
+
+
+
+
+ Click to sort in ascending order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No. of connected services
+
+
+
+
+
+
+ Click to sort in ascending order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Connected services
+
+
+
+
+
+
+ Click to sort in ascending order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Traces
+
+
+
+
+
+
+ Click to sort in ascending order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name
+
+
+
+
+ database
+
+
+
+
+
+
+
+
+ Average latency (ms)
+
+
+ 49.54
+
+
+
+
+
+
+ Error rate
+
+
+
+
+
+
+
+ Throughput
+
+
+
+ 53
+
+
+
+
+
+
+
+ No. of connected services
+
+
+ 2
+
+
+
+
+
+
+ Connected services
+
+
+
+
+ order, inventory
+
+
+
+
+
+
+
+
+ Traces
+
+
+
+
+
+ 31
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ :
+ 10
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Rows per page
+
+ :
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/trace_analytics/components/services/__tests__/service_view.test.tsx b/public/components/trace_analytics/components/services/__tests__/service_view.test.tsx
new file mode 100644
index 0000000000..b480555482
--- /dev/null
+++ b/public/components/trace_analytics/components/services/__tests__/service_view.test.tsx
@@ -0,0 +1,44 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, shallow } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { ServiceView } from '..';
+import { coreStartMock } from '../../../../../../test/__mocks__/coreMocks';
+
+describe('Service view component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders service view', () => {
+ const core = coreStartMock;
+ const setQuery = jest.fn();
+ const setFilters = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const addFilter = jest.fn();
+ const wrapper = shallow(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+});
diff --git a/public/components/trace_analytics/components/services/__tests__/services.test.tsx b/public/components/trace_analytics/components/services/__tests__/services.test.tsx
new file mode 100644
index 0000000000..fca7a6c44b
--- /dev/null
+++ b/public/components/trace_analytics/components/services/__tests__/services.test.tsx
@@ -0,0 +1,102 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { Services } from '..';
+import { coreStartMock } from '../../../../../../test/__mocks__/coreMocks';
+
+describe('Services component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders empty services page', () => {
+ const core = coreStartMock;
+ const setQuery = jest.fn();
+ const setFilters = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const serviceBreadcrumbs = [
+ {
+ text: 'Trace analytics',
+ href: '#/trace_analytics/home',
+ },
+ {
+ text: 'Services',
+ href: '#/trace_analytics/services',
+ },
+ ];
+ const nameColumnAction = (item: any) =>
+ location.assign(`#/trace_analytics/services/${encodeURIComponent(item)}`);
+ const traceColumnAction = () => location.assign('#/trace_analytics/traces');
+ const wrapper = mount(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it('renders services page', () => {
+ const core = coreStartMock;
+ const setQuery = jest.fn();
+ const setFilters = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const serviceBreadcrumbs = [
+ {
+ text: 'Trace analytics',
+ href: '#/trace_analytics/home',
+ },
+ {
+ text: 'Services',
+ href: '#/trace_analytics/services',
+ },
+ ];
+ const nameColumnAction = (item: any) =>
+ location.assign(`#/trace_analytics/services/${encodeURIComponent(item)}`);
+ const traceColumnAction = () => location.assign('#/trace_analytics/traces');
+ const wrapper = mount(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+});
diff --git a/public/components/trace_analytics/components/services/__tests__/services_table.test.tsx b/public/components/trace_analytics/components/services/__tests__/services_table.test.tsx
new file mode 100644
index 0000000000..a4eb24e3c2
--- /dev/null
+++ b/public/components/trace_analytics/components/services/__tests__/services_table.test.tsx
@@ -0,0 +1,66 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import { ServicesTable } from '../services_table';
+
+describe('Services table component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders empty services table message', () => {
+ const addFilter = jest.fn();
+ const setRedirect = jest.fn();
+ const nameColumnAction = (item: any) =>
+ location.assign(`#/trace_analytics/services/${encodeURIComponent(item)}`);
+ const traceColumnAction = () => location.assign('#/trace_analytics/traces');
+ const wrapper = mount(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it('renders services table', () => {
+ const tableItems = [
+ {
+ name: 'database',
+ average_latency: 49.54,
+ error_rate: 3.77,
+ throughput: 53,
+ traces: 31,
+ connected_services: ['order', 'inventory'],
+ number_of_connected_services: 2,
+ },
+ ];
+ const addFilter = jest.fn();
+ const setRedirect = jest.fn();
+ const nameColumnAction = (item: any) =>
+ location.assign(`#/trace_analytics/services/${encodeURIComponent(item)}`);
+ const traceColumnAction = () => location.assign('#/trace_analytics/traces');
+ const wrapper = mount(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+});
diff --git a/public/components/trace_analytics/components/services/index.ts b/public/components/trace_analytics/components/services/index.ts
new file mode 100644
index 0000000000..d38e5a4a3d
--- /dev/null
+++ b/public/components/trace_analytics/components/services/index.ts
@@ -0,0 +1,8 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { Services } from './services';
+export { ServiceView } from './service_view';
+export { ServiceMap } from '../common/plots/service_map';
diff --git a/public/components/trace_analytics/components/services/service_view.tsx b/public/components/trace_analytics/components/services/service_view.tsx
new file mode 100644
index 0000000000..555446ac27
--- /dev/null
+++ b/public/components/trace_analytics/components/services/service_view.tsx
@@ -0,0 +1,346 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable react-hooks/exhaustive-deps */
+
+import {
+ EuiBadge,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiHorizontalRule,
+ EuiI18nNumber,
+ EuiLink,
+ EuiPage,
+ EuiPageBody,
+ EuiPanel,
+ EuiSpacer,
+ EuiText,
+ EuiTitle,
+} from '@elastic/eui';
+import _ from 'lodash';
+import React, { useEffect, useMemo, useState } from 'react';
+import { TraceAnalyticsComponentDeps } from '../../home';
+import {
+ handleServiceMapRequest,
+ handleServiceViewRequest,
+} from '../../requests/services_request_handler';
+import { FilterType } from '../common/filters/filters';
+import { filtersToDsl, PanelTitle } from '../common/helper_functions';
+import { ServiceMap, ServiceObject } from '../common/plots/service_map';
+import { renderDatePicker, SearchBarProps } from '../common/search_bar';
+import { SpanDetailFlyout } from '../traces/span_detail_flyout';
+import { SpanDetailTable } from '../traces/span_detail_table';
+
+interface ServiceViewProps extends TraceAnalyticsComponentDeps {
+ serviceName: string;
+ addFilter: (filter: FilterType) => void;
+}
+
+export function ServiceView(props: ServiceViewProps) {
+ const [fields, setFields] = useState({});
+ const [serviceMap, setServiceMap] = useState({});
+ const [serviceMapIdSelected, setServiceMapIdSelected] = useState<
+ 'latency' | 'error_rate' | 'throughput'
+ >('latency');
+ const [redirect, setRedirect] = useState(false);
+
+ const refresh = () => {
+ const DSL = filtersToDsl(props.filters, props.query, props.startTime, props.endTime);
+ handleServiceViewRequest(props.serviceName, props.http, DSL, setFields);
+ handleServiceMapRequest(props.http, DSL, setServiceMap, props.serviceName);
+ };
+
+ useEffect(() => {
+ props.chrome.setBreadcrumbs([
+ ...props.parentBreadcrumbs,
+ {
+ text: 'Trace analytics',
+ href: '#/trace_analytics/home',
+ },
+ {
+ text: 'Services',
+ href: '#/trace_analytics/services',
+ },
+ {
+ text: props.serviceName,
+ href: `#/trace_analytics/services/${encodeURIComponent(props.serviceName)}`,
+ },
+ ]);
+ }, [props.serviceName]);
+
+ useEffect(() => {
+ if (!redirect) refresh();
+ }, [props.startTime, props.endTime, props.serviceName]);
+
+ const renderTitle = (
+ serviceName: string,
+ startTime: SearchBarProps['startTime'],
+ setStartTime: SearchBarProps['setStartTime'],
+ endTime: SearchBarProps['endTime'],
+ setEndTime: SearchBarProps['setEndTime'],
+ addFilter: (filter: FilterType) => void
+ ) => {
+ return (
+ <>
+
+
+ {serviceName}
+
+
+
+ {renderDatePicker(startTime, setStartTime, endTime, setEndTime)}
+
+
+ >
+ );
+ };
+
+ const renderOverview = () => {
+ return (
+
+
+
+
+
+
+
+ Name
+
+ {props.serviceName || '-'}
+
+
+
+ Number of connected services
+
+ {fields.number_of_connected_services !== undefined
+ ? fields.number_of_connected_services
+ : 0}
+
+
+
+ Connected services
+
+ {fields.connected_services
+ ? fields.connected_services
+ .map((service: string) => (
+
+ {service}
+
+ ))
+ .reduce((prev: React.ReactNode, curr: React.ReactNode) => {
+ return [prev, ', ', curr];
+ })
+ : '-'}
+
+
+
+
+
+
+
+ Average latency (ms)
+
+ {fields.average_latency !== undefined ? fields.average_latency : '-'}
+
+
+
+ Error rate
+
+ {fields.error_rate !== undefined
+ ? _.round(fields.error_rate, 2).toString() + '%'
+ : '-'}
+
+
+
+ Throughput
+
+ {fields.throughput !== undefined ? (
+
+ ) : (
+ '-'
+ )}
+
+
+
+ Traces
+
+ {fields.traces === 0 || fields.traces ? (
+ {
+ setRedirect(true);
+ props.addFilter({
+ field: 'serviceName',
+ operator: 'is',
+ value: props.serviceName,
+ inverted: false,
+ disabled: false,
+ });
+ location.assign('#/trace_analytics/traces');
+ }}
+ >
+
+
+ ) : (
+ '-'
+ )}
+
+
+
+
+
+
+
+ );
+ };
+
+ const overview = useMemo(() => renderOverview(), [fields, props.serviceName]);
+
+ const title = useMemo(
+ () =>
+ renderTitle(
+ props.serviceName,
+ props.startTime,
+ props.setStartTime,
+ props.endTime,
+ props.setEndTime,
+ props.addFilter
+ ),
+ [props.serviceName, props.startTime, props.endTime]
+ );
+
+ const activeFilters = useMemo(
+ () => props.filters.filter((filter) => !filter.locked && !filter.disabled),
+ [props.filters]
+ );
+
+ const [currentSpan, setCurrentSpan] = useState('');
+ const storedFilters = sessionStorage.getItem('TraceAnalyticsSpanFilters');
+ const [spanFilters, setSpanFilters] = useState>(
+ storedFilters ? JSON.parse(storedFilters) : []
+ );
+ const [DSL, setDSL] = useState({});
+
+ const setSpanFiltersWithStorage = (newFilters: Array<{ field: string; value: any }>) => {
+ setSpanFilters(newFilters);
+ sessionStorage.setItem('TraceAnalyticsSpanFilters', JSON.stringify(newFilters));
+ };
+
+ useEffect(() => {
+ const spanDSL = filtersToDsl(props.filters, props.query, props.startTime, props.endTime);
+ spanDSL.query.bool.must.push({
+ term: {
+ serviceName: props.serviceName,
+ },
+ });
+ spanFilters.map(({ field, value }) => {
+ if (value != null) {
+ spanDSL.query.bool.must.push({
+ term: {
+ [field]: value,
+ },
+ });
+ }
+ });
+ setDSL(spanDSL);
+ }, [props.startTime, props.endTime, props.serviceName, spanFilters]);
+
+ const addSpanFilter = (field: string, value: any) => {
+ const newFilters = [...spanFilters];
+ const index = newFilters.findIndex(({ field: filterField }) => field === filterField);
+ if (index === -1) {
+ newFilters.push({ field, value });
+ } else {
+ newFilters.splice(index, 1, { field, value });
+ }
+ setSpanFiltersWithStorage(newFilters);
+ };
+
+ const removeSpanFilter = (field: string) => {
+ const newFilters = [...spanFilters];
+ const index = newFilters.findIndex(({ field: filterField }) => field === filterField);
+ if (index !== -1) {
+ newFilters.splice(index, 1);
+ setSpanFiltersWithStorage(newFilters);
+ }
+ };
+
+ const renderFilters = useMemo(() => {
+ return spanFilters.map(({ field, value }) => (
+
+ removeSpanFilter(field)}
+ iconOnClickAriaLabel="remove current filter"
+ >
+ {`${field}: ${value}`}
+
+
+ ));
+ }, [spanFilters]);
+
+ const [total, setTotal] = useState(0);
+ const spanDetailTable = useMemo(
+ () => (
+ setCurrentSpan(spanId)}
+ setTotal={setTotal}
+ />
+ ),
+ [DSL, setCurrentSpan]
+ );
+
+ return (
+ <>
+
+
+
+ {title}
+
+ {activeFilters.length > 0 && (
+
+ results are filtered by {activeFilters.map((filter) => filter.field).join(', ')}
+
+ )}
+
+ {overview}
+
+
+
+
+
+ {spanFilters.length > 0 && (
+ <>
+
+
+ {renderFilters}
+
+ >
+ )}
+
+ {spanDetailTable}
+
+ {!!currentSpan && (
+ setCurrentSpan('')}
+ addSpanFilter={addSpanFilter}
+ />
+ )}
+
+
+ >
+ );
+}
diff --git a/public/components/trace_analytics/components/services/services.tsx b/public/components/trace_analytics/components/services/services.tsx
new file mode 100644
index 0000000000..04c6bad2f9
--- /dev/null
+++ b/public/components/trace_analytics/components/services/services.tsx
@@ -0,0 +1,28 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { EuiBreadcrumb, EuiTitle } from '@elastic/eui';
+import _ from 'lodash';
+import React from 'react';
+import { TraceAnalyticsComponentDeps } from '../../home';
+import { ServicesContent } from './services_content';
+
+export interface ServicesProps extends TraceAnalyticsComponentDeps {
+ childBreadcrumbs: EuiBreadcrumb[];
+ nameColumnAction: any;
+ traceColumnAction: any;
+ page: 'services' | 'app';
+}
+
+export function Services(props: ServicesProps) {
+ return (
+ <>
+
+ Services
+
+
+ >
+ );
+}
diff --git a/public/components/trace_analytics/components/services/services_content.tsx b/public/components/trace_analytics/components/services/services_content.tsx
new file mode 100644
index 0000000000..e4fa97e25d
--- /dev/null
+++ b/public/components/trace_analytics/components/services/services_content.tsx
@@ -0,0 +1,141 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable react-hooks/exhaustive-deps */
+
+import { EuiSpacer } from '@elastic/eui';
+import _ from 'lodash';
+import React, { useEffect, useState } from 'react';
+import {
+ handleServiceMapRequest,
+ handleServicesRequest,
+} from '../../requests/services_request_handler';
+import { FilterType } from '../common/filters/filters';
+import { getValidFilterFields } from '../common/filters/filter_helpers';
+import { filtersToDsl } from '../common/helper_functions';
+import { ServiceMap, ServiceObject } from '../common/plots/service_map';
+import { SearchBar } from '../common/search_bar';
+import { ServicesProps } from './services';
+import { ServicesTable } from './services_table';
+
+export function ServicesContent(props: ServicesProps) {
+ const {
+ page,
+ http,
+ chrome,
+ filters,
+ query,
+ startTime,
+ endTime,
+ indicesExist,
+ appConfigs = [],
+ childBreadcrumbs,
+ parentBreadcrumbs,
+ nameColumnAction,
+ traceColumnAction,
+ setFilters,
+ setQuery,
+ setStartTime,
+ setEndTime,
+ } = props;
+ const [tableItems, setTableItems] = useState([]);
+ const [serviceMap, setServiceMap] = useState({});
+ const [serviceMapIdSelected, setServiceMapIdSelected] = useState<
+ 'latency' | 'error_rate' | 'throughput'
+ >('latency');
+ const [redirect, setRedirect] = useState(true);
+ const [loading, setLoading] = useState(false);
+ const [filteredService, setFilteredService] = useState('');
+
+ useEffect(() => {
+ chrome.setBreadcrumbs([...parentBreadcrumbs, ...childBreadcrumbs]);
+ const validFilters = getValidFilterFields('services');
+ setFilters([
+ ...filters.map((filter) => ({
+ ...filter,
+ locked: validFilters.indexOf(filter.field) === -1,
+ })),
+ ]);
+ setRedirect(false);
+ }, []);
+
+ useEffect(() => {
+ let newFilteredService = '';
+ for (const filter of filters) {
+ if (filter.field === 'serviceName') {
+ newFilteredService = filter.value;
+ break;
+ }
+ }
+ setFilteredService(newFilteredService);
+ if (!redirect && indicesExist) refresh(newFilteredService);
+ }, [filters, appConfigs]);
+
+ const refresh = async (currService?: string) => {
+ setLoading(true);
+ const DSL = filtersToDsl(filters, query, startTime, endTime, page, appConfigs);
+ // service map should not be filtered by service name
+ const serviceMapDSL = _.cloneDeep(DSL);
+ serviceMapDSL.query.bool.must = serviceMapDSL.query.bool.must.filter(
+ (must: any) => must?.term?.serviceName == null
+ );
+ await Promise.all([
+ handleServicesRequest(http, DSL, setTableItems),
+ handleServiceMapRequest(http, serviceMapDSL, setServiceMap, currService || filteredService),
+ ]);
+ setLoading(false);
+ };
+
+ const addFilter = (filter: FilterType) => {
+ for (let i = 0; i < filters.length; i++) {
+ const addedFilter = filters[i];
+ if (addedFilter.field === filter.field) {
+ if (addedFilter.operator === filter.operator && addedFilter.value === filter.value) return;
+ const newFilters = [...filters];
+ newFilters.splice(i, 1, filter);
+ setFilters(newFilters);
+ return;
+ }
+ }
+ const newFilters = [...filters, filter];
+ setFilters(newFilters);
+ };
+
+ return (
+ <>
+
+
+
+
+
+ >
+ );
+}
diff --git a/public/components/trace_analytics/components/services/services_table.tsx b/public/components/trace_analytics/components/services/services_table.tsx
new file mode 100644
index 0000000000..d294f13ef4
--- /dev/null
+++ b/public/components/trace_analytics/components/services/services_table.tsx
@@ -0,0 +1,180 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable react-hooks/exhaustive-deps */
+
+import {
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiHorizontalRule,
+ EuiI18nNumber,
+ EuiInMemoryTable,
+ EuiLink,
+ EuiPanel,
+ EuiSpacer,
+ EuiTableFieldDataColumnType,
+ EuiText,
+} from '@elastic/eui';
+import _ from 'lodash';
+import React, { useMemo } from 'react';
+import { FilterType } from '../common/filters/filters';
+import {
+ MissingConfigurationMessage,
+ NoMatchMessage,
+ PanelTitle,
+} from '../common/helper_functions';
+
+interface ServicesTableProps {
+ items: any[];
+ indicesExist: boolean;
+ loading: boolean;
+ nameColumnAction: (item: any) => any;
+ traceColumnAction: any;
+ addFilter: (filter: FilterType) => void;
+ setRedirect: (redirect: boolean) => void;
+}
+
+export function ServicesTable(props: ServicesTableProps) {
+ const {
+ items,
+ indicesExist,
+ loading,
+ nameColumnAction,
+ traceColumnAction,
+ addFilter,
+ setRedirect,
+ } = props;
+ const renderTitleBar = (totalItems?: number) => {
+ return (
+
+
+
+
+
+ );
+ };
+
+ const columns = useMemo(
+ () =>
+ [
+ {
+ field: 'name',
+ name: 'Name',
+ align: 'left',
+ sortable: true,
+ render: (item: any) => (
+ nameColumnAction(item)}>
+ {item.length < 24 ? item : {_.truncate(item, { length: 24 })}
}
+
+ ),
+ },
+ {
+ field: 'average_latency',
+ name: 'Average latency (ms)',
+ align: 'right',
+ sortable: true,
+ render: (item: any) => (item === 0 || item ? _.round(item, 2) : '-'),
+ },
+ {
+ field: 'error_rate',
+ name: 'Error rate',
+ align: 'right',
+ sortable: true,
+ render: (item) =>
+ item === 0 || item ? {`${_.round(item, 2)}%`} : '-',
+ },
+ {
+ field: 'throughput',
+ name: 'Throughput',
+ align: 'right',
+ sortable: true,
+ truncateText: true,
+ render: (item: any) => (item === 0 || item ? : '-'),
+ },
+ {
+ field: 'number_of_connected_services',
+ name: 'No. of connected services',
+ align: 'right',
+ sortable: true,
+ truncateText: true,
+ width: '80px',
+ render: (item: any) => (item === 0 || item ? item : '-'),
+ },
+ {
+ field: 'connected_services',
+ name: 'Connected services',
+ align: 'left',
+ sortable: true,
+ truncateText: true,
+ render: (item: any) =>
+ item ? {_.truncate(item.join(', '), { length: 50 })} : '-',
+ },
+ {
+ field: 'traces',
+ name: 'Traces',
+ align: 'right',
+ sortable: true,
+ truncateText: true,
+ render: (item: any, row: any) => (
+ <>
+ {item === 0 || item ? (
+ {
+ setRedirect(true);
+ addFilter({
+ field: 'serviceName',
+ operator: 'is',
+ value: row.name,
+ inverted: false,
+ disabled: false,
+ });
+ traceColumnAction();
+ }}
+ >
+
+
+ ) : (
+ '-'
+ )}
+ >
+ ),
+ },
+ ] as Array>,
+ [items]
+ );
+
+ const titleBar = useMemo(() => renderTitleBar(items?.length), [items]);
+
+ return (
+ <>
+
+ {titleBar}
+
+
+ {items?.length > 0 ? (
+
+ ) : indicesExist ? (
+
+ ) : (
+
+ )}
+
+ >
+ );
+}
diff --git a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/flyout_list_item.test.tsx.snap b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/flyout_list_item.test.tsx.snap
new file mode 100644
index 0000000000..00b1ddc113
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/flyout_list_item.test.tsx.snap
@@ -0,0 +1,48 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` spec renders the component 1`] = `
+
+`;
diff --git a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/service_breakdown_panel.test.tsx.snap b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/service_breakdown_panel.test.tsx.snap
new file mode 100644
index 0000000000..949b2fc032
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/service_breakdown_panel.test.tsx.snap
@@ -0,0 +1,432 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Service breakdown panel component renders empty service breakdown panel 1`] = `
+
+
+
+
+
+
+
+ Time spent by service
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Service breakdown panel component renders service breakdown panel 1`] = `
+%{value:.2f}% ",
+ "labels": Array [
+ "inventory",
+ ],
+ "marker": Object {
+ "colors": Array [
+ "#7492e7",
+ ],
+ },
+ "textinfo": "none",
+ "type": "pie",
+ "values": Array [
+ 100,
+ ],
+ },
+ ]
+ }
+>
+
+
+
+
+
+
+ Time spent by service
+
+
+
+
+
+
+
+
+
+
+
+
%{value:.2f}% ",
+ "labels": Array [
+ "inventory",
+ ],
+ "marker": Object {
+ "colors": Array [
+ "#7492e7",
+ ],
+ },
+ "textinfo": "none",
+ "type": "pie",
+ "values": Array [
+ 100,
+ ],
+ },
+ ]
+ }
+ layout={
+ Object {
+ "height": 200,
+ "margin": Object {
+ "b": 5,
+ "l": 5,
+ "r": 5,
+ "t": 5,
+ },
+ "showlegend": false,
+ "width": 200,
+ }
+ }
+ >
+ %{value:.2f}% ",
+ "labels": Array [
+ "inventory",
+ ],
+ "marker": Object {
+ "colors": Array [
+ "#7492e7",
+ ],
+ },
+ "textinfo": "none",
+ "type": "pie",
+ "values": Array [
+ 100,
+ ],
+ },
+ ]
+ }
+ debug={false}
+ divId="explorerPlotComponent"
+ layout={
+ Object {
+ "autosize": true,
+ "barmode": "stack",
+ "height": 200,
+ "hovermode": "closest",
+ "legend": Object {
+ "orientation": "h",
+ "traceorder": "normal",
+ },
+ "margin": Object {
+ "b": 5,
+ "l": 5,
+ "r": 5,
+ "t": 5,
+ },
+ "showlegend": false,
+ "width": 200,
+ "xaxis": Object {
+ "automargin": true,
+ "rangemode": "normal",
+ "showgrid": true,
+ "zeroline": false,
+ },
+ "yaxis": Object {
+ "rangemode": "normal",
+ "showgrid": true,
+ "zeroline": false,
+ },
+ }
+ }
+ style={
+ Object {
+ "height": "100%",
+ "width": "100%",
+ }
+ }
+ useResizeHandler={true}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/span_detail_flyout.test.tsx.snap b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/span_detail_flyout.test.tsx.snap
new file mode 100644
index 0000000000..08a482581c
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/span_detail_flyout.test.tsx.snap
@@ -0,0 +1,2217 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` spec renders the component with data 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Overview
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frontend-client
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ client_pay_order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 03/25/2021 17:23:45
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 03/25/2021 17:23:45
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Span attributes
+
+
+ (12)
+
+
+
+
+
+
+
+
+ droppedAttributesCount
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ droppedEventsCount
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ droppedLinksCount
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ instrumentationLibrary.name
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SPAN_KIND_INTERNAL
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ resource.attributes.host@hostname
+
+
+
+
+
+
+
+
+ ip-172-31-10-8.us-west-2.compute.internal
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ resource.attributes.service@name
+
+
+
+
+
+
+
+
+ frontend-client
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ resource.attributes.telemetry@sdk@language
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ resource.attributes.telemetry@sdk@name
+
+
+
+
+
+
+
+
+ opentelemetry
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ resource.attributes.telemetry@sdk@version
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[` spec renders the empty component 1`] = `
+
+
+
+
+
+
+
+ }
+ onActivation={[Function]}
+ onDeactivation={[Function]}
+ persistentFocus={false}
+ returnFocus={[Function]}
+ shards={Array []}
+ sideCar={
+ Object {
+ "assignMedium": [Function],
+ "assignSyncMedium": [Function],
+ "options": Object {
+ "async": true,
+ "ssr": false,
+ },
+ "read": [Function],
+ "useMedium": [Function],
+ }
+ }
+ >
+
+
+
+ }
+ onActivation={[Function]}
+ onDeactivation={[Function]}
+ persistentFocus={false}
+ returnFocus={[Function]}
+ shards={Array []}
+ sideCar={
+ Object {
+ "assignMedium": [Function],
+ "assignSyncMedium": [Function],
+ "options": Object {
+ "async": true,
+ "ssr": false,
+ },
+ "read": [Function],
+ "useMedium": [Function],
+ }
+ }
+ >
+
+
+
+ }
+ onActivation={[Function]}
+ onDeactivation={[Function]}
+ persistentFocus={false}
+ returnFocus={[Function]}
+ shards={Array []}
+ >
+
+
+
+ }
+ onActivation={[Function]}
+ onDeactivation={[Function]}
+ persistentFocus={false}
+ returnFocus={[Function]}
+ shards={Array []}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Span detail
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[` spec renders the empty component 2`] = `
+
+
+
+
+
+
+
+ }
+ onActivation={[Function]}
+ onDeactivation={[Function]}
+ persistentFocus={false}
+ returnFocus={[Function]}
+ shards={Array []}
+ sideCar={
+ Object {
+ "assignMedium": [Function],
+ "assignSyncMedium": [Function],
+ "options": Object {
+ "async": true,
+ "ssr": false,
+ },
+ "read": [Function],
+ "useMedium": [Function],
+ }
+ }
+ >
+
+
+
+ }
+ onActivation={[Function]}
+ onDeactivation={[Function]}
+ persistentFocus={false}
+ returnFocus={[Function]}
+ shards={Array []}
+ sideCar={
+ Object {
+ "assignMedium": [Function],
+ "assignSyncMedium": [Function],
+ "options": Object {
+ "async": true,
+ "ssr": false,
+ },
+ "read": [Function],
+ "useMedium": [Function],
+ }
+ }
+ >
+
+
+
+ }
+ onActivation={[Function]}
+ onDeactivation={[Function]}
+ persistentFocus={false}
+ returnFocus={[Function]}
+ shards={Array []}
+ >
+
+
+
+ }
+ onActivation={[Function]}
+ onDeactivation={[Function]}
+ persistentFocus={false}
+ returnFocus={[Function]}
+ shards={Array []}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Span detail
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/span_detail_panel.test.tsx.snap b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/span_detail_panel.test.tsx.snap
new file mode 100644
index 0000000000..89378df5fb
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/span_detail_panel.test.tsx.snap
@@ -0,0 +1,527 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Service breakdown panel component renders service breakdown panel 1`] = `
+HTTP GET 4dec6080-61af-11eb-aee3-ef2f84ffa4a2",
+ ],
+ },
+ Object {
+ "hovertemplate": "%{x} ",
+ "marker": Object {
+ "color": "#7492e7",
+ },
+ "orientation": "h",
+ "text": Array [
+ "Error",
+ ],
+ "textfont": Object {
+ "color": Array [
+ "#c14125",
+ ],
+ },
+ "textposition": "outside",
+ "type": "bar",
+ "width": 0.4,
+ "x": Array [
+ 19.91,
+ ],
+ "y": Array [
+ "inventory HTTP GET 4dec6080-61af-11eb-aee3-ef2f84ffa4a2",
+ ],
+ },
+ ],
+ "ganttMaxX": 19.91,
+ "table": Array [
+ Object {
+ "end_time": "2020-11-10T17:55:45.239564396Z",
+ "error": "Error",
+ "latency": 19.91,
+ "service_name": "inventory",
+ "span_id": "32c641131b569afa",
+ "start_time": "2020-11-10T17:55:45.219652629Z",
+ "vs_benchmark": 0,
+ },
+ ],
+ }
+ }
+ setData={[MockFunction]}
+>
+
+
+
+
+
+
+
+
+
+
+ Spans
+
+
+ (1)
+
+
+
+
+
+
+
+
+
+
+
+
+ Select view of spans
+
+
+
+
+
+
+
+
+
+
+
+
+
+
HTTP GET 4dec6080-61af-11eb-aee3-ef2f84ffa4a2",
+ ],
+ },
+ Object {
+ "hovertemplate": "%{x} ",
+ "marker": Object {
+ "color": "#7492e7",
+ },
+ "orientation": "h",
+ "text": Array [
+ "Error",
+ ],
+ "textfont": Object {
+ "color": Array [
+ "#c14125",
+ ],
+ },
+ "textposition": "outside",
+ "type": "bar",
+ "width": 0.4,
+ "x": Array [
+ 19.91,
+ ],
+ "y": Array [
+ "inventory HTTP GET 4dec6080-61af-11eb-aee3-ef2f84ffa4a2",
+ ],
+ },
+ ]
+ }
+ layout={
+ Object {
+ "height": 110,
+ "margin": Object {
+ "b": 30,
+ "l": 260,
+ "r": 5,
+ "t": 30,
+ },
+ "width": 800,
+ "xaxis": Object {
+ "color": "#91989c",
+ "range": Array [
+ 0,
+ 23.892,
+ ],
+ "showline": true,
+ "side": "top",
+ "ticksuffix": " ms",
+ },
+ "yaxis": Object {
+ "showgrid": false,
+ "ticktext": Array [
+ "inventory HTTP GET ",
+ ],
+ "tickvals": Array [
+ "inventory HTTP GET 4dec6080-61af-11eb-aee3-ef2f84ffa4a2",
+ ],
+ },
+ }
+ }
+ onClickHandler={[Function]}
+ onHoverHandler={[Function]}
+ onUnhoverHandler={[Function]}
+ >
+ HTTP GET 4dec6080-61af-11eb-aee3-ef2f84ffa4a2",
+ ],
+ },
+ Object {
+ "hovertemplate": "%{x} ",
+ "marker": Object {
+ "color": "#7492e7",
+ },
+ "orientation": "h",
+ "text": Array [
+ "Error",
+ ],
+ "textfont": Object {
+ "color": Array [
+ "#c14125",
+ ],
+ },
+ "textposition": "outside",
+ "type": "bar",
+ "width": 0.4,
+ "x": Array [
+ 19.91,
+ ],
+ "y": Array [
+ "inventory HTTP GET 4dec6080-61af-11eb-aee3-ef2f84ffa4a2",
+ ],
+ },
+ ]
+ }
+ debug={false}
+ divId="explorerPlotComponent"
+ layout={
+ Object {
+ "autosize": true,
+ "barmode": "stack",
+ "height": 110,
+ "hovermode": "closest",
+ "legend": Object {
+ "orientation": "h",
+ "traceorder": "normal",
+ },
+ "margin": Object {
+ "b": 30,
+ "l": 260,
+ "r": 5,
+ "t": 30,
+ },
+ "showlegend": false,
+ "width": 800,
+ "xaxis": Object {
+ "color": "#91989c",
+ "range": Array [
+ 0,
+ 23.892,
+ ],
+ "showline": true,
+ "side": "top",
+ "ticksuffix": " ms",
+ },
+ "yaxis": Object {
+ "showgrid": false,
+ "ticktext": Array [
+ "inventory HTTP GET ",
+ ],
+ "tickvals": Array [
+ "inventory HTTP GET 4dec6080-61af-11eb-aee3-ef2f84ffa4a2",
+ ],
+ },
+ }
+ }
+ onClick={[Function]}
+ onHover={[Function]}
+ onUnhover={[Function]}
+ style={
+ Object {
+ "height": "100%",
+ "width": "100%",
+ }
+ }
+ useResizeHandler={true}
+ >
+
+
+
+
+
+
+
+`;
diff --git a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/span_detail_table.test.tsx.snap b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/span_detail_table.test.tsx.snap
new file mode 100644
index 0000000000..674d48a955
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/span_detail_table.test.tsx.snap
@@ -0,0 +1,354 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` spec renders the component with data 1`] = `
+
+`;
+
+exports[` spec renders the empty component 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+ }
+ title={
+
+ No matches
+
+ }
+ >
+
+
+
+
+
+ No matches
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/trace_view.test.tsx.snap b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/trace_view.test.tsx.snap
new file mode 100644
index 0000000000..bc35bb4ef9
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/trace_view.test.tsx.snap
@@ -0,0 +1,169 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Trace view component renders trace view 1`] = `
+
+
+
+
+
+
+
+ test
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace ID
+
+
+
+
+ Trace group name
+
+
+ -
+
+
+
+
+
+
+
+
+ Latency
+
+
+
+
+
+ Last updated
+
+
+
+
+
+
+
+
+
+ Errors
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces.test.tsx.snap b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces.test.tsx.snap
new file mode 100644
index 0000000000..e0af247d6e
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces.test.tsx.snap
@@ -0,0 +1,2374 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Traces component renders empty traces page 1`] = `
+
+
+
+ Traces
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ >
+
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="QuickSelectPopover"
+ isOpen={false}
+ ownFocus={true}
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
}
+ iconType={false}
+ isCustom={true}
+ startDateControl={
}
+ >
+
+
+ Last 5 minutes
+
+
+ Show dates
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Refresh
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+
+
+
+ + Add filter
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="m"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+ + Add filter
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Traces
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Learn more
+
+ }
+ body={
+
+ The indices required for trace analytics (otel-v1-apm-span-* and otel-v1-apm-service-map*) do not exist or you do not have permission to access them.
+
+ }
+ title={
+
+ Trace Analytics not set up
+
+ }
+ >
+
+
+
+
+
+ Trace Analytics not set up
+
+
+
+
+
+
+
+
+
+ The indices required for trace analytics (otel-v1-apm-span-* and otel-v1-apm-service-map*) do not exist or you do not have permission to access them.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Learn more
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Traces component renders traces page 1`] = `
+
+
+
+ Traces
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ >
+
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ id="QuickSelectPopover"
+ isOpen={false}
+ ownFocus={true}
+ panelPaddingSize="m"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
}
+ iconType={false}
+ isCustom={true}
+ startDateControl={
}
+ >
+
+
+ Last 5 minutes
+
+
+ Show dates
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Refresh
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+
+
+
+ + Add filter
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="m"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+ + Add filter
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Traces
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+ }
+ title={
+
+ No matches
+
+ }
+ >
+
+
+
+
+
+ No matches
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces_table.test.tsx.snap b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces_table.test.tsx.snap
new file mode 100644
index 0000000000..7a68b18cdd
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/traces_table.test.tsx.snap
@@ -0,0 +1,2042 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Traces table component renders empty traces table message 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+ Traces
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Learn more
+
+ }
+ body={
+
+ The indices required for trace analytics (otel-v1-apm-span-* and otel-v1-apm-service-map*) do not exist or you do not have permission to access them.
+
+ }
+ title={
+
+ Trace Analytics not set up
+
+ }
+ >
+
+
+
+
+
+ Trace Analytics not set up
+
+
+
+
+
+
+
+
+
+ The indices required for trace analytics (otel-v1-apm-span-* and otel-v1-apm-service-map*) do not exist or you do not have permission to access them.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Learn more
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Traces table component renders empty traces table message 2`] = `
+
+
+
+
+
+
+
+
+
+
+
+ Traces
+
+
+ (0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+ }
+ title={
+
+ No matches
+
+ }
+ >
+
+
+
+
+
+ No matches
+
+
+
+
+
+
+
+
+
+ No data matches the selected filter. Clear the filter and/or increase the time range to see more results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Traces table component renders traces table 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+ Traces
+
+
+ (1)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Percentile in trace group
+
+ ,
+ "render": [Function],
+ "sortable": true,
+ },
+ Object {
+ "align": "right",
+ "field": "error_count",
+ "name": "Errors",
+ "render": [Function],
+ "sortable": true,
+ },
+ Object {
+ "align": "left",
+ "field": "last_updated",
+ "name": "Last updated",
+ "render": [Function],
+ "sortable": true,
+ },
+ ]
+ }
+ items={
+ Array [
+ Object {
+ "actions": "#",
+ "error_count": "Yes",
+ "last_updated": "11/10/2020 09:55:45",
+ "latency": 19.91,
+ "percentile_in_trace_group": 30,
+ "trace_group": "HTTP GET",
+ "trace_id": "00079a615e31e61766fcb20b557051c1",
+ },
+ ]
+ }
+ loading={false}
+ onTableChange={[Function]}
+ pagination={
+ Object {
+ "initialPageSize": 10,
+ "pageSizeOptions": Array [
+ 5,
+ 10,
+ 15,
+ ],
+ }
+ }
+ responsive={true}
+ sorting={
+ Object {
+ "sort": Object {
+ "direction": "asc",
+ "field": "trace_id",
+ },
+ }
+ }
+ tableLayout="auto"
+ >
+
+
+ Percentile in trace group
+
+ ,
+ "render": [Function],
+ "sortable": true,
+ },
+ Object {
+ "align": "right",
+ "field": "error_count",
+ "name": "Errors",
+ "render": [Function],
+ "sortable": true,
+ },
+ Object {
+ "align": "left",
+ "field": "last_updated",
+ "name": "Last updated",
+ "render": [Function],
+ "sortable": true,
+ },
+ ]
+ }
+ items={
+ Array [
+ Object {
+ "actions": "#",
+ "error_count": "Yes",
+ "last_updated": "11/10/2020 09:55:45",
+ "latency": 19.91,
+ "percentile_in_trace_group": 30,
+ "trace_group": "HTTP GET",
+ "trace_id": "00079a615e31e61766fcb20b557051c1",
+ },
+ ]
+ }
+ loading={false}
+ noItemsMessage="No items found"
+ onChange={[Function]}
+ pagination={
+ Object {
+ "hidePerPageOptions": undefined,
+ "pageIndex": 0,
+ "pageSize": 10,
+ "pageSizeOptions": Array [
+ 5,
+ 10,
+ 15,
+ ],
+ "totalItemCount": 1,
+ }
+ }
+ responsive={true}
+ sorting={
+ Object {
+ "allowNeutralSort": true,
+ "sort": Object {
+ "direction": "asc",
+ "field": "Trace ID",
+ },
+ }
+ }
+ tableLayout="auto"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Percentile in trace group
+
+ ,
+ "onSort": [Function],
+ },
+ Object {
+ "isSortAscending": undefined,
+ "isSorted": false,
+ "key": "_data_s_error_count_4",
+ "name": "Errors",
+ "onSort": [Function],
+ },
+ Object {
+ "isSortAscending": undefined,
+ "isSorted": false,
+ "key": "_data_s_last_updated_5",
+ "name": "Last updated",
+ "onSort": [Function],
+ },
+ ]
+ }
+ >
+
+
+
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelPaddingSize="none"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sorting
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace ID
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Click to sort in descending order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace group
+
+
+
+
+
+
+ Click to sort in ascending order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latency (ms)
+
+
+
+
+
+
+ Click to sort in ascending order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Percentile in trace group
+
+
+
+
+
+
+
+ Click to sort in ascending order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Errors
+
+
+
+
+
+
+ Click to sort in ascending order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Last updated
+
+
+
+
+
+
+ Click to sort in ascending order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace ID
+
+
+
+
+
+
+
+
+
+ 00079a615e31e61766fcb...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Trace group
+
+
+
+
+
+
+
+ Latency (ms)
+
+
+
+ 19.91
+
+
+
+
+
+
+ Percentile in trace group
+
+ ,
+ "render": undefined,
+ }
+ }
+ setScopeRow={false}
+ textOnly={false}
+ >
+
+
+
+ Percentile in trace group
+
+
+
+
+
+
+
+
+ Errors
+
+
+ No
+
+
+
+
+
+
+ Last updated
+
+
+ 11/10/2020 09:55:45
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ :
+ 10
+
+ }
+ closePopover={[Function]}
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={false}
+ panelPaddingSize="none"
+ withTitle={true}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Rows per page
+
+ :
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/trace_analytics/components/traces/__tests__/flyout_list_item.test.tsx b/public/components/trace_analytics/components/traces/__tests__/flyout_list_item.test.tsx
new file mode 100644
index 0000000000..130d694583
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/__tests__/flyout_list_item.test.tsx
@@ -0,0 +1,29 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { render } from '@testing-library/react';
+import { configure } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { FlyoutListItem } from '../flyout_list_item';
+
+describe(' spec', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders the component', () => {
+ const addSpanFilter = jest.fn();
+ const utils = render(
+
+ );
+ expect(utils.container.firstChild).toMatchSnapshot();
+ });
+
+ it('renders the component', () => {
+ const addSpanFilter = jest.fn();
+ const utils = render(
+
+ );
+ });
+});
diff --git a/public/components/trace_analytics/components/traces/__tests__/service_breakdown_panel.test.tsx b/public/components/trace_analytics/components/traces/__tests__/service_breakdown_panel.test.tsx
new file mode 100644
index 0000000000..82fb9257ab
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/__tests__/service_breakdown_panel.test.tsx
@@ -0,0 +1,33 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { ServiceBreakdownPanel } from '../service_breakdown_panel';
+
+describe('Service breakdown panel component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders empty service breakdown panel', () => {
+ const wrapper = mount( );
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it('renders service breakdown panel', () => {
+ const data = [
+ {
+ values: [100],
+ labels: ['inventory'],
+ marker: { colors: ['#7492e7'] },
+ type: 'pie',
+ textinfo: 'none',
+ hovertemplate: '%{label} %{value:.2f}% ',
+ },
+ ] as Plotly.Data[];
+ const wrapper = mount( );
+ expect(wrapper).toMatchSnapshot();
+ });
+});
diff --git a/public/components/trace_analytics/components/traces/__tests__/span_detail_flyout.test.tsx b/public/components/trace_analytics/components/traces/__tests__/span_detail_flyout.test.tsx
new file mode 100644
index 0000000000..58935b22f5
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/__tests__/span_detail_flyout.test.tsx
@@ -0,0 +1,62 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { waitFor } from '@testing-library/react';
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import ReactDOM from 'react-dom';
+import { act } from 'react-dom/test-utils';
+import { HttpResponse } from '../../../../../../../../src/core/public';
+import { TEST_SPAN_RESPONSE } from '../../../../../../test/constants';
+import httpClientMock from '../../../../../../test/__mocks__/httpClientMock';
+import { SpanDetailFlyout } from '../span_detail_flyout';
+
+describe(' spec', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders the empty component', async () => {
+ httpClientMock.post = jest.fn(() =>
+ Promise.resolve(({ hits: { hits: [], total: { value: 0 } } } as unknown) as HttpResponse)
+ );
+ const closeFlyout = jest.fn();
+ const addSpanFilter = jest.fn();
+ const utils = await mount(
+
+ );
+ utils.update();
+ await waitFor(() => {
+ expect(utils).toMatchSnapshot();
+ });
+ });
+
+ it('renders the component with data', async () => {
+ httpClientMock.post = jest.fn(() =>
+ Promise.resolve((TEST_SPAN_RESPONSE as unknown) as HttpResponse)
+ );
+ let container = document.createElement('div');
+ const closeFlyout = jest.fn();
+ const addSpanFilter = jest.fn();
+ await act(() => {
+ ReactDOM.render(
+ ,
+ container
+ );
+ });
+ expect(container).toMatchSnapshot();
+ });
+});
diff --git a/public/components/trace_analytics/components/traces/__tests__/span_detail_panel.test.tsx b/public/components/trace_analytics/components/traces/__tests__/span_detail_panel.test.tsx
new file mode 100644
index 0000000000..bcad5bd546
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/__tests__/span_detail_panel.test.tsx
@@ -0,0 +1,57 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { render } from '@testing-library/react';
+import { configure, mount, shallow } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import { SpanDetailPanel } from '../span_detail_panel';
+
+describe('Service breakdown panel component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders service breakdown panel', () => {
+ const data = {
+ gantt: [
+ {
+ x: [0],
+ y: ['inventory HTTP GET 4dec6080-61af-11eb-aee3-ef2f84ffa4a2'],
+ marker: { color: 'rgba(0, 0, 0, 0)' },
+ width: 0.4,
+ type: 'bar',
+ orientation: 'h',
+ hoverinfo: 'none',
+ showlegend: false,
+ },
+ {
+ x: [19.91],
+ y: ['inventory HTTP GET 4dec6080-61af-11eb-aee3-ef2f84ffa4a2'],
+ text: ['Error'],
+ textfont: { color: ['#c14125'] },
+ textposition: 'outside',
+ marker: { color: '#7492e7' },
+ width: 0.4,
+ type: 'bar',
+ orientation: 'h',
+ hovertemplate: '%{x} ',
+ },
+ ] as Plotly.Data[],
+ table: [
+ {
+ service_name: 'inventory',
+ span_id: '32c641131b569afa',
+ latency: 19.91,
+ vs_benchmark: 0,
+ error: 'Error',
+ start_time: '2020-11-10T17:55:45.219652629Z',
+ end_time: '2020-11-10T17:55:45.239564396Z',
+ },
+ ],
+ ganttMaxX: 19.91,
+ };
+ const wrapper = mount( );
+ expect(wrapper).toMatchSnapshot();
+ });
+});
diff --git a/public/components/trace_analytics/components/traces/__tests__/span_detail_table.test.tsx b/public/components/trace_analytics/components/traces/__tests__/span_detail_table.test.tsx
new file mode 100644
index 0000000000..59837df0ee
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/__tests__/span_detail_table.test.tsx
@@ -0,0 +1,57 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { waitFor } from '@testing-library/react';
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import ReactDOM from 'react-dom';
+import { act } from 'react-dom/test-utils';
+import { HttpResponse } from '../../../../../../../../src/core/public';
+import { TEST_SPAN_RESPONSE } from '../../../../../../test/constants';
+import httpClientMock from '../../../../../../test/__mocks__/httpClientMock';
+import { SpanDetailTable } from '../span_detail_table';
+
+describe(' spec', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders the empty component', async () => {
+ httpClientMock.post = jest.fn(() =>
+ Promise.resolve(({ hits: { hits: [], total: { value: 0 } } } as unknown) as HttpResponse)
+ );
+ const utils = await mount(
+ {}}
+ />
+ );
+ utils.update();
+ await waitFor(() => {
+ expect(utils).toMatchSnapshot();
+ });
+ });
+
+ it('renders the component with data', async () => {
+ const setCurrentSpan = jest.fn();
+ httpClientMock.post = jest.fn(() =>
+ Promise.resolve((TEST_SPAN_RESPONSE as unknown) as HttpResponse)
+ );
+ let container = document.createElement('div');
+ await act(() => {
+ ReactDOM.render(
+ setCurrentSpan(spanId)}
+ />,
+ container
+ );
+ });
+ expect(container).toMatchSnapshot();
+ });
+});
diff --git a/public/components/trace_analytics/components/traces/__tests__/trace_view.test.tsx b/public/components/trace_analytics/components/traces/__tests__/trace_view.test.tsx
new file mode 100644
index 0000000000..3d334e25c6
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/__tests__/trace_view.test.tsx
@@ -0,0 +1,27 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, shallow } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { TraceView } from '..';
+import { coreStartMock } from '../../../../../../test/__mocks__/coreMocks';
+
+describe('Trace view component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders trace view', () => {
+ const core = coreStartMock;
+ const wrapper = shallow(
+
+ );
+ expect(wrapper).toMatchSnapshot();
+ });
+});
diff --git a/public/components/trace_analytics/components/traces/__tests__/traces.test.tsx b/public/components/trace_analytics/components/traces/__tests__/traces.test.tsx
new file mode 100644
index 0000000000..a48f54f0c9
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/__tests__/traces.test.tsx
@@ -0,0 +1,98 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import { Traces } from '..';
+import { coreStartMock } from '../../../../../../test/__mocks__/coreMocks';
+
+describe('Traces component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders empty traces page', () => {
+ const core = coreStartMock;
+ const setQuery = jest.fn();
+ const setFilters = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const traceIdColumnAction = (item: any) =>
+ location.assign(`#/trace_analytics/traces/${encodeURIComponent(item)}`);
+ const childBreadcrumbs = [
+ {
+ text: 'Trace analytics',
+ href: '#/trace_analytics/home',
+ },
+ {
+ text: 'Traces',
+ href: '#/trace_analytics/traces',
+ },
+ ];
+ const wrapper = mount(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it('renders traces page', () => {
+ const core = coreStartMock;
+ const setQuery = jest.fn();
+ const setFilters = jest.fn();
+ const setStartTime = jest.fn();
+ const setEndTime = jest.fn();
+ const traceIdColumnAction = (item: any) =>
+ location.assign(`#/trace_analytics/traces/${encodeURIComponent(item)}`);
+ const childBreadcrumbs = [
+ {
+ text: 'Trace analytics',
+ href: '#/trace_analytics/home',
+ },
+ {
+ text: 'Traces',
+ href: '#/trace_analytics/traces',
+ },
+ ];
+ const wrapper = mount(
+
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+});
diff --git a/public/components/trace_analytics/components/traces/__tests__/traces_table.test.tsx b/public/components/trace_analytics/components/traces/__tests__/traces_table.test.tsx
new file mode 100644
index 0000000000..c57fd4f78f
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/__tests__/traces_table.test.tsx
@@ -0,0 +1,70 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { TracesTable } from '../traces_table';
+
+describe('Traces table component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('renders empty traces table message', () => {
+ const refresh = jest.fn();
+ const traceIdColumnAction = (item: any) =>
+ location.assign(`#/trace_analytics/traces/${encodeURIComponent(item)}`);
+ const noIndicesTable = mount(
+
+ );
+ expect(noIndicesTable).toMatchSnapshot();
+
+ const emptyTable = mount(
+
+ );
+ expect(emptyTable).toMatchSnapshot();
+ });
+
+ it('renders traces table', () => {
+ jest.mock('../../../../../../common/constants/trace_analytics', () => ({ TRACES_MAX_NUM: 1 }));
+ const tableItems = [
+ {
+ trace_id: '00079a615e31e61766fcb20b557051c1',
+ trace_group: 'HTTP GET',
+ latency: 19.91,
+ last_updated: '11/10/2020 09:55:45',
+ error_count: 'Yes',
+ percentile_in_trace_group: 30,
+ actions: '#',
+ },
+ ];
+ const traceIdColumnAction = (item: any) =>
+ location.assign(`#/trace_analytics/traces/${encodeURIComponent(item)}`);
+ const refresh = jest.fn();
+ const wrapper = mount(
+
+ );
+ expect(wrapper).toMatchSnapshot();
+
+ wrapper.find('button[data-test-subj="tableHeaderSortButton"]').at(0).simulate('click');
+ });
+});
diff --git a/public/components/trace_analytics/components/traces/flyout_list_item.tsx b/public/components/trace_analytics/components/traces/flyout_list_item.tsx
new file mode 100644
index 0000000000..22111c8e5d
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/flyout_list_item.tsx
@@ -0,0 +1,86 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ EuiButtonIcon,
+ EuiDescriptionList,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiSpacer,
+ EuiText,
+ EuiToolTip,
+} from '@elastic/eui';
+import React, { useState } from 'react';
+
+interface FlyoutListItemProps {
+ title: React.ReactNode;
+ description: React.ReactNode;
+ addSpanFilter: () => void;
+}
+
+export function FlyoutListItem(props: FlyoutListItemProps) {
+ const [hover, setHover] = useState(false);
+
+ const descriptionComponent =
+ props.description !== '-' ? (
+
+
+
+ {props.description}
+
+
+
+ {hover && (
+
+
+
+ )}
+
+
+ ) : (
+
+ {props.description}
+
+ );
+ return (
+ <>
+ setHover(true)}
+ onMouseLeave={() => setHover(false)}
+ onFocus={() => setHover(true)}
+ >
+
+ {props.title}
+
+ ),
+ description: descriptionComponent,
+ },
+ ]}
+ type="column"
+ align="center"
+ compressed
+ />
+
+
+ >
+ );
+}
diff --git a/public/components/trace_analytics/components/traces/index.ts b/public/components/trace_analytics/components/traces/index.ts
new file mode 100644
index 0000000000..534ae2e036
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/index.ts
@@ -0,0 +1,7 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { Traces } from './traces';
+export { TraceView } from './trace_view';
diff --git a/public/components/trace_analytics/components/traces/service_breakdown_panel.tsx b/public/components/trace_analytics/components/traces/service_breakdown_panel.tsx
new file mode 100644
index 0000000000..71987208d0
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/service_breakdown_panel.tsx
@@ -0,0 +1,84 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiHealth,
+ EuiHorizontalRule,
+ EuiPanel,
+ EuiSpacer,
+ EuiText,
+} from '@elastic/eui';
+import _ from 'lodash';
+import React, { useMemo } from 'react';
+import { Plt } from '../../../visualizations/plotly/plot';
+import { PanelTitle } from '../common/helper_functions';
+
+export function ServiceBreakdownPanel(props: { data: Plotly.Data[] }) {
+ const layout = useMemo(
+ () =>
+ ({
+ height: 200,
+ width: 200,
+ showlegend: false,
+ margin: {
+ l: 5,
+ r: 5,
+ b: 5,
+ t: 5,
+ },
+ } as Partial),
+ [props.data]
+ );
+
+ const renderStats = () => {
+ return props.data.length > 0 ? (
+
+
+
+ {props.data[0].marker.colors.map((color, i) => (
+
+
+ {props.data[0].labels[i]}
+
+
+ ))}
+
+
+
+
+
+
+ {props.data[0].values.map((value, i) => (
+
+ {_.round(value, 2)}%
+
+ ))}
+
+
+
+ ) : null;
+ };
+
+ const stats = useMemo(() => renderStats(), [props.data]);
+
+ return (
+ <>
+
+
+
+
+
+ {props.data?.length > 0 ? : null}
+
+
+ {stats}
+
+
+
+ >
+ );
+}
diff --git a/public/components/trace_analytics/components/traces/span_detail_flyout.tsx b/public/components/trace_analytics/components/traces/span_detail_flyout.tsx
new file mode 100644
index 0000000000..a49432d615
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/span_detail_flyout.tsx
@@ -0,0 +1,204 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ EuiButtonIcon,
+ EuiCodeBlock,
+ EuiCopy,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiFlyout,
+ EuiFlyoutBody,
+ EuiFlyoutHeader,
+ EuiHorizontalRule,
+ EuiSpacer,
+ EuiText,
+ EuiTitle,
+} from '@elastic/eui';
+import _ from 'lodash';
+import moment from 'moment';
+import React, { useEffect, useState } from 'react';
+import { HttpSetup } from '../../../../../../../src/core/public';
+import { TRACE_ANALYTICS_DATE_FORMAT } from '../../../../../common/constants/trace_analytics';
+import { handleSpansFlyoutRequest } from '../../requests/traces_request_handler';
+import { nanoToMilliSec } from '../common/helper_functions';
+import { FlyoutListItem } from './flyout_list_item';
+
+export function SpanDetailFlyout(props: {
+ http: HttpSetup;
+ spanId: string;
+ isFlyoutVisible: boolean;
+ closeFlyout: () => void;
+ addSpanFilter: (field: string, value: any) => void;
+}) {
+ const [span, setSpan] = useState({});
+
+ useEffect(() => {
+ handleSpansFlyoutRequest(props.http, props.spanId, setSpan);
+ }, [props.spanId]);
+
+ const getListItem = (field: string, title: React.ReactNode, description: React.ReactNode) => {
+ return (
+ props.addSpanFilter(field, span[field])}
+ />
+ );
+ };
+
+ const isEmpty = (value) => {
+ return (
+ value == null ||
+ (value.hasOwnProperty('length') && value.length === 0) ||
+ (value.constructor === Object && Object.keys(value).length === 0)
+ );
+ };
+
+ const renderContent = () => {
+ if (!span || _.isEmpty(span)) return '-';
+ const overviewList = [
+ getListItem(
+ 'spanId',
+ 'Span ID',
+ span.spanId ? (
+
+
+
+ {(copy) => (
+
+ )}
+
+
+ {span.spanId}
+
+ ) : (
+ '-'
+ )
+ ),
+ getListItem(
+ 'parentSpanId',
+ 'Parent span ID',
+ span.parentSpanId ? (
+
+
+
+ {(copy) => (
+
+ )}
+
+
+ {span.parentSpanId}
+
+ ) : (
+ '-'
+ )
+ ),
+ getListItem('serviceName', 'Service', span.serviceName || '-'),
+ getListItem('name', 'Operation', span.name || '-'),
+ getListItem(
+ 'durationInNanos',
+ 'Duration',
+ `${_.round(nanoToMilliSec(Math.max(0, span.durationInNanos)), 2)} ms`
+ ),
+ getListItem(
+ 'startTime',
+ 'Start time',
+ moment(span.startTime).format(TRACE_ANALYTICS_DATE_FORMAT)
+ ),
+ getListItem('endTime', 'End time', moment(span.endTime).format(TRACE_ANALYTICS_DATE_FORMAT)),
+ getListItem(
+ 'status.code',
+ 'Errors',
+ span['status.code'] === 2 ? (
+
+ Yes
+
+ ) : (
+ 'No'
+ )
+ ),
+ ];
+ const ignoredKeys = new Set([
+ 'spanId',
+ 'parentSpanId',
+ 'serviceName',
+ 'name',
+ 'durationInNanos',
+ 'startTime',
+ 'endTime',
+ 'status.code',
+ 'events',
+ 'traceId',
+ 'traceGroup',
+ 'traceGroupFields.endTime',
+ 'traceGroupFields.statusCode',
+ 'traceGroupFields.durationInNanos',
+ ]);
+ const attributesList = Object.keys(span)
+ .filter((key) => !ignoredKeys.has(key))
+ .sort((keyA, keyB) => {
+ const isANull = isEmpty(span[keyA]);
+ const isBNull = isEmpty(span[keyB]);
+ if ((isANull && isBNull) || (!isANull && !isBNull)) return keyA < keyB ? -1 : 1;
+ if (isANull) return 1;
+ return -1;
+ })
+ .map((key) => {
+ if (isEmpty(span[key])) return getListItem(key, key, '-');
+ let value = span[key];
+ if (typeof value === 'object') value = JSON.stringify(value);
+ return getListItem(key, key, value);
+ });
+
+ const eventsComponent = _.isEmpty(span['events']) ? null : (
+ <>
+
+ Event
+
+
+ {JSON.stringify(span['events'], null, 2)}
+
+
+
+ >
+ );
+
+ return (
+ <>
+
+ Overview
+
+
+ {overviewList}
+
+
+ {eventsComponent}
+
+ Span attributes
+ {attributesList.length === 0 || attributesList.length ? (
+ {` (${attributesList.length})`}
+ ) : null}
+
+
+ {attributesList}
+ >
+ );
+ };
+
+ return (
+ <>
+
+
+
+ Span detail
+
+
+ {renderContent()}
+
+ >
+ );
+}
diff --git a/public/components/trace_analytics/components/traces/span_detail_panel.tsx b/public/components/trace_analytics/components/traces/span_detail_panel.tsx
new file mode 100644
index 0000000000..466a12b428
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/span_detail_panel.tsx
@@ -0,0 +1,271 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable react-hooks/exhaustive-deps */
+
+import {
+ EuiBadge,
+ EuiButtonGroup,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiHorizontalRule,
+ EuiPanel,
+ EuiSpacer,
+} from '@elastic/eui';
+import _ from 'lodash';
+import React, { useEffect, useMemo, useState } from 'react';
+import { HttpSetup } from '../../../../../../../src/core/public';
+import { Plt } from '../../../visualizations/plotly/plot';
+import { handleSpansGanttRequest } from '../../requests/traces_request_handler';
+import { PanelTitle } from '../common/helper_functions';
+import { SpanDetailFlyout } from './span_detail_flyout';
+import { SpanDetailTable } from './span_detail_table';
+
+export function SpanDetailPanel(props: {
+ http: HttpSetup;
+ traceId: string;
+ colorMap: any;
+ page?: string;
+ openSpanFlyout?: any;
+ data?: { gantt: any[]; table: any[]; ganttMaxX: number };
+ setData?: (data: { gantt: any[]; table: any[]; ganttMaxX: number }) => void;
+}) {
+ const storedFilters = sessionStorage.getItem('TraceAnalyticsSpanFilters');
+ const fromApp = props.page === 'app';
+ const [spanFilters, setSpanFilters] = useState>(
+ storedFilters ? JSON.parse(storedFilters) : []
+ );
+ const [DSL, setDSL] = useState({});
+ let data: { gantt: any[]; table: any[]; ganttMaxX: number },
+ setData: (data: { gantt: any[]; table: any[]; ganttMaxX: number }) => void;
+ if (props.data && props.setData) {
+ [data, setData] = [props.data, props.setData];
+ } else {
+ [data, setData] = useState<{ gantt: any[]; table: any[]; ganttMaxX: number }>({
+ gantt: [],
+ table: [],
+ ganttMaxX: 0,
+ });
+ }
+
+ const setSpanFiltersWithStorage = (newFilters: Array<{ field: string; value: any }>) => {
+ setSpanFilters(newFilters);
+ sessionStorage.setItem('TraceAnalyticsSpanFilters', JSON.stringify(newFilters));
+ };
+
+ const addSpanFilter = (field: string, value: any) => {
+ const newFilters = [...spanFilters];
+ const index = newFilters.findIndex(({ field: filterField }) => field === filterField);
+ if (index === -1) {
+ newFilters.push({ field, value });
+ } else {
+ newFilters.splice(index, 1, { field, value });
+ }
+ setSpanFiltersWithStorage(newFilters);
+ };
+
+ const removeSpanFilter = (field: string) => {
+ const newFilters = [...spanFilters];
+ const index = newFilters.findIndex(({ field: filterField }) => field === filterField);
+ if (index !== -1) {
+ newFilters.splice(index, 1);
+ setSpanFiltersWithStorage(newFilters);
+ }
+ };
+
+ const refresh = _.debounce(() => {
+ if (_.isEmpty(props.colorMap)) return;
+ const refreshDSL = spanFiltersToDSL();
+ setDSL(refreshDSL);
+ handleSpansGanttRequest(props.traceId, props.http, setData, props.colorMap, refreshDSL);
+ }, 150);
+
+ const spanFiltersToDSL = () => {
+ const spanDSL: any = {
+ query: {
+ bool: {
+ must: [
+ {
+ term: {
+ traceId: props.traceId,
+ },
+ },
+ ],
+ filter: [],
+ should: [],
+ must_not: [],
+ },
+ },
+ };
+ spanFilters.map(({ field, value }) => {
+ if (value != null) {
+ spanDSL.query.bool.must.push({
+ term: {
+ [field]: value,
+ },
+ });
+ }
+ });
+ return spanDSL;
+ };
+
+ useEffect(() => {
+ refresh();
+ }, [props.colorMap, spanFilters]);
+
+ const getSpanDetailLayout = (plotTraces: Plotly.Data[], maxX: number): Partial => {
+ // get unique labels from traces
+ const yLabels = plotTraces
+ .map((d) => d.y[0])
+ .filter((label, i, self) => self.indexOf(label) === i);
+ // remove uuid when displaying y-ticks
+ const yTexts = yLabels.map((label) => label.substring(0, label.length - 36));
+
+ return {
+ height: 25 * plotTraces.length + 60,
+ width: 800,
+ margin: {
+ l: 260,
+ r: 5,
+ b: 30,
+ t: 30,
+ },
+ xaxis: {
+ ticksuffix: ' ms',
+ side: 'top',
+ color: '#91989c',
+ showline: true,
+ range: [0, maxX * 1.2],
+ },
+ yaxis: {
+ showgrid: false,
+ tickvals: yLabels,
+ ticktext: yTexts,
+ },
+ };
+ };
+
+ const layout = useMemo(
+ () => getSpanDetailLayout(data.gantt, data.ganttMaxX),
+ [data.gantt, data.ganttMaxX]
+ );
+
+ const [currentSpan, setCurrentSpan] = useState('');
+
+ const onClick = (event: any) => {
+ if (!event?.points) return;
+ const point = event.points[0];
+ if (fromApp) {
+ props.openSpanFlyout(point.data.spanId);
+ } else {
+ setCurrentSpan(point.data.spanId);
+ }
+ };
+
+ const renderFilters = useMemo(() => {
+ return spanFilters.map(({ field, value }) => (
+
+ removeSpanFilter(field)}
+ iconOnClickAriaLabel="remove current filter"
+ >
+ {`${field}: ${value}`}
+
+
+ ));
+ }, [spanFilters]);
+
+ const onHover = () => {
+ const dragLayer = document.getElementsByClassName('nsewdrag')?.[0];
+ dragLayer.style.cursor = 'pointer';
+ };
+
+ const onUnhover = () => {
+ const dragLayer = document.getElementsByClassName('nsewdrag')?.[0];
+ dragLayer.style.cursor = '';
+ };
+
+ const toggleOptions = [
+ {
+ id: 'timeline',
+ label: 'Timeline',
+ },
+ {
+ id: 'span_list',
+ label: 'Span list',
+ },
+ ];
+ const [toggleIdSelected, setToggleIdSelected] = useState(toggleOptions[0].id);
+
+ const spanDetailTable = useMemo(
+ () => (
+ {
+ if (fromApp) {
+ props.openSpanFlyout(spanId);
+ } else {
+ setCurrentSpan(spanId);
+ }
+ }}
+ />
+ ),
+ [DSL, setCurrentSpan]
+ );
+
+ return (
+ <>
+
+
+
+
+
+
+ setToggleIdSelected(id)}
+ />
+
+
+ {spanFilters.length > 0 && (
+ <>
+
+
+ {renderFilters}
+
+ >
+ )}
+
+
+ {toggleIdSelected === 'timeline' ? (
+
+ ) : (
+ spanDetailTable
+ )}
+
+
+ {!!currentSpan && (
+ setCurrentSpan('')}
+ addSpanFilter={addSpanFilter}
+ />
+ )}
+ >
+ );
+}
diff --git a/public/components/trace_analytics/components/traces/span_detail_table.tsx b/public/components/trace_analytics/components/traces/span_detail_table.tsx
new file mode 100644
index 0000000000..32108b1c92
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/span_detail_table.tsx
@@ -0,0 +1,174 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable react-hooks/exhaustive-deps */
+
+import { EuiDataGrid, EuiDataGridColumn, EuiLink, EuiText } from '@elastic/eui';
+import _ from 'lodash';
+import moment from 'moment';
+import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import { HttpSetup } from '../../../../../../../src/core/public';
+import { TRACE_ANALYTICS_DATE_FORMAT } from '../../../../../common/constants/trace_analytics';
+import { handleSpansRequest } from '../../requests/traces_request_handler';
+import { nanoToMilliSec, NoMatchMessage } from '../common/helper_functions';
+
+interface SpanDetailTableProps {
+ http: HttpSetup;
+ hiddenColumns: string[];
+ openFlyout: (spanId: string) => void;
+ DSL?: any;
+ setTotal?: (total: number) => void;
+}
+
+export interface SpanSearchParams {
+ from: number;
+ size: number;
+ sortingColumns: Array<{
+ [id: string]: 'asc' | 'desc';
+ }>;
+}
+
+export function SpanDetailTable(props: SpanDetailTableProps) {
+ const [tableParams, setTableParams] = useState({
+ size: 10,
+ page: 0,
+ sortingColumns: [] as Array<{
+ id: string;
+ direction: 'asc' | 'desc';
+ }>,
+ });
+ const [items, setItems] = useState([]);
+ const [total, setTotal] = useState(0);
+
+ useEffect(() => {
+ const spanSearchParams: SpanSearchParams = {
+ from: tableParams.page * tableParams.size,
+ size: tableParams.size,
+ sortingColumns: tableParams.sortingColumns.map(({ id, direction }) => ({ [id]: direction })),
+ };
+ handleSpansRequest(props.http, setItems, setTotal, spanSearchParams, props.DSL);
+ }, [tableParams, props.DSL]);
+
+ useEffect(() => {
+ if (props.setTotal) props.setTotal(total);
+ }, [total]);
+
+ const columns: EuiDataGridColumn[] = [
+ {
+ id: 'spanId',
+ display: 'Span ID',
+ },
+ {
+ id: 'parentSpanId',
+ display: 'Parent span ID',
+ },
+ {
+ id: 'traceId',
+ display: 'Trace ID',
+ },
+ {
+ id: 'traceGroup',
+ display: 'Trace group',
+ },
+ {
+ id: 'serviceName',
+ display: 'Service',
+ },
+ {
+ id: 'name',
+ display: 'Operation',
+ },
+ {
+ id: 'durationInNanos',
+ display: 'Duration',
+ },
+ {
+ id: 'startTime',
+ display: 'Start time',
+ },
+ {
+ id: 'endTime',
+ display: 'End time',
+ },
+ {
+ id: 'status.code',
+ display: 'Errors',
+ },
+ ];
+
+ const [visibleColumns, setVisibleColumns] = useState(() =>
+ columns
+ .filter(({ id }) => props.hiddenColumns.findIndex((column) => column === id) === -1)
+ .map(({ id }) => id)
+ );
+
+ const renderCellValue = useMemo(() => {
+ return ({ rowIndex, columnId }: { rowIndex: number; columnId: string }) => {
+ const adjustedRowIndex = rowIndex - tableParams.page * tableParams.size;
+ if (!items.hasOwnProperty(adjustedRowIndex)) return '-';
+ const value = items[adjustedRowIndex][columnId];
+ if (value == null || value === '') return '-';
+ switch (columnId) {
+ case 'spanId':
+ return props.openFlyout(value)}>{value} ;
+ case 'durationInNanos':
+ return `${_.round(nanoToMilliSec(Math.max(0, value)), 2)} ms`;
+ case 'startTime':
+ case 'endTime':
+ return moment(value).format(TRACE_ANALYTICS_DATE_FORMAT);
+ case 'status.code':
+ return value === 2 ? (
+
+ Yes
+
+ ) : (
+ 'No'
+ );
+
+ default:
+ return value;
+ }
+ };
+ }, [items, tableParams.page, tableParams.size]);
+
+ const onSort = useCallback(
+ (sortingColumns) => {
+ setTableParams({
+ ...tableParams,
+ sortingColumns,
+ });
+ },
+ [setTableParams]
+ );
+
+ const onChangeItemsPerPage = useCallback((size) => setTableParams({ ...tableParams, size }), [
+ tableParams,
+ setTableParams,
+ ]);
+ const onChangePage = useCallback((page) => setTableParams({ ...tableParams, page }), [
+ tableParams,
+ setTableParams,
+ ]);
+
+ return (
+ <>
+
+ {total === 0 && }
+ >
+ );
+}
diff --git a/public/components/trace_analytics/components/traces/trace_view.tsx b/public/components/trace_analytics/components/traces/trace_view.tsx
new file mode 100644
index 0000000000..e839a87ecf
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/trace_view.tsx
@@ -0,0 +1,260 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable react-hooks/exhaustive-deps */
+
+import {
+ EuiButtonIcon,
+ EuiCodeBlock,
+ EuiCopy,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiHorizontalRule,
+ EuiPage,
+ EuiPageBody,
+ EuiPanel,
+ EuiSpacer,
+ EuiText,
+ EuiTitle,
+} from '@elastic/eui';
+import _ from 'lodash';
+import React, { useEffect, useState } from 'react';
+import { TraceAnalyticsCoreDeps } from '../../home';
+import { handleServiceMapRequest } from '../../requests/services_request_handler';
+import {
+ handlePayloadRequest,
+ handleServicesPieChartRequest,
+ handleTraceViewRequest,
+} from '../../requests/traces_request_handler';
+import { filtersToDsl, PanelTitle } from '../common/helper_functions';
+import { ServiceMap, ServiceObject } from '../common/plots/service_map';
+import { ServiceBreakdownPanel } from './service_breakdown_panel';
+import { SpanDetailPanel } from './span_detail_panel';
+
+interface TraceViewProps extends TraceAnalyticsCoreDeps {
+ traceId: string;
+}
+
+export function TraceView(props: TraceViewProps) {
+ const page = 'traceView';
+ const renderTitle = (traceId: string) => {
+ return (
+ <>
+
+
+ {traceId}
+
+
+ >
+ );
+ };
+
+ const renderOverview = (fields: any) => {
+ return (
+
+
+
+
+
+
+
+ Trace ID
+ {fields.trace_id && (
+
+
+
+ {fields.trace_id}
+
+
+
+
+ {(copy) => (
+
+ Click to copy
+
+ )}
+
+
+
+ )}
+
+
+ Trace group name
+
+ {fields.trace_group || '-'}
+
+
+
+
+
+
+
+ Latency
+
+ {fields.latency}
+
+
+
+ Last updated
+
+ {fields.last_updated}
+
+
+
+
+
+
+
+ Errors
+
+ {fields.error_count == null ? (
+ '-'
+ ) : fields.error_count > 0 ? (
+
+ Yes
+
+ ) : (
+ 'No'
+ )}
+
+
+
+
+
+
+ );
+ };
+
+ const [fields, setFields] = useState({});
+ const [serviceBreakdownData, setServiceBreakdownData] = useState([]);
+ const [payloadData, setPayloadData] = useState('');
+ const [colorMap, setColorMap] = useState({});
+ const [ganttData, setGanttData] = useState<{ gantt: any[]; table: any[]; ganttMaxX: number }>({
+ gantt: [],
+ table: [],
+ ganttMaxX: 0,
+ });
+ const [serviceMap, setServiceMap] = useState({});
+ const [traceFilteredServiceMap, setTraceFilteredServiceMap] = useState({});
+ const [serviceMapIdSelected, setServiceMapIdSelected] = useState<
+ 'latency' | 'error_rate' | 'throughput'
+ >('latency');
+
+ const refresh = async () => {
+ const DSL = filtersToDsl([], '', 'now', 'now', page);
+ handleTraceViewRequest(props.traceId, props.http, fields, setFields);
+ handlePayloadRequest(props.traceId, props.http, payloadData, setPayloadData);
+ handleServicesPieChartRequest(props.traceId, props.http, setServiceBreakdownData, setColorMap);
+ handleServiceMapRequest(props.http, DSL, setServiceMap);
+ };
+
+ useEffect(() => {
+ if (!Object.keys(serviceMap).length || !ganttData.table.length) return;
+ const services: any = {};
+ ganttData.table.forEach((service: any) => {
+ if (!services[service.service_name]) {
+ services[service.service_name] = {
+ latency: 0,
+ errors: 0,
+ throughput: 0,
+ };
+ }
+ services[service.service_name].latency += service.latency;
+ if (service.error) services[service.service_name].errors++;
+ services[service.service_name].throughput++;
+ });
+ const filteredServiceMap: ServiceObject = {};
+ Object.entries(services).forEach(([serviceName, service]: [string, any]) => {
+ if (!serviceMap[serviceName]) return;
+ filteredServiceMap[serviceName] = serviceMap[serviceName];
+ filteredServiceMap[serviceName].latency = _.round(service.latency / service.throughput, 2);
+ filteredServiceMap[serviceName].error_rate = _.round(
+ (service.errors / service.throughput) * 100,
+ 2
+ );
+ filteredServiceMap[serviceName].throughput = service.throughput;
+ filteredServiceMap[serviceName].destServices = filteredServiceMap[
+ serviceName
+ ].destServices.filter((destService) => services[destService]);
+ });
+ setTraceFilteredServiceMap(filteredServiceMap);
+ }, [serviceMap, ganttData]);
+
+ useEffect(() => {
+ props.chrome.setBreadcrumbs([
+ ...props.parentBreadcrumbs,
+ {
+ text: 'Trace analytics',
+ href: '#/trace_analytics/home',
+ },
+ {
+ text: 'Traces',
+ href: '#/trace_analytics/traces',
+ },
+ {
+ text: props.traceId,
+ href: `#/trace_analytics/traces/${encodeURIComponent(props.traceId)}`,
+ },
+ ]);
+ refresh();
+ }, []);
+
+ return (
+ <>
+
+
+
+ {renderTitle(props.traceId)}
+
+
+ {renderOverview(fields)}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {payloadData.length > 0 ? (
+
+ {payloadData}
+
+ ) : null}
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/public/components/trace_analytics/components/traces/traces.tsx b/public/components/trace_analytics/components/traces/traces.tsx
new file mode 100644
index 0000000000..9fc2b262d6
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/traces.tsx
@@ -0,0 +1,26 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { EuiBreadcrumb, EuiTitle } from '@elastic/eui';
+import React from 'react';
+import { TraceAnalyticsComponentDeps } from '../../home';
+import { TracesContent } from './traces_content';
+
+export interface TracesProps extends TraceAnalyticsComponentDeps {
+ page: 'traces' | 'app';
+ childBreadcrumbs: EuiBreadcrumb[];
+ traceIdColumnAction: any;
+}
+
+export function Traces(props: TracesProps) {
+ return (
+ <>
+
+ Traces
+
+
+ >
+ );
+}
diff --git a/public/components/trace_analytics/components/traces/traces_content.tsx b/public/components/trace_analytics/components/traces/traces_content.tsx
new file mode 100644
index 0000000000..b71a243341
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/traces_content.tsx
@@ -0,0 +1,88 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable react-hooks/exhaustive-deps */
+
+import { EuiSpacer, PropertySort } from '@elastic/eui';
+import React, { useEffect, useState } from 'react';
+import { handleTracesRequest } from '../../requests/traces_request_handler';
+import { getValidFilterFields } from '../common/filters/filter_helpers';
+import { filtersToDsl } from '../common/helper_functions';
+import { SearchBar } from '../common/search_bar';
+import { TracesProps } from './traces';
+import { TracesTable } from './traces_table';
+
+export function TracesContent(props: TracesProps) {
+ const {
+ page,
+ http,
+ chrome,
+ query,
+ filters,
+ appConfigs,
+ startTime,
+ endTime,
+ indicesExist,
+ parentBreadcrumbs,
+ childBreadcrumbs,
+ traceIdColumnAction,
+ setQuery,
+ setFilters,
+ setStartTime,
+ setEndTime,
+ } = props;
+ const [tableItems, setTableItems] = useState([]);
+ const [redirect, setRedirect] = useState(true);
+ const [loading, setLoading] = useState(false);
+
+ useEffect(() => {
+ chrome.setBreadcrumbs([...parentBreadcrumbs, ...childBreadcrumbs]);
+ const validFilters = getValidFilterFields('traces');
+ setFilters([
+ ...filters.map((filter) => ({
+ ...filter,
+ locked: validFilters.indexOf(filter.field) === -1,
+ })),
+ ]);
+ setRedirect(false);
+ }, []);
+
+ useEffect(() => {
+ if (!redirect && indicesExist) refresh();
+ }, [filters, appConfigs]);
+
+ const refresh = async (sort?: PropertySort) => {
+ setLoading(true);
+ const DSL = filtersToDsl(filters, query, startTime, endTime, page, appConfigs);
+ const timeFilterDSL = filtersToDsl([], '', startTime, endTime, page);
+ await handleTracesRequest(http, DSL, timeFilterDSL, tableItems, setTableItems, sort);
+ setLoading(false);
+ };
+
+ return (
+ <>
+
+
+
+ >
+ );
+}
diff --git a/public/components/trace_analytics/components/traces/traces_table.tsx b/public/components/trace_analytics/components/traces/traces_table.tsx
new file mode 100644
index 0000000000..40f1396067
--- /dev/null
+++ b/public/components/trace_analytics/components/traces/traces_table.tsx
@@ -0,0 +1,218 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable react-hooks/exhaustive-deps */
+
+import {
+ EuiButtonIcon,
+ EuiCopy,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiHorizontalRule,
+ EuiInMemoryTable,
+ EuiLink,
+ EuiPanel,
+ EuiSpacer,
+ EuiTableFieldDataColumnType,
+ EuiText,
+ PropertySort,
+} from '@elastic/eui';
+import _ from 'lodash';
+import React, { useMemo, useState } from 'react';
+import { TRACES_MAX_NUM } from '../../../../../common/constants/trace_analytics';
+import {
+ MissingConfigurationMessage,
+ NoMatchMessage,
+ PanelTitle,
+} from '../common/helper_functions';
+
+interface TracesTableProps {
+ items: any[];
+ refresh: (sort?: PropertySort) => void;
+ indicesExist: boolean;
+ loading: boolean;
+ traceIdColumnAction: any;
+}
+
+export function TracesTable(props: TracesTableProps) {
+ const { items, refresh, indicesExist, loading, traceIdColumnAction } = props;
+ const renderTitleBar = (totalItems?: number) => {
+ return (
+
+
+
+
+
+ );
+ };
+
+ const columns = useMemo(
+ () =>
+ [
+ {
+ field: 'trace_id',
+ name: 'Trace ID',
+ align: 'left',
+ sortable: true,
+ truncateText: true,
+ render: (item) => (
+
+
+ traceIdColumnAction(item)}>
+ {item.length < 24 ? (
+ item
+ ) : (
+ {_.truncate(item, { length: 24 })}
+ )}
+
+
+
+
+ {(copy) => (
+
+ Click to copy
+
+ )}
+
+
+
+
+ ),
+ },
+ {
+ field: 'trace_group',
+ name: 'Trace group',
+ align: 'left',
+ sortable: true,
+ truncateText: true,
+ render: (item) =>
+ item ? (
+
+ {item.length < 36 ? (
+ item
+ ) : (
+ {_.truncate(item, { length: 36 })}
+ )}
+
+ ) : (
+ '-'
+ ),
+ },
+ {
+ field: 'latency',
+ name: 'Latency (ms)',
+ align: 'right',
+ sortable: true,
+ truncateText: true,
+ },
+ {
+ field: 'percentile_in_trace_group',
+ name: (
+ <>
+ Percentile in trace group
+ {/* trace group
*/}
+ >
+ ),
+ align: 'right',
+ sortable: true,
+ render: (item) =>
+ item === 0 || item ? {`${_.round(item, 2)}th`} : '-',
+ },
+ {
+ field: 'error_count',
+ name: 'Errors',
+ align: 'right',
+ sortable: true,
+ render: (item) =>
+ item == null ? (
+ '-'
+ ) : item > 0 ? (
+
+ Yes
+
+ ) : (
+ 'No'
+ ),
+ },
+ {
+ field: 'last_updated',
+ name: 'Last updated',
+ align: 'left',
+ sortable: true,
+ render: (item) => (item === 0 || item ? item : '-'),
+ },
+ ] as Array>,
+ [items]
+ );
+
+ const titleBar = useMemo(() => renderTitleBar(items?.length), [items]);
+
+ const [sorting, setSorting] = useState<{ sort: PropertySort }>({
+ sort: {
+ field: 'trace_id',
+ direction: 'asc',
+ },
+ });
+
+ const onTableChange = async ({ currPage, sort }: { currPage: any; sort: any }) => {
+ if (typeof sort?.field !== 'string') return;
+
+ // maps table column key to DSL aggregation name
+ const fieldMappings = {
+ trace_id: '_key',
+ trace_group: null,
+ latency: 'latency',
+ percentile_in_trace_group: null,
+ error_count: 'error_count',
+ last_updated: 'last_updated',
+ };
+ const field = fieldMappings[sort.field as keyof typeof fieldMappings];
+ if (!field || items?.length < TRACES_MAX_NUM) {
+ setSorting({ sort });
+ return;
+ }
+
+ // using await when sorting the default sorted field leads to a bug in UI
+ if (sort.field === 'trace_id') {
+ refresh({ ...sort, field });
+ setSorting({ sort });
+ return;
+ }
+
+ await refresh({ ...sort, field });
+ setSorting({ sort });
+ };
+
+ return (
+ <>
+
+ {titleBar}
+
+
+ {items?.length > 0 ? (
+
+ ) : indicesExist ? (
+
+ ) : (
+
+ )}
+
+ >
+ );
+}
diff --git a/public/components/trace_analytics/home.tsx b/public/components/trace_analytics/home.tsx
new file mode 100644
index 0000000000..ab04874366
--- /dev/null
+++ b/public/components/trace_analytics/home.tsx
@@ -0,0 +1,202 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { EuiLink } from '@elastic/eui';
+import React, { useEffect, useState } from 'react';
+import { Route, RouteComponentProps } from 'react-router-dom';
+import {
+ ChromeBreadcrumb,
+ ChromeStart,
+ CoreStart,
+ HttpStart,
+} from '../../../../../src/core/public';
+import { ObservabilitySideBar } from '../common/side_nav';
+import { FilterType } from './components/common/filters/filters';
+import { SearchBarProps } from './components/common/search_bar';
+import { Dashboard } from './components/dashboard';
+import { Services, ServiceView } from './components/services';
+import { Traces, TraceView } from './components/traces';
+import { handleIndicesExistRequest } from './requests/request_handler';
+
+export interface TraceAnalyticsCoreDeps {
+ parentBreadcrumbs: ChromeBreadcrumb[];
+ http: HttpStart;
+ chrome: ChromeStart;
+}
+
+interface HomeProps extends RouteComponentProps, TraceAnalyticsCoreDeps {}
+
+export interface TraceAnalyticsComponentDeps extends TraceAnalyticsCoreDeps, SearchBarProps {
+ indicesExist: boolean;
+}
+
+export const Home = (props: HomeProps) => {
+ const [indicesExist, setIndicesExist] = useState(true);
+ const storedFilters = sessionStorage.getItem('TraceAnalyticsFilters');
+ const [query, setQuery] = useState(sessionStorage.getItem('TraceAnalyticsQuery') || '');
+ const [filters, setFilters] = useState(
+ storedFilters ? JSON.parse(storedFilters) : []
+ );
+ const [startTime, setStartTime] = useState(
+ sessionStorage.getItem('TraceAnalyticsStartTime') || 'now-5m'
+ );
+ const [endTime, setEndTime] = useState(
+ sessionStorage.getItem('TraceAnalyticsEndTime') || 'now'
+ );
+
+ const setFiltersWithStorage = (newFilters: FilterType[]) => {
+ setFilters(newFilters);
+ sessionStorage.setItem('TraceAnalyticsFilters', JSON.stringify(newFilters));
+ };
+ const setQueryWithStorage = (newQuery: string) => {
+ setQuery(newQuery);
+ sessionStorage.setItem('TraceAnalyticsQuery', newQuery);
+ };
+ const setStartTimeWithStorage = (newStartTime: string) => {
+ setStartTime(newStartTime);
+ sessionStorage.setItem('TraceAnalyticsStartTime', newStartTime);
+ };
+ const setEndTimeWithStorage = (newEndTime: string) => {
+ setEndTime(newEndTime);
+ sessionStorage.setItem('TraceAnalyticsEndTime', newEndTime);
+ };
+
+ useEffect(() => {
+ handleIndicesExistRequest(props.http, setIndicesExist);
+ }, []);
+
+ const dashboardBreadcrumbs = [
+ {
+ text: 'Trace analytics',
+ href: '#/trace_analytics/home',
+ },
+ {
+ text: 'Dashboard',
+ href: '#/trace_analytics/home',
+ },
+ ];
+
+ const serviceBreadcrumbs = [
+ {
+ text: 'Trace analytics',
+ href: '#/trace_analytics/home',
+ },
+ {
+ text: 'Services',
+ href: '#/trace_analytics/services',
+ },
+ ];
+
+ const traceBreadcrumbs = [
+ {
+ text: 'Trace analytics',
+ href: '#/trace_analytics/home',
+ },
+ {
+ text: 'Traces',
+ href: '#/trace_analytics/traces',
+ },
+ ];
+
+ const nameColumnAction = (item: any) =>
+ location.assign(`#/trace_analytics/services/${encodeURIComponent(item)}`);
+
+ const traceColumnAction = () => location.assign('#/trace_analytics/traces');
+
+ const traceIdColumnAction = (item: any) =>
+ location.assign(`#/trace_analytics/traces/${encodeURIComponent(item)}`);
+
+ const commonProps: TraceAnalyticsComponentDeps = {
+ parentBreadcrumbs: props.parentBreadcrumbs,
+ http: props.http,
+ chrome: props.chrome,
+ query,
+ setQuery: setQueryWithStorage,
+ filters,
+ appConfigs: [],
+ setFilters: setFiltersWithStorage,
+ startTime,
+ setStartTime: setStartTimeWithStorage,
+ endTime,
+ setEndTime: setEndTimeWithStorage,
+ indicesExist,
+ };
+
+ return (
+ <>
+ (
+
+
+
+ )}
+ />
+ (
+
+
+
+ )}
+ />
+ (
+
+ )}
+ />
+ (
+
+
+
+ )}
+ />
+ (
+ {
+ for (const addedFilter of filters) {
+ if (
+ addedFilter.field === filter.field &&
+ addedFilter.operator === filter.operator &&
+ addedFilter.value === filter.value
+ ) {
+ return;
+ }
+ }
+ const newFilters = [...filters, filter];
+ setFiltersWithStorage(newFilters);
+ }}
+ />
+ )}
+ />
+ >
+ );
+};
diff --git a/public/components/trace_analytics/images/unmatched_node.png b/public/components/trace_analytics/images/unmatched_node.png
new file mode 100644
index 0000000000..7c576b7273
Binary files /dev/null and b/public/components/trace_analytics/images/unmatched_node.png differ
diff --git a/public/components/trace_analytics/index.scss b/public/components/trace_analytics/index.scss
new file mode 100644
index 0000000000..90dca4b7d9
--- /dev/null
+++ b/public/components/trace_analytics/index.scss
@@ -0,0 +1,54 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+@import '../../../node_modules/vis-network/dist/dist/vis-network.min.css';
+
+.overview-title {
+ color: '#333333';
+ font-weight: 370;
+}
+
+.overview-content {
+ font-weight: 430;
+}
+
+.panel-title {
+ color: '#3f3f3f';
+ font-weight: 500;
+}
+
+.panel-title-count {
+ color: '#8a9596';
+ font-weight: 300;
+}
+
+div.vis-network > div.vis-tooltip {
+ color: #f4f5f5;
+ background-color: #3d4652;
+ opacity: 0.9;
+ padding: 5px;
+ font-size: small;
+ p {
+ padding: 5px;
+ }
+}
+
+th[data-test-subj^='tableHeaderCell_dashboard_trace_group_name'],
+th[data-test-subj^='tableHeaderCell_dashboard_latency_variance'],
+th[data-test-subj^='tableHeaderCell_dashboard_average_latency'],
+th[data-test-subj^='tableHeaderCell_dashboard_error_rate'],
+th[data-test-subj^='tableHeaderCell_dashboard_traces'] {
+ svg[aria-label^="Sorted in"] {
+ margin-top: -20px;
+ }
+}
+
+th[data-test-subj^='tableHeaderCell_dashboard_latency_variance'] {
+ svg[aria-label^="Sorted in"] {
+ margin-left: -16px;
+ position: relative;
+ left: 10px;
+ }
+}
\ No newline at end of file
diff --git a/public/components/trace_analytics/requests/dashboard_request_handler.ts b/public/components/trace_analytics/requests/dashboard_request_handler.ts
new file mode 100644
index 0000000000..322ebf8ed5
--- /dev/null
+++ b/public/components/trace_analytics/requests/dashboard_request_handler.ts
@@ -0,0 +1,187 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import _ from 'lodash';
+import moment from 'moment';
+import { TRACE_ANALYTICS_PLOTS_DATE_FORMAT } from '../../../../common/constants/trace_analytics';
+import { fixedIntervalToMilli, nanoToMilliSec } from '../components/common/helper_functions';
+import {
+ getDashboardQuery,
+ getDashboardThroughputPltQuery,
+ getDashboardTraceGroupPercentiles,
+ getErrorRatePltQuery,
+ getLatencyTrendQuery,
+} from './queries/dashboard_queries';
+import { handleDslRequest } from './request_handler';
+
+export const handleDashboardRequest = async (
+ http,
+ DSL,
+ timeFilterDSL,
+ latencyTrendDSL,
+ items,
+ setItems,
+ setPercentileMap?
+) => {
+ // latency_variance should only be affected by timefilter
+ const latencyVariances = await handleDslRequest(
+ http,
+ timeFilterDSL,
+ getDashboardTraceGroupPercentiles()
+ )
+ .then((response) => {
+ const map: any = {};
+ response.aggregations.trace_group.buckets.forEach((traceGroup) => {
+ map[traceGroup.key] = Object.values(
+ traceGroup.latency_variance_nanos.values
+ ).map((nano: number) => _.round(nanoToMilliSec(Math.max(0, nano)), 2));
+ });
+ return map;
+ })
+ .catch((error) => console.error(error));
+ if (setPercentileMap) setPercentileMap(latencyVariances);
+
+ const latencyTrends = await handleDslRequest(http, latencyTrendDSL, getLatencyTrendQuery())
+ .then((response) => {
+ const map: any = {};
+ response.aggregations.trace_group_name.buckets.map((bucket) => {
+ const latencyTrend = bucket.group_by_hour.buckets
+ .slice(-24)
+ .filter((bucket) => bucket.average_latency?.value || bucket.average_latency?.value === 0);
+ const values = {
+ x: latencyTrend.map((bucket) => bucket.key),
+ y: latencyTrend.map((bucket) => bucket.average_latency?.value || 0),
+ };
+ const latencyTrendData =
+ values.x?.length > 0
+ ? {
+ '24_hour_latency_trend': {
+ trendData: [
+ {
+ ...values,
+ type: 'scatter',
+ mode: 'lines',
+ hoverinfo: 'none',
+ line: {
+ color: '#000000',
+ width: 1,
+ },
+ },
+ ],
+ popoverData: [
+ {
+ ...values,
+ type: 'scatter',
+ mode: 'lines+markers',
+ hovertemplate: '%{x} Average latency: %{y} ',
+ hoverlabel: {
+ bgcolor: '#d7c2ff',
+ },
+ marker: {
+ color: '#987dcb',
+ size: 8,
+ },
+ line: {
+ color: '#987dcb',
+ size: 2,
+ },
+ },
+ ],
+ },
+ }
+ : {};
+ map[bucket.key] = latencyTrendData;
+ });
+ return map;
+ })
+ .catch((error) => console.error(error));
+
+ await handleDslRequest(http, DSL, getDashboardQuery())
+ .then((response) => {
+ return Promise.all(
+ response.aggregations.trace_group_name.buckets.map((bucket) => {
+ const latencyTrend = latencyTrends?.[bucket.key] || {};
+ return {
+ dashboard_trace_group_name: bucket.key,
+ dashboard_average_latency: bucket.average_latency?.value,
+ dashboard_traces: bucket.trace_count.value,
+ dashboard_latency_variance: latencyVariances[bucket.key],
+ dashboard_error_rate: bucket.error_rate.value,
+ ...latencyTrend,
+ };
+ })
+ );
+ })
+ .then((newItems) => {
+ setItems(newItems);
+ })
+ .catch((error) => console.error(error));
+};
+
+export const handleDashboardThroughputPltRequest = (http, DSL, fixedInterval, items, setItems) => {
+ return handleDslRequest(http, DSL, getDashboardThroughputPltQuery(fixedInterval))
+ .then((response) => {
+ const buckets = response.aggregations.throughput.buckets;
+ const texts = buckets.map(
+ (bucket) =>
+ `${moment(bucket.key).format(TRACE_ANALYTICS_PLOTS_DATE_FORMAT)} - ${moment(
+ bucket.key + fixedIntervalToMilli(fixedInterval)
+ ).format(TRACE_ANALYTICS_PLOTS_DATE_FORMAT)}`
+ );
+ const newItems =
+ buckets.length > 0
+ ? [
+ {
+ x: buckets.map((bucket) => bucket.key),
+ y: buckets.map((bucket) => bucket.trace_count.value),
+ marker: {
+ color: 'rgb(171, 211, 240)',
+ },
+ type: 'bar',
+ customdata: texts,
+ hoverlabel: {
+ align: 'left',
+ },
+ hovertemplate: '%{customdata} Throughput: %{y:,} ',
+ },
+ ]
+ : [];
+ setItems({ items: newItems, fixedInterval: fixedInterval });
+ })
+ .catch((error) => console.error(error));
+};
+
+export const handleDashboardErrorRatePltRequest = (http, DSL, fixedInterval, items, setItems) => {
+ return handleDslRequest(http, DSL, getErrorRatePltQuery(fixedInterval))
+ .then((response) => {
+ const buckets = response.aggregations.error_rate.buckets;
+ const texts = buckets.map(
+ (bucket) =>
+ `${moment(bucket.key).format(TRACE_ANALYTICS_PLOTS_DATE_FORMAT)} - ${moment(
+ bucket.key + fixedIntervalToMilli(fixedInterval)
+ ).format(TRACE_ANALYTICS_PLOTS_DATE_FORMAT)}`
+ );
+ const newItems =
+ buckets.length > 0
+ ? [
+ {
+ x: buckets.map((bucket) => bucket.key),
+ y: buckets.map((bucket) => _.round(bucket.error_rate?.value || 0, 2)),
+ marker: {
+ color: '#fad963',
+ },
+ type: 'bar',
+ customdata: texts,
+ hoverlabel: {
+ align: 'left',
+ },
+ hovertemplate: '%{customdata} Error rate: %{y} ',
+ },
+ ]
+ : [];
+ setItems({ items: newItems, fixedInterval: fixedInterval });
+ })
+ .catch((error) => console.error(error));
+};
diff --git a/public/components/trace_analytics/requests/queries/dashboard_queries.ts b/public/components/trace_analytics/requests/queries/dashboard_queries.ts
new file mode 100644
index 0000000000..bdc9111ac1
--- /dev/null
+++ b/public/components/trace_analytics/requests/queries/dashboard_queries.ts
@@ -0,0 +1,286 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const getDashboardQuery = () => {
+ const query = {
+ size: 0,
+ query: {
+ bool: {
+ must: [],
+ filter: [],
+ should: [],
+ must_not: [],
+ },
+ },
+ aggs: {
+ trace_group_name: {
+ terms: {
+ field: 'traceGroup',
+ size: 10000,
+ },
+ aggs: {
+ average_latency: {
+ scripted_metric: {
+ init_script: 'state.traceIdToLatencyMap = [:];',
+ map_script: `
+ if (doc.containsKey('traceGroupFields.durationInNanos') && !doc['traceGroupFields.durationInNanos'].empty) {
+ def traceId = doc['traceId'].value;
+ if (!state.traceIdToLatencyMap.containsKey(traceId)) {
+ state.traceIdToLatencyMap[traceId] = doc['traceGroupFields.durationInNanos'].value;
+ }
+ }
+ `,
+ combine_script: 'return state.traceIdToLatencyMap',
+ reduce_script: `
+ def seenTraceIdsMap = [:];
+ def totalLatency = 0.0;
+ def traceCount = 0.0;
+
+ for (s in states) {
+ if (s == null) {
+ continue;
+ }
+
+ for (entry in s.entrySet()) {
+ def traceId = entry.getKey();
+ def traceLatency = entry.getValue();
+ if (!seenTraceIdsMap.containsKey(traceId)) {
+ seenTraceIdsMap[traceId] = true;
+ totalLatency += traceLatency;
+ traceCount++;
+ }
+ }
+ }
+
+ def average_latency_nanos = totalLatency / traceCount;
+ return Math.round(average_latency_nanos / 10000) / 100.0;
+ `,
+ },
+ },
+ trace_count: {
+ cardinality: {
+ field: 'traceId',
+ },
+ },
+ error_count: {
+ filter: {
+ term: {
+ 'traceGroupFields.statusCode': '2',
+ },
+ },
+ aggs: {
+ trace_count: {
+ cardinality: {
+ field: 'traceId',
+ },
+ },
+ },
+ },
+ error_rate: {
+ bucket_script: {
+ buckets_path: {
+ total: 'trace_count.value',
+ errors: 'error_count>trace_count.value',
+ },
+ script: 'params.errors / params.total * 100',
+ },
+ },
+ },
+ },
+ },
+ };
+ return query;
+};
+
+export const getLatencyTrendQuery = () => {
+ const query = {
+ size: 0,
+ query: {
+ bool: {
+ must: [],
+ filter: [],
+ should: [],
+ must_not: [],
+ },
+ },
+ aggs: {
+ trace_group_name: {
+ terms: {
+ field: 'traceGroup',
+ size: 10000,
+ },
+ aggs: {
+ group_by_hour: {
+ date_histogram: {
+ field: 'endTime',
+ calendar_interval: 'hour',
+ },
+ aggs: {
+ average_latency: {
+ scripted_metric: {
+ init_script: 'state.traceIdToLatencyMap = [:];',
+ map_script: `
+ if (doc.containsKey('traceGroupFields.durationInNanos') && !doc['traceGroupFields.durationInNanos'].empty) {
+ def traceId = doc['traceId'].value;
+ if (!state.traceIdToLatencyMap.containsKey(traceId)) {
+ state.traceIdToLatencyMap[traceId] = doc['traceGroupFields.durationInNanos'].value;
+ }
+ }
+ `,
+ combine_script: 'return state.traceIdToLatencyMap',
+ reduce_script: `
+ def seenTraceIdsMap = [:];
+ def totalLatency = 0.0;
+ def traceCount = 0.0;
+
+ for (s in states) {
+ if (s == null) {
+ continue;
+ }
+
+ for (entry in s.entrySet()) {
+ def traceId = entry.getKey();
+ def traceLatency = entry.getValue();
+ if (!seenTraceIdsMap.containsKey(traceId)) {
+ seenTraceIdsMap[traceId] = true;
+ totalLatency += traceLatency;
+ traceCount++;
+ }
+ }
+ }
+
+ def average_latency_nanos = totalLatency / traceCount;
+ return Math.round(average_latency_nanos / 10000) / 100.0;
+ `,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ };
+ return query;
+};
+
+export const getDashboardTraceGroupPercentiles = () => {
+ return {
+ size: 0,
+ query: {
+ bool: {
+ must: [
+ {
+ term: {
+ parentSpanId: {
+ value: '',
+ },
+ },
+ },
+ ],
+ filter: [],
+ should: [],
+ must_not: [],
+ },
+ },
+ aggs: {
+ trace_group: {
+ terms: {
+ field: 'traceGroup',
+ },
+ aggs: {
+ latency_variance_nanos: {
+ percentiles: {
+ field: 'traceGroupFields.durationInNanos',
+ percents: [0, 95, 100],
+ },
+ },
+ },
+ },
+ },
+ };
+};
+
+export const getErrorRatePltQuery = (fixedInterval) => {
+ const query: any = {
+ size: 0,
+ query: {
+ bool: {
+ must: [],
+ filter: [],
+ should: [],
+ must_not: [],
+ },
+ },
+ aggs: {
+ error_rate: {
+ date_histogram: {
+ field: 'startTime',
+ fixed_interval: fixedInterval,
+ },
+ aggs: {
+ error_count: {
+ filter: {
+ term: {
+ 'traceGroupFields.statusCode': '2',
+ },
+ },
+ aggs: {
+ trace_count: {
+ cardinality: {
+ field: 'traceId',
+ },
+ },
+ },
+ },
+ trace_count: {
+ cardinality: {
+ field: 'traceId',
+ },
+ },
+ error_rate: {
+ bucket_script: {
+ buckets_path: {
+ total: 'trace_count.value',
+ errors: 'error_count>trace_count.value',
+ },
+ script: 'params.errors / params.total * 100',
+ },
+ },
+ },
+ },
+ },
+ };
+ return query;
+};
+
+export const getDashboardThroughputPltQuery = (fixedInterval) => {
+ const query: any = {
+ size: 0,
+ query: {
+ bool: {
+ must: [],
+ filter: [],
+ should: [],
+ must_not: [],
+ },
+ },
+ aggs: {
+ throughput: {
+ date_histogram: {
+ field: 'startTime',
+ fixed_interval: fixedInterval,
+ },
+ aggs: {
+ trace_count: {
+ cardinality: {
+ field: 'traceId',
+ },
+ },
+ },
+ },
+ },
+ };
+ return query;
+};
diff --git a/public/components/trace_analytics/requests/queries/services_queries.ts b/public/components/trace_analytics/requests/queries/services_queries.ts
new file mode 100644
index 0000000000..327e029d42
--- /dev/null
+++ b/public/components/trace_analytics/requests/queries/services_queries.ts
@@ -0,0 +1,318 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ DATA_PREPPER_SERVICE_INDEX_NAME,
+ SERVICE_MAP_MAX_EDGES,
+ SERVICE_MAP_MAX_NODES,
+} from '../../../../../common/constants/trace_analytics';
+import { getServiceMapTargetResources } from '../../components/common/helper_functions';
+import { ServiceObject } from '../../components/common/plots/service_map';
+
+export const getServicesQuery = (serviceName: string | undefined, DSL?: any) => {
+ const query = {
+ size: 0,
+ query: {
+ bool: {
+ must: [],
+ filter: [],
+ should: [],
+ must_not: [],
+ },
+ },
+ aggs: {
+ service: {
+ terms: {
+ field: 'serviceName',
+ size: 10000,
+ },
+ aggs: {
+ trace_count: {
+ cardinality: {
+ field: 'traceId',
+ },
+ },
+ },
+ },
+ },
+ };
+ if (serviceName) {
+ query.query.bool.must.push({
+ term: {
+ serviceName,
+ },
+ });
+ }
+ DSL?.custom?.serviceNames?.map((service: string) => {
+ query.query.bool.must.push({
+ term: {
+ serviceName: service,
+ },
+ });
+ });
+ DSL?.custom?.serviceNamesExclude?.map((service: string) => {
+ query.query.bool.must_not.push({
+ term: {
+ serviceName: service,
+ },
+ });
+ });
+ return query;
+};
+
+export const getRelatedServicesQuery = (serviceName: string) => {
+ const query = {
+ size: 0,
+ query: {
+ bool: {
+ must: [],
+ filter: [],
+ should: [],
+ must_not: [],
+ },
+ },
+ aggs: {
+ traces: {
+ terms: {
+ field: 'traceId',
+ size: 10000,
+ },
+ aggs: {
+ all_services: {
+ terms: {
+ field: 'serviceName',
+ size: 10000,
+ },
+ },
+ service: {
+ filter: {
+ bool: {
+ must: [
+ {
+ term: {
+ serviceName,
+ },
+ },
+ ],
+ must_not: [],
+ },
+ },
+ },
+ },
+ },
+ },
+ };
+ return query;
+};
+
+export const getServiceNodesQuery = () => {
+ return {
+ index: DATA_PREPPER_SERVICE_INDEX_NAME,
+ size: 0,
+ query: {
+ bool: {
+ must: [],
+ filter: [],
+ should: [],
+ must_not: [],
+ },
+ },
+ aggs: {
+ service_name: {
+ terms: {
+ field: 'serviceName',
+ size: SERVICE_MAP_MAX_NODES,
+ },
+ aggs: {
+ trace_group: {
+ terms: {
+ field: 'traceGroupName',
+ size: SERVICE_MAP_MAX_EDGES,
+ },
+ aggs: {
+ target_resource: {
+ terms: {
+ field: 'target.resource',
+ size: SERVICE_MAP_MAX_EDGES,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ };
+};
+
+export const getServiceEdgesQuery = (source: 'destination' | 'target') => {
+ return {
+ index: DATA_PREPPER_SERVICE_INDEX_NAME,
+ size: 0,
+ query: {
+ bool: {
+ must: [],
+ filter: [],
+ should: [],
+ must_not: [],
+ },
+ },
+ aggs: {
+ service_name: {
+ terms: {
+ field: 'serviceName',
+ size: SERVICE_MAP_MAX_EDGES,
+ },
+ aggs: {
+ resource: {
+ terms: {
+ field: `${source}.resource`,
+ size: SERVICE_MAP_MAX_EDGES,
+ },
+ aggs: {
+ domain: {
+ terms: {
+ field: `${source}.domain`,
+ size: SERVICE_MAP_MAX_EDGES,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ };
+};
+
+export const getServiceMetricsQuery = (DSL: any, serviceNames: string[], map: ServiceObject) => {
+ const traceGroupFilter = new Set(
+ DSL?.query?.bool.must
+ .filter((must: any) => must.term?.['traceGroup'])
+ .map((must: any) => must.term.traceGroup) || []
+ );
+
+ const targetResource =
+ traceGroupFilter.size > 0
+ ? [].concat(
+ ...[].concat(
+ ...serviceNames.map((service) =>
+ map[service].traceGroups
+ .filter((traceGroup) => traceGroupFilter.has(traceGroup.traceGroup))
+ .map((traceGroup) => traceGroup.targetResource)
+ )
+ )
+ )
+ : [].concat(...Object.keys(map).map((service) => getServiceMapTargetResources(map, service)));
+ const query: any = {
+ size: 0,
+ query: {
+ bool: {
+ must: [],
+ should: [],
+ must_not: [],
+ filter: [
+ {
+ terms: {
+ serviceName: serviceNames,
+ },
+ },
+ {
+ bool: {
+ should: [
+ {
+ bool: {
+ filter: [
+ {
+ bool: {
+ must_not: {
+ term: {
+ parentSpanId: {
+ value: '',
+ },
+ },
+ },
+ },
+ },
+ {
+ terms: {
+ name: targetResource,
+ },
+ },
+ ],
+ },
+ },
+ {
+ bool: {
+ must: {
+ term: {
+ parentSpanId: {
+ value: '',
+ },
+ },
+ },
+ },
+ },
+ ],
+ adjust_pure_negative: true,
+ boost: 1,
+ },
+ },
+ ],
+ },
+ },
+ aggregations: {
+ service_name: {
+ terms: {
+ field: 'serviceName',
+ size: SERVICE_MAP_MAX_NODES,
+ min_doc_count: 1,
+ shard_min_doc_count: 0,
+ show_term_doc_count_error: false,
+ order: [
+ {
+ _count: 'desc',
+ },
+ {
+ _key: 'asc',
+ },
+ ],
+ },
+ aggregations: {
+ average_latency_nanos: {
+ avg: {
+ field: 'durationInNanos',
+ },
+ },
+ average_latency: {
+ bucket_script: {
+ buckets_path: {
+ count: '_count',
+ latency: 'average_latency_nanos.value',
+ },
+ script: 'Math.round(params.latency / 10000) / 100.0',
+ },
+ },
+ error_count: {
+ filter: {
+ term: {
+ 'status.code': '2',
+ },
+ },
+ },
+ error_rate: {
+ bucket_script: {
+ buckets_path: {
+ total: '_count',
+ errors: 'error_count._count',
+ },
+ script: 'params.errors / params.total * 100',
+ },
+ },
+ },
+ },
+ },
+ };
+ if (DSL.custom?.timeFilter.length > 0) query.query.bool.must.push(...DSL.custom.timeFilter);
+ return query;
+};
diff --git a/public/components/trace_analytics/requests/queries/traces_queries.ts b/public/components/trace_analytics/requests/queries/traces_queries.ts
new file mode 100644
index 0000000000..89d63a42e7
--- /dev/null
+++ b/public/components/trace_analytics/requests/queries/traces_queries.ts
@@ -0,0 +1,308 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { PropertySort } from '@elastic/eui';
+import { TRACES_MAX_NUM } from '../../../../../common/constants/trace_analytics';
+import { SpanSearchParams } from '../../components/traces/span_detail_table';
+
+export const getTraceGroupPercentilesQuery = () => {
+ const query: any = {
+ size: 0,
+ query: {
+ bool: {
+ must: [
+ {
+ term: {
+ parentSpanId: {
+ value: '',
+ },
+ },
+ },
+ ],
+ filter: [],
+ should: [],
+ must_not: [],
+ },
+ },
+ aggs: {
+ trace_group_name: {
+ terms: {
+ field: 'name',
+ size: 10000,
+ },
+ aggs: {
+ percentiles: {
+ percentiles: {
+ field: 'durationInNanos',
+ percents: Array.from({ length: 101 }, (v, i) => i),
+ },
+ },
+ },
+ },
+ },
+ };
+ return query;
+};
+
+export const getTracesQuery = (traceId: string = '', sort?: PropertySort) => {
+ const field = sort?.field || '_key';
+ const direction = sort?.direction || 'asc';
+ const query: any = {
+ size: 0,
+ query: {
+ bool: {
+ must: [],
+ filter: [],
+ should: [],
+ must_not: [],
+ },
+ },
+ aggs: {
+ traces: {
+ terms: {
+ field: 'traceId',
+ size: TRACES_MAX_NUM,
+ order: {
+ [field]: direction,
+ },
+ },
+ aggs: {
+ latency: {
+ max: {
+ script: {
+ source: `
+ if (doc.containsKey('traceGroupFields.durationInNanos') && !doc['traceGroupFields.durationInNanos'].empty) {
+ return Math.round(doc['traceGroupFields.durationInNanos'].value / 10000) / 100.0
+ }
+
+ return 0
+ `,
+ lang: 'painless',
+ },
+ },
+ },
+ trace_group: {
+ terms: {
+ field: 'traceGroup',
+ size: 1,
+ },
+ },
+ error_count: {
+ filter: {
+ term: {
+ 'traceGroupFields.statusCode': '2',
+ },
+ },
+ },
+ last_updated: {
+ max: {
+ field: 'traceGroupFields.endTime',
+ },
+ },
+ },
+ },
+ },
+ };
+ if (traceId) {
+ query.query.bool.must.push({
+ term: {
+ traceId,
+ },
+ });
+ }
+ return query;
+};
+
+export const getServiceBreakdownQuery = (traceId: string) => {
+ const query = {
+ size: 0,
+ query: {
+ bool: {
+ must: [
+ {
+ term: {
+ traceId,
+ },
+ },
+ ],
+ filter: [],
+ should: [],
+ must_not: [],
+ },
+ },
+ aggs: {
+ service_type: {
+ terms: {
+ field: 'serviceName',
+ order: [
+ {
+ total_latency_nanos: 'desc',
+ },
+ ],
+ },
+ aggs: {
+ total_latency_nanos: {
+ sum: {
+ field: 'durationInNanos',
+ },
+ },
+ total_latency: {
+ bucket_script: {
+ buckets_path: {
+ count: '_count',
+ latency: 'total_latency_nanos.value',
+ },
+ script: 'Math.round(params.latency / 10000) / 100.0',
+ },
+ },
+ },
+ },
+ },
+ };
+ return query;
+};
+
+export const getSpanDetailQuery = (traceId: string, size = 3000) => {
+ const query = {
+ size,
+ query: {
+ bool: {
+ must: [
+ {
+ term: {
+ traceId,
+ },
+ },
+ {
+ exists: {
+ field: 'serviceName',
+ },
+ },
+ ],
+ filter: [],
+ should: [],
+ must_not: [],
+ },
+ },
+ sort: [
+ {
+ startTime: {
+ order: 'desc',
+ },
+ },
+ ],
+ _source: {
+ includes: [
+ 'serviceName',
+ 'name',
+ 'startTime',
+ 'endTime',
+ 'spanId',
+ 'status.code',
+ 'durationInNanos',
+ ],
+ },
+ };
+ return query;
+};
+
+export const getPayloadQuery = (traceId: string, size = 1000) => {
+ return {
+ size,
+ query: {
+ bool: {
+ must: [
+ {
+ term: {
+ traceId,
+ },
+ },
+ ],
+ filter: [],
+ should: [],
+ must_not: [],
+ },
+ },
+ };
+};
+
+export const getSpanFlyoutQuery = (spanId?: string, size = 1000) => {
+ return {
+ size,
+ query: {
+ bool: {
+ must: [
+ {
+ term: {
+ spanId,
+ },
+ },
+ ],
+ filter: [],
+ should: [],
+ must_not: [],
+ },
+ },
+ };
+};
+
+export const getSpansQuery = (spanSearchParams: SpanSearchParams) => {
+ const query: any = {
+ size: spanSearchParams.size,
+ from: spanSearchParams.from,
+ query: {
+ bool: {
+ must: [],
+ filter: [],
+ should: [],
+ must_not: [],
+ },
+ },
+ sort: spanSearchParams.sortingColumns,
+ };
+ return query;
+};
+
+export const getValidTraceIdsQuery = (DSL) => {
+ const query: any = {
+ size: 0,
+ query: {
+ bool: {
+ must: [],
+ filter: [],
+ should: [],
+ must_not: [],
+ },
+ },
+ aggs: {
+ traces: {
+ terms: {
+ field: 'traceId',
+ size: 10000,
+ },
+ },
+ },
+ };
+ if (DSL.custom?.timeFilter.length > 0) query.query.bool.must.push(...DSL.custom.timeFilter);
+ if (DSL.custom?.traceGroupFields.length > 0) {
+ query.query.bool.filter.push({
+ terms: {
+ traceGroup: DSL.custom.traceGroup,
+ },
+ });
+ }
+ if (DSL.custom?.percentiles?.query.bool.should.length > 0) {
+ query.query.bool.should.push(...DSL.custom.percentiles.query.bool.should);
+ query.query.bool.minimum_should_match = DSL.custom.percentiles.query.bool.minimum_should_match;
+ }
+ if (DSL.custom?.serviceNames.length > 0) {
+ query.query.bool.filter.push({
+ terms: {
+ serviceName: DSL.custom.serviceNames,
+ },
+ });
+ }
+ return query;
+};
diff --git a/public/components/trace_analytics/requests/request_handler.ts b/public/components/trace_analytics/requests/request_handler.ts
new file mode 100644
index 0000000000..a115cc7872
--- /dev/null
+++ b/public/components/trace_analytics/requests/request_handler.ts
@@ -0,0 +1,34 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable no-console */
+
+import { CoreStart } from '../../../../../../src/core/public';
+import {
+ TRACE_ANALYTICS_DSL_ROUTE,
+ TRACE_ANALYTICS_INDICES_ROUTE,
+} from '../../../../common/constants/trace_analytics';
+
+export function handleDslRequest(http: CoreStart['http'], DSL: any, bodyQuery: any) {
+ if (DSL?.query) {
+ bodyQuery.query.bool.must.push(...DSL.query.bool.must);
+ bodyQuery.query.bool.filter.push(...DSL.query.bool.filter);
+ bodyQuery.query.bool.should.push(...DSL.query.bool.should);
+ bodyQuery.query.bool.must_not.push(...DSL.query.bool.must_not);
+ if (DSL.query.bool.minimum_should_match)
+ bodyQuery.query.bool.minimum_should_match = DSL.query.bool.minimum_should_match;
+ }
+ return http
+ .post(TRACE_ANALYTICS_DSL_ROUTE, {
+ body: JSON.stringify(bodyQuery),
+ })
+ .catch((error) => console.error(error));
+}
+
+export async function handleIndicesExistRequest(http: CoreStart['http'], setIndicesExist) {
+ http
+ .post(TRACE_ANALYTICS_INDICES_ROUTE)
+ .then((exists) => setIndicesExist(exists))
+ .catch(() => setIndicesExist(false));
+}
diff --git a/public/components/trace_analytics/requests/services_request_handler.ts b/public/components/trace_analytics/requests/services_request_handler.ts
new file mode 100644
index 0000000000..9c59deb18e
--- /dev/null
+++ b/public/components/trace_analytics/requests/services_request_handler.ts
@@ -0,0 +1,187 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable no-console */
+
+import _ from 'lodash';
+import dateMath from '@elastic/datemath';
+import DSLService from 'public/services/requests/dsl';
+import { ServiceObject } from '../components/common/plots/service_map';
+import {
+ getRelatedServicesQuery,
+ getServiceEdgesQuery,
+ getServiceMetricsQuery,
+ getServiceNodesQuery,
+ getServicesQuery,
+} from './queries/services_queries';
+import { handleDslRequest } from './request_handler';
+import { HttpSetup } from '../../../../../../src/core/public';
+
+export const handleServicesRequest = async (
+ http: HttpSetup,
+ DSL: any,
+ setItems: any,
+ setServiceMap?: any,
+ serviceNameFilter?: string
+) => {
+ return handleDslRequest(http, DSL, getServicesQuery(serviceNameFilter, DSL))
+ .then(async (response) => {
+ const serviceObject: ServiceObject = await handleServiceMapRequest(http, DSL, setServiceMap);
+ return Promise.all(
+ response.aggregations.service.buckets
+ .filter((bucket: any) => serviceObject[bucket.key])
+ .map((bucket: any) => {
+ const connectedServices = [
+ ...serviceObject[bucket.key].targetServices,
+ ...serviceObject[bucket.key].destServices,
+ ];
+ return {
+ name: bucket.key,
+ average_latency: serviceObject[bucket.key].latency,
+ error_rate: serviceObject[bucket.key].error_rate,
+ throughput: serviceObject[bucket.key].throughput,
+ traces: bucket.trace_count.value,
+ connected_services: connectedServices.sort(),
+ number_of_connected_services: connectedServices.length,
+ };
+ })
+ );
+ })
+ .then((newItems) => {
+ setItems(newItems);
+ })
+ .catch((error) => console.error(error));
+};
+
+export const handleServiceMapRequest = async (
+ http: HttpSetup,
+ DSL: DSLService | any,
+ setItems?: any,
+ currService?: string
+) => {
+ let minutesInDateRange: number;
+ const startTime = DSL.custom?.timeFilter?.[0]?.range?.startTime;
+ if (startTime) {
+ const gte = dateMath.parse(startTime.gte)!;
+ const lte = dateMath.parse(startTime.lte)!;
+ minutesInDateRange = lte.diff(gte, 'minutes', true);
+ }
+
+ const map: ServiceObject = {};
+ let id = 1;
+ await handleDslRequest(http, null, getServiceNodesQuery())
+ .then((response) =>
+ response.aggregations.service_name.buckets.map(
+ (bucket: any) =>
+ (map[bucket.key] = {
+ serviceName: bucket.key,
+ id: id++,
+ traceGroups: bucket.trace_group.buckets.map((traceGroup: any) => ({
+ traceGroup: traceGroup.key,
+ targetResource: traceGroup.target_resource.buckets.map((res: any) => res.key),
+ })),
+ targetServices: [],
+ destServices: [],
+ })
+ )
+ )
+ .catch((error) => console.error(error));
+
+ const targets = {};
+ await handleDslRequest(http, null, getServiceEdgesQuery('target'))
+ .then((response) =>
+ response.aggregations.service_name.buckets.map((bucket: any) => {
+ bucket.resource.buckets.map((resource: any) => {
+ resource.domain.buckets.map((domain: any) => {
+ targets[resource.key + ':' + domain.key] = bucket.key;
+ });
+ });
+ })
+ )
+ .catch((error) => console.error(error));
+ await handleDslRequest(http, null, getServiceEdgesQuery('destination'))
+ .then((response) =>
+ Promise.all(
+ response.aggregations.service_name.buckets.map((bucket: any) => {
+ bucket.resource.buckets.map((resource: any) => {
+ resource.domain.buckets.map((domain: any) => {
+ const targetService = targets[resource.key + ':' + domain.key];
+ if (targetService) {
+ if (map[bucket.key].targetServices.indexOf(targetService) === -1)
+ map[bucket.key].targetServices.push(targetService);
+ if (map[targetService].destServices.indexOf(bucket.key) === -1)
+ map[targetService].destServices.push(bucket.key);
+ }
+ });
+ });
+ })
+ )
+ )
+ .catch((error) => console.error(error));
+
+ // service map handles DSL differently
+ const latencies = await handleDslRequest(
+ http,
+ DSL,
+ getServiceMetricsQuery(DSL, Object.keys(map), map)
+ );
+ latencies.aggregations.service_name.buckets.map((bucket: any) => {
+ map[bucket.key].latency = bucket.average_latency.value;
+ map[bucket.key].error_rate = _.round(bucket.error_rate.value, 2) || 0;
+ map[bucket.key].throughput = bucket.doc_count;
+ if (minutesInDateRange != null)
+ map[bucket.key].throughputPerMinute = _.round(bucket.doc_count / minutesInDateRange, 2);
+ });
+
+ if (currService) {
+ await handleDslRequest(http, DSL, getRelatedServicesQuery(currService))
+ .then((response) =>
+ response.aggregations.traces.buckets.filter((bucket: any) => bucket.service.doc_count > 0)
+ )
+ .then((traces) => {
+ const maxNumServices = Object.keys(map).length;
+ const relatedServices = new Set();
+ for (let i = 0; i < traces.length; i++) {
+ traces[i].all_services.buckets.map((bucket: any) => relatedServices.add(bucket.key));
+ if (relatedServices.size === maxNumServices) break;
+ }
+ map[currService].relatedServices = [...relatedServices];
+ })
+ .catch((error) => console.error(error));
+ }
+
+ if (setItems) setItems(map);
+ return map;
+};
+
+export const handleServiceViewRequest = (
+ serviceName: string,
+ http: HttpSetup,
+ DSL: any,
+ setFields: any
+) => {
+ handleDslRequest(http, DSL, getServicesQuery(serviceName))
+ .then(async (response) => {
+ const bucket = response.aggregations.service.buckets[0];
+ if (!bucket) return {};
+ const serviceObject: ServiceObject = await handleServiceMapRequest(http, DSL);
+ const connectedServices = [
+ ...serviceObject[bucket.key].targetServices,
+ ...serviceObject[bucket.key].destServices,
+ ];
+ return {
+ name: bucket.key,
+ connected_services: connectedServices.sort(),
+ number_of_connected_services: connectedServices.length,
+ average_latency: serviceObject[bucket.key].latency,
+ error_rate: serviceObject[bucket.key].error_rate,
+ throughput: serviceObject[bucket.key].throughput,
+ traces: bucket.trace_count.value,
+ };
+ })
+ .then((newFields) => {
+ setFields(newFields);
+ })
+ .catch((error) => console.error(error));
+};
diff --git a/public/components/trace_analytics/requests/traces_request_handler.ts b/public/components/trace_analytics/requests/traces_request_handler.ts
new file mode 100644
index 0000000000..03eb33f4d1
--- /dev/null
+++ b/public/components/trace_analytics/requests/traces_request_handler.ts
@@ -0,0 +1,296 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable no-console */
+
+import _ from 'lodash';
+import moment from 'moment';
+import { v1 as uuid } from 'uuid';
+import { HttpSetup } from '../../../../../../src/core/public';
+import { TRACE_ANALYTICS_DATE_FORMAT } from '../../../../common/constants/trace_analytics';
+import { nanoToMilliSec } from '../components/common/helper_functions';
+import { SpanSearchParams } from '../components/traces/span_detail_table';
+import {
+ getPayloadQuery,
+ getServiceBreakdownQuery,
+ getSpanDetailQuery,
+ getSpanFlyoutQuery,
+ getSpansQuery,
+ getTraceGroupPercentilesQuery,
+ getTracesQuery,
+ getValidTraceIdsQuery,
+} from './queries/traces_queries';
+import { handleDslRequest } from './request_handler';
+
+export const handleValidTraceIds = (http: HttpSetup, DSL: any) => {
+ return handleDslRequest(http, {}, getValidTraceIdsQuery(DSL))
+ .then((response) => response.aggregations.traces.buckets.map((bucket: any) => bucket.key))
+ .catch((error) => console.error(error));
+};
+
+export const handleTracesRequest = async (
+ http: HttpSetup,
+ DSL: any,
+ timeFilterDSL: any,
+ items: any,
+ setItems: (items: any) => void,
+ sort?: any
+) => {
+ const binarySearch = (arr: number[], target: number) => {
+ if (!arr) return Number.NaN;
+ let low = 0;
+ let high = arr.length;
+ let mid;
+ while (low < high) {
+ mid = Math.floor((low + high) / 2);
+ if (arr[mid] < target) low = mid + 1;
+ else high = mid;
+ }
+ return Math.max(0, Math.min(100, low));
+ };
+
+ // percentile should only be affected by timefilter
+ const percentileRanges = await handleDslRequest(
+ http,
+ timeFilterDSL,
+ getTraceGroupPercentilesQuery()
+ ).then((response) => {
+ const map: any = {};
+ response.aggregations.trace_group_name.buckets.forEach((traceGroup: any) => {
+ map[traceGroup.key] = Object.values(traceGroup.percentiles.values).map((value: any) =>
+ nanoToMilliSec(value)
+ );
+ });
+ return map;
+ });
+
+ return handleDslRequest(http, DSL, getTracesQuery(undefined, sort))
+ .then((response) => {
+ return Promise.all(
+ response.aggregations.traces.buckets.map((bucket: any) => {
+ return {
+ trace_id: bucket.key,
+ trace_group: bucket.trace_group.buckets[0]?.key,
+ latency: bucket.latency.value,
+ last_updated: moment(bucket.last_updated.value).format(TRACE_ANALYTICS_DATE_FORMAT),
+ error_count: bucket.error_count.doc_count,
+ percentile_in_trace_group: binarySearch(
+ percentileRanges[bucket.trace_group.buckets[0]?.key],
+ bucket.latency.value
+ ),
+ actions: '#',
+ };
+ })
+ );
+ })
+ .then((newItems) => {
+ setItems(newItems);
+ })
+ .catch((error) => console.error(error));
+};
+
+export const handleTraceViewRequest = (
+ traceId: string,
+ http: HttpSetup,
+ fields: {},
+ setFields: (fields: any) => void
+) => {
+ handleDslRequest(http, null, getTracesQuery(traceId))
+ .then(async (response) => {
+ const bucket = response.aggregations.traces.buckets[0];
+ return {
+ trace_id: bucket.key,
+ trace_group: bucket.trace_group.buckets[0]?.key,
+ last_updated: moment(bucket.last_updated.value).format(TRACE_ANALYTICS_DATE_FORMAT),
+ user_id: 'N/A',
+ latency: bucket.latency.value,
+ latency_vs_benchmark: 'N/A',
+ percentile_in_trace_group: 'N/A',
+ error_count: bucket.error_count.doc_count,
+ errors_vs_benchmark: 'N/A',
+ };
+ })
+ .then((newFields) => {
+ setFields(newFields);
+ })
+ .catch((error) => console.error(error));
+};
+
+// setColorMap sets serviceName to color mappings
+export const handleServicesPieChartRequest = async (
+ traceId: string,
+ http: HttpSetup,
+ setServiceBreakdownData: (serviceBreakdownData: any) => void,
+ setColorMap: (colorMap: any) => void
+) => {
+ const colors = [
+ '#7492e7',
+ '#c33d69',
+ '#2ea597',
+ '#8456ce',
+ '#e07941',
+ '#3759ce',
+ '#ce567c',
+ '#9469d6',
+ '#4066df',
+ '#da7596',
+ '#a783e1',
+ '#5978e3',
+ ];
+ const colorMap: any = {};
+ let index = 0;
+ await handleDslRequest(http, null, getServiceBreakdownQuery(traceId))
+ .then((response) =>
+ Promise.all(
+ response.aggregations.service_type.buckets.map((bucket: any) => {
+ colorMap[bucket.key] = colors[index++ % colors.length];
+ return {
+ name: bucket.key,
+ color: colorMap[bucket.key],
+ value: bucket.total_latency.value,
+ benchmark: 0,
+ };
+ })
+ )
+ )
+ .then((newItems) => {
+ const latencySum = newItems.map((item) => item.value).reduce((a, b) => a + b, 0);
+ return [
+ {
+ values: newItems.map((item) =>
+ latencySum === 0 ? 100 : (item.value / latencySum) * 100
+ ),
+ labels: newItems.map((item) => item.name),
+ benchmarks: newItems.map((item) => item.benchmark),
+ marker: {
+ colors: newItems.map((item) => item.color),
+ },
+ type: 'pie',
+ textinfo: 'none',
+ hovertemplate: '%{label} %{value:.2f}% ',
+ },
+ ];
+ })
+ .then((newItems) => {
+ setServiceBreakdownData(newItems);
+ setColorMap(colorMap);
+ })
+ .catch((error) => console.error(error));
+};
+
+export const handleSpansGanttRequest = (
+ traceId: string,
+ http: HttpSetup,
+ setSpanDetailData: (spanDetailData: any) => void,
+ colorMap: any,
+ spanFiltersDSL: any
+) => {
+ handleDslRequest(http, spanFiltersDSL, getSpanDetailQuery(traceId))
+ .then((response) => hitsToSpanDetailData(response.hits.hits, colorMap))
+ .then((newItems) => setSpanDetailData(newItems))
+ .catch((error) => console.error(error));
+};
+
+export const handleSpansFlyoutRequest = (
+ http: HttpSetup,
+ spanId: string,
+ setItems: (items: any) => void
+) => {
+ handleDslRequest(http, null, getSpanFlyoutQuery(spanId))
+ .then((response) => {
+ setItems(response?.hits.hits?.[0]?._source);
+ })
+ .catch((error) => console.error(error));
+};
+
+const hitsToSpanDetailData = async (hits: any, colorMap: any) => {
+ const data: { gantt: any[]; table: any[]; ganttMaxX: number } = {
+ gantt: [],
+ table: [],
+ ganttMaxX: 0,
+ };
+ if (hits.length === 0) return data;
+
+ const minStartTime = nanoToMilliSec(hits[hits.length - 1].sort[0]);
+ let maxEndTime = 0;
+
+ hits.forEach((hit: any) => {
+ const startTime = nanoToMilliSec(hit.sort[0]) - minStartTime;
+ const duration = _.round(nanoToMilliSec(hit._source.durationInNanos), 2);
+ const serviceName = _.get(hit, ['_source', 'serviceName']);
+ const name = _.get(hit, '_source.name');
+ const error = hit._source['status.code'] === 2 ? ' \u26a0 Error' : '';
+ const uniqueLabel = `${serviceName} ${name} ` + uuid();
+ maxEndTime = Math.max(maxEndTime, startTime + duration);
+
+ data.table.push({
+ service_name: serviceName,
+ span_id: hit._source.spanId,
+ latency: duration,
+ vs_benchmark: 0,
+ error,
+ start_time: hit._source.startTime,
+ end_time: hit._source.endTime,
+ });
+ data.gantt.push(
+ {
+ x: [startTime],
+ y: [uniqueLabel],
+ marker: {
+ color: 'rgba(0, 0, 0, 0)',
+ },
+ width: 0.4,
+ type: 'bar',
+ orientation: 'h',
+ hoverinfo: 'none',
+ showlegend: false,
+ spanId: hit._source.spanId,
+ },
+ {
+ x: [duration],
+ y: [uniqueLabel],
+ text: [error],
+ textfont: { color: ['#c14125'] },
+ textposition: 'outside',
+ marker: {
+ color: colorMap[serviceName],
+ },
+ width: 0.4,
+ type: 'bar',
+ orientation: 'h',
+ hovertemplate: '%{x} ',
+ spanId: hit._source.spanId,
+ }
+ );
+ });
+
+ data.ganttMaxX = maxEndTime;
+ return data;
+};
+
+export const handlePayloadRequest = (
+ traceId: string,
+ http: HttpSetup,
+ payloadData: any,
+ setPayloadData: (payloadData: any) => void
+) => {
+ handleDslRequest(http, null, getPayloadQuery(traceId))
+ .then((response) => setPayloadData(JSON.stringify(response.hits.hits, null, 2)))
+ .catch((error) => console.error(error));
+};
+
+export const handleSpansRequest = (
+ http: HttpSetup,
+ setItems: (items: any) => void,
+ setTotal: (total: number) => void,
+ spanSearchParams: SpanSearchParams,
+ DSL: any
+) => {
+ handleDslRequest(http, DSL, getSpansQuery(spanSearchParams))
+ .then((response) => {
+ setItems(response.hits.hits.map((hit: any) => hit._source));
+ setTotal(response.hits.total?.value || 0);
+ })
+ .catch((error) => console.error(error));
+};
diff --git a/public/components/visualizations/assets/__tests__/__snapshots__/assets.test.tsx.snap b/public/components/visualizations/assets/__tests__/__snapshots__/assets.test.tsx.snap
new file mode 100644
index 0000000000..3b213ff7d2
--- /dev/null
+++ b/public/components/visualizations/assets/__tests__/__snapshots__/assets.test.tsx.snap
@@ -0,0 +1,64 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Assets components Renders lens icon of bar component 1`] = `
+
+
+
+
+
+
+`;
+
+exports[`Assets components Renders lens icon of horizontal bar component 1`] = `
+
+
+
+
+
+
+`;
+
+exports[`Assets components Renders lens icon of line component 1`] = `
+
+
+
+
+
+
+`;
diff --git a/public/components/visualizations/assets/__tests__/assets.test.tsx b/public/components/visualizations/assets/__tests__/assets.test.tsx
new file mode 100644
index 0000000000..3b3263533e
--- /dev/null
+++ b/public/components/visualizations/assets/__tests__/assets.test.tsx
@@ -0,0 +1,56 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { LensIconChartBar } from '../chart_bar';
+import { LensIconChartBarHorizontal } from '../chart_bar_horizontal';
+import { LensIconChartLine } from '../chart_line';
+
+
+describe('Assets components', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders lens icon of bar component', async () => {
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+
+ it('Renders lens icon of horizontal bar component', async () => {
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+
+ it('Renders lens icon of line component', async () => {
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
\ No newline at end of file
diff --git a/public/components/visualizations/assets/chart_bar.tsx b/public/components/visualizations/assets/chart_bar.tsx
new file mode 100644
index 0000000000..3ee43ea227
--- /dev/null
+++ b/public/components/visualizations/assets/chart_bar.tsx
@@ -0,0 +1,29 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { EuiIconProps } from '@elastic/eui';
+
+export const LensIconChartBar = ({ title, titleId, ...props }: Omit) => (
+
+ {title ? {title} : null}
+
+
+
+);
diff --git a/public/components/visualizations/assets/chart_bar_horizontal.tsx b/public/components/visualizations/assets/chart_bar_horizontal.tsx
new file mode 100644
index 0000000000..0ccfa6a6cb
--- /dev/null
+++ b/public/components/visualizations/assets/chart_bar_horizontal.tsx
@@ -0,0 +1,33 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { EuiIconProps } from '@elastic/eui';
+
+export const LensIconChartBarHorizontal = ({
+ title,
+ titleId,
+ ...props
+}: Omit) => (
+
+ {title ? {title} : null}
+
+
+
+);
diff --git a/public/components/visualizations/assets/chart_datatable.tsx b/public/components/visualizations/assets/chart_datatable.tsx
new file mode 100644
index 0000000000..d6a5cb733e
--- /dev/null
+++ b/public/components/visualizations/assets/chart_datatable.tsx
@@ -0,0 +1,35 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import React from 'react';
+import { EuiIconProps } from '@elastic/eui';
+
+export const LensIconChartDatatable = ({
+ title,
+ titleId,
+ ...props
+}: Omit) => (
+
+ {title ? {title} : null}
+
+
+
+);
diff --git a/public/components/visualizations/assets/chart_line.tsx b/public/components/visualizations/assets/chart_line.tsx
new file mode 100644
index 0000000000..af6b1294ca
--- /dev/null
+++ b/public/components/visualizations/assets/chart_line.tsx
@@ -0,0 +1,29 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { EuiIconProps } from '@elastic/eui';
+
+export const LensIconChartLine = ({ title, titleId, ...props }: Omit) => (
+
+ {title ? {title} : null}
+
+
+
+);
diff --git a/public/components/visualizations/assets/chart_pie.tsx b/public/components/visualizations/assets/chart_pie.tsx
new file mode 100644
index 0000000000..56a18b9d61
--- /dev/null
+++ b/public/components/visualizations/assets/chart_pie.tsx
@@ -0,0 +1,31 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import React from 'react';
+import { EuiIconProps } from '@elastic/eui';
+
+export const LensIconChartPie = ({ title, titleId, ...props }: Omit) => (
+
+ {title ? {title} : null}
+
+
+
+);
diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/bar.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/bar.test.tsx.snap
new file mode 100644
index 0000000000..4c82547a2d
--- /dev/null
+++ b/public/components/visualizations/charts/__tests__/__snapshots__/bar.test.tsx.snap
@@ -0,0 +1,491 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Bar component Renders bar component 1`] = `
+
+
+
+
+
+
+
+`;
+
+exports[`Bar component Renders bar component 2`] = `
+
+
+
+
+
+
+
+`;
diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/horizontal_bar.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/horizontal_bar.test.tsx.snap
new file mode 100644
index 0000000000..f73261fc75
--- /dev/null
+++ b/public/components/visualizations/charts/__tests__/__snapshots__/horizontal_bar.test.tsx.snap
@@ -0,0 +1,567 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Horizontal bar component Renders horizontal bar component 1`] = `
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Horizontal bar component Renders horizontal bar component 2`] = `
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/line.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/line.test.tsx.snap
new file mode 100644
index 0000000000..260d82d33c
--- /dev/null
+++ b/public/components/visualizations/charts/__tests__/__snapshots__/line.test.tsx.snap
@@ -0,0 +1,499 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Line component Renders line component 1`] = `
+
+
+
+
+
+
+
+`;
+
+exports[`Line component Renders line component 2`] = `
+
+
+
+
+
+
+
+`;
diff --git a/public/components/visualizations/charts/__tests__/bar.test.tsx b/public/components/visualizations/charts/__tests__/bar.test.tsx
new file mode 100644
index 0000000000..3e56516fd3
--- /dev/null
+++ b/public/components/visualizations/charts/__tests__/bar.test.tsx
@@ -0,0 +1,35 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { Bar } from '../bar/bar';
+import {
+ LAYOUT_CONFIG,
+ SAMPLE_VISUALIZATIONS,
+} from '../../../../../test/event_analytics_constants';
+
+describe.skip('Bar component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders bar component', async () => {
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
diff --git a/public/components/visualizations/charts/__tests__/horizontal_bar.test.tsx b/public/components/visualizations/charts/__tests__/horizontal_bar.test.tsx
new file mode 100644
index 0000000000..744783727e
--- /dev/null
+++ b/public/components/visualizations/charts/__tests__/horizontal_bar.test.tsx
@@ -0,0 +1,35 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { HorizontalBar } from '../horizontal_bar';
+import {
+ LAYOUT_CONFIG,
+ SAMPLE_VISUALIZATIONS,
+} from '../../../../../test/event_analytics_constants';
+
+describe.skip('Horizontal bar component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders horizontal bar component', async () => {
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
diff --git a/public/components/visualizations/charts/__tests__/line.test.tsx b/public/components/visualizations/charts/__tests__/line.test.tsx
new file mode 100644
index 0000000000..b5cce02e36
--- /dev/null
+++ b/public/components/visualizations/charts/__tests__/line.test.tsx
@@ -0,0 +1,35 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { Line } from '../lines/line';
+import {
+ LAYOUT_CONFIG,
+ SAMPLE_VISUALIZATIONS,
+} from '../../../../../test/event_analytics_constants';
+
+describe.skip('Line component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders line component', async () => {
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
diff --git a/public/components/visualizations/charts/bar/bar.tsx b/public/components/visualizations/charts/bar/bar.tsx
new file mode 100644
index 0000000000..83ec1e3931
--- /dev/null
+++ b/public/components/visualizations/charts/bar/bar.tsx
@@ -0,0 +1,137 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { isEmpty, last, take } from 'lodash';
+import { Plt } from '../../plotly/plot';
+import { LONG_CHART_COLOR, PLOTLY_COLOR } from '../../../../../common/constants/shared';
+import { AvailabilityUnitType } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_availability';
+import { ThresholdUnitType } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_thresholds';
+
+export const Bar = ({ visualizations, layout, config }: any) => {
+ const { vis } = visualizations;
+ const {
+ data,
+ metadata: { fields },
+ } = visualizations.data.rawVizData;
+ const { isUniColor } = vis.visConfig;
+ const lastIndex = fields.length - 1;
+ const {
+ dataConfig = {},
+ layoutConfig = {},
+ availabilityConfig = {},
+ } = visualizations?.data?.userConfigs;
+ const xaxis =
+ dataConfig.valueOptions && dataConfig.valueOptions.xaxis ? dataConfig.valueOptions.xaxis : [];
+ const yaxis =
+ dataConfig.valueOptions && dataConfig.valueOptions.xaxis ? dataConfig?.valueOptions.yaxis : [];
+ const barOrientation =
+ dataConfig?.chartOptions?.orientation &&
+ dataConfig.chartOptions.orientation[0] &&
+ dataConfig.chartOptions.orientation[0].orientationId
+ ? dataConfig.chartOptions.orientation[0].orientationId
+ : visualizations.vis.orientation;
+ const { defaultAxes } = visualizations.data;
+
+ const isVertical = barOrientation === 'v';
+
+ // Individual bars have different colors
+ // when: stackLength = 1 and length of result buckets < 16 and chart is not unicolor
+ // Else each stacked bar has its own color using colorway
+ let marker = {};
+ if (lastIndex === 1 && data[fields[lastIndex].name].length < 16 && !isUniColor) {
+ marker = {
+ color: data[fields[lastIndex].name].map((_: string, index: number) => {
+ return PLOTLY_COLOR[index % PLOTLY_COLOR.length];
+ }),
+ };
+ }
+
+ let valueSeries;
+ if (!isEmpty(xaxis) && !isEmpty(yaxis)) {
+ valueSeries = isVertical ? [...yaxis] : [...xaxis];
+ } else {
+ valueSeries = defaultAxes.yaxis || take(fields, lastIndex > 0 ? lastIndex : 1);
+ }
+
+ // determine category axis
+ let bars = valueSeries.map((field: any) => {
+ return {
+ x: isVertical
+ ? data[!isEmpty(xaxis) ? xaxis[0].label : fields[lastIndex].name]
+ : data[field.name],
+ y: isVertical
+ ? data[field.name]
+ : data[!isEmpty(yaxis) ? yaxis[0]?.label : fields[lastIndex].name],
+ type: vis.type,
+ marker,
+ name: field.name,
+ orientation: barOrientation,
+ };
+ });
+
+ // If chart has length of result buckets < 16
+ // then use the LONG_CHART_COLOR for all the bars in the chart
+ const plotlyColorway =
+ data[fields[lastIndex].name].length < 16 ? PLOTLY_COLOR : [LONG_CHART_COLOR];
+
+ const mergedLayout = {
+ colorway: plotlyColorway,
+ ...layout,
+ ...(layoutConfig.layout && layoutConfig.layout),
+ title: dataConfig?.panelOptions?.title || layoutConfig.layout?.title || '',
+ barmode:
+ dataConfig?.chartOptions?.mode &&
+ dataConfig.chartOptions.mode[0] &&
+ dataConfig.chartOptions.mode[0].modeId
+ ? dataConfig.chartOptions.mode[0].modeId
+ : '',
+ };
+
+ if (dataConfig.thresholds || availabilityConfig.level) {
+ const thresholdTraces = {
+ x: [],
+ y: [],
+ mode: 'text',
+ text: [],
+ };
+ const thresholds = dataConfig.thresholds ? dataConfig.thresholds : [];
+ const levels = availabilityConfig.level ? availabilityConfig.level : [];
+
+ const mapToLine = (list: ThresholdUnitType[] | AvailabilityUnitType[], lineStyle: any) => {
+ return list.map((thr: ThresholdUnitType) => {
+ thresholdTraces.x.push(
+ data[!isEmpty(xaxis) ? xaxis[xaxis.length - 1]?.label : fields[lastIndex].name][0]
+ );
+ thresholdTraces.y.push(thr.value * (1 + 0.06));
+ thresholdTraces.text.push(thr.name);
+ return {
+ type: 'line',
+ x0: data[!isEmpty(xaxis) ? xaxis[0]?.label : fields[lastIndex].name][0],
+ y0: thr.value,
+ x1: last(data[!isEmpty(xaxis) ? xaxis[0]?.label : fields[lastIndex].name]),
+ y1: thr.value,
+ name: thr.name || '',
+ opacity: 0.7,
+ line: {
+ color: thr.color,
+ width: 3,
+ ...lineStyle,
+ },
+ };
+ });
+ };
+
+ mergedLayout.shapes = [...mapToLine(thresholds, { dash: 'dashdot' }), ...mapToLine(levels, {})];
+ bars = [...bars, thresholdTraces];
+ }
+
+ const mergedConfigs = {
+ ...config,
+ ...(layoutConfig.config && layoutConfig.config),
+ };
+
+ return ;
+};
diff --git a/public/components/visualizations/charts/bar/bar_type.ts b/public/components/visualizations/charts/bar/bar_type.ts
new file mode 100644
index 0000000000..7ea9546274
--- /dev/null
+++ b/public/components/visualizations/charts/bar/bar_type.ts
@@ -0,0 +1,121 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { Bar } from './bar';
+import { getPlotlySharedConfigs, getPlotlyCategory } from '../shared/shared_configs';
+import { LensIconChartBar } from '../../assets/chart_bar';
+import { VizDataPanel } from '../../../explorer/visualizations/config_panel/config_editor/default_vis_editor';
+import { ConfigEditor } from '../../../explorer/visualizations/config_panel/config_editor/config_editor';
+import { ConfigValueOptions } from '../../../explorer/visualizations/config_panel/config_editor/config_controls';
+import { ConfigAvailability } from '../../../explorer/visualizations/config_panel/config_editor/config_controls/config_availability';
+
+const sharedConfigs = getPlotlySharedConfigs();
+const VIS_CATEGORY = getPlotlyCategory();
+
+export const createBarTypeDefinition = (params: any) => ({
+ name: 'bar',
+ type: 'bar',
+ id: 'bar',
+ label: 'Bar',
+ fullLabel: 'Bar',
+ iconType: 'visBarVerticalStacked',
+ selection: {
+ dataLoss: 'nothing',
+ },
+ category: VIS_CATEGORY.BASICS,
+ icon: LensIconChartBar,
+ categoryAxis: 'xaxis',
+ seriesAxis: 'yaxis',
+ orientation: 'v',
+ component: Bar,
+ editorConfig: {
+ panelTabs: [
+ {
+ id: 'data-panel',
+ name: 'Data',
+ mapTo: 'dataConfig',
+ editor: VizDataPanel,
+ sections: [
+ {
+ id: 'value_options',
+ name: 'Value options',
+ editor: ConfigValueOptions,
+ mapTo: 'valueOptions',
+ schemas: [
+ {
+ name: 'X-axis',
+ isSingleSelection: false,
+ component: null,
+ mapTo: 'xaxis',
+ },
+ {
+ name: 'Y-axis',
+ isSingleSelection: false,
+ component: null,
+ mapTo: 'yaxis',
+ },
+ ],
+ },
+ {
+ id: 'chart_options',
+ name: 'Chart options',
+ editor: ConfigValueOptions,
+ mapTo: 'chartOptions',
+ schemas: [
+ {
+ name: 'Orientation',
+ isSingleSelection: true,
+ component: null,
+ mapTo: 'orientation',
+ props: {
+ dropdownList: [
+ { name: 'Vertical', orientationId: 'v' },
+ { name: 'Horizontal', orientationId: 'h' },
+ ],
+ defaultSelections: [{ name: 'Vertical', orientationId: 'v' }],
+ },
+ },
+ {
+ name: 'Mode',
+ isSingleSelection: true,
+ component: null,
+ mapTo: 'mode',
+ props: {
+ dropdownList: [
+ { name: 'Group', modeId: 'group' },
+ { name: 'Stack', modeId: 'stack' },
+ ],
+ defaultSelections: [{ name: 'Group', modeId: 'group' }],
+ },
+ },
+ ],
+ },
+ ],
+ },
+ {
+ id: 'style-panel',
+ name: 'Layout',
+ mapTo: 'layoutConfig',
+ editor: ConfigEditor,
+ content: [],
+ },
+ {
+ id: 'availability-panel',
+ name: 'Availability',
+ mapTo: 'availabilityConfig',
+ editor: ConfigAvailability,
+ },
+ ],
+ },
+ visConfig: {
+ layout: {
+ ...sharedConfigs.layout,
+ },
+ config: {
+ ...sharedConfigs.config,
+ },
+ isUniColor: false,
+ },
+});
diff --git a/public/components/visualizations/charts/bar/horizontal_bar_type.ts b/public/components/visualizations/charts/bar/horizontal_bar_type.ts
new file mode 100644
index 0000000000..9a3523208f
--- /dev/null
+++ b/public/components/visualizations/charts/bar/horizontal_bar_type.ts
@@ -0,0 +1,111 @@
+import { Bar } from './bar';
+import { getPlotlySharedConfigs, getPlotlyCategory } from '../shared/shared_configs';
+import { LensIconChartBar } from '../../assets/chart_bar';
+import { VizDataPanel } from '../../../explorer/visualizations/config_panel/config_editor/default_vis_editor';
+import { ConfigEditor } from '../../../explorer/visualizations/config_panel/config_editor/config_editor';
+import { ConfigValueOptions } from '../../../explorer/visualizations/config_panel/config_editor/config_controls';
+
+const sharedConfigs = getPlotlySharedConfigs();
+const VIS_CATEGORY = getPlotlyCategory();
+
+export interface BarTypeParams {}
+
+export const createHorizontalBarTypeDefinition = (params: BarTypeParams = {}) => ({
+ id: 'horizontal_bar',
+ name: 'horizontal_bar',
+ type: 'bar',
+ label: 'Bar',
+ fullLabel: 'Bar',
+ iconType: 'visBarVerticalStacked',
+ selection: {
+ dataLoss: 'nothing',
+ },
+ category: VIS_CATEGORY.BASICS,
+ icon: LensIconChartBar,
+ categoryAxis: 'xaxis',
+ seriesAxis: 'yaxis',
+ orientation: 'h',
+ component: Bar,
+ editorConfig: {
+ panelTabs: [
+ {
+ id: 'data-panel',
+ name: 'Data',
+ mapTo: 'dataConfig',
+ editor: VizDataPanel,
+ sections: [
+ {
+ id: 'value_options',
+ name: 'Value options',
+ editor: ConfigValueOptions,
+ mapTo: 'valueOptions',
+ schemas: [
+ {
+ name: 'X-axis',
+ isSingleSelection: false,
+ component: null,
+ mapTo: 'xaxis',
+ },
+ {
+ name: 'Y-axis',
+ isSingleSelection: false,
+ component: null,
+ mapTo: 'yaxis',
+ },
+ ],
+ },
+ {
+ id: 'chart_options',
+ name: 'Chart options',
+ editor: ConfigValueOptions,
+ mapTo: 'chartOptions',
+ schemas: [
+ {
+ name: 'Orientation',
+ isSingleSelection: true,
+ component: null,
+ mapTo: 'orientation',
+ props: {
+ dropdownList: [
+ { name: 'Vertical', orientationId: 'v' },
+ { name: 'Horizontal', orientationId: 'h' },
+ ],
+ defaultSelections: [{ name: 'Horizontal', orientationId: 'h' }],
+ },
+ },
+ {
+ name: 'Mode',
+ isSingleSelection: true,
+ component: null,
+ mapTo: 'mode',
+ props: {
+ dropdownList: [
+ { name: 'Group', modeId: 'group' },
+ { name: 'Stack', modeId: 'stack' },
+ ],
+ defaultSelections: [{ name: 'Group', modeId: 'group' }],
+ },
+ },
+ ],
+ },
+ ],
+ },
+ {
+ id: 'style-panel',
+ name: 'Layout',
+ mapTo: 'layoutConfig',
+ editor: ConfigEditor,
+ content: [],
+ },
+ ],
+ },
+ visConfig: {
+ layout: {
+ ...sharedConfigs.layout,
+ },
+ config: {
+ ...sharedConfigs.config,
+ },
+ isUniColor: false,
+ },
+});
diff --git a/public/components/visualizations/charts/bubble/bubble.tsx b/public/components/visualizations/charts/bubble/bubble.tsx
new file mode 100644
index 0000000000..8007be9946
--- /dev/null
+++ b/public/components/visualizations/charts/bubble/bubble.tsx
@@ -0,0 +1,72 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { take, merge, isEmpty } from 'lodash';
+import { Plt } from '../../plotly/plot';
+import { PLOTLY_COLOR } from '../../../../../common/constants/shared';
+
+export const Bubble = ({
+ visualizations,
+ figureConfig = {},
+ layoutConfig = {},
+ dispatch,
+ customVizData = {},
+}: any) => {
+ const {
+ data,
+ metadata: { fields },
+ } = visualizations.data.rawVizData;
+ const lineLength = fields.length - 1;
+ // let lineValues;
+ // if (isEmpty(customVizData)) {
+ const lineValues = take(fields, lineLength).map((field: any) => {
+ return {
+ x: data[field.name],
+ y: data[fields[lineLength].name],
+ mode: 'markers',
+ // type: 'pie',
+ name: field.name,
+ };
+ });
+ // } else {
+ // lineValues = [...customVizData];
+ // }
+
+ const config = {
+ // barmode: 'pie',
+ xaxis: {
+ automargin: true,
+ },
+ yaxis: {
+ automargin: true,
+ },
+ };
+ const lineLayoutConfig = merge(config, layoutConfig);
+
+ return (
+
+ );
+};
diff --git a/public/components/visualizations/charts/bubble/bubble_type.ts b/public/components/visualizations/charts/bubble/bubble_type.ts
new file mode 100644
index 0000000000..03b8181c20
--- /dev/null
+++ b/public/components/visualizations/charts/bubble/bubble_type.ts
@@ -0,0 +1,75 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { Bubble } from './bubble';
+import { getPlotlySharedConfigs, getPlotlyCategory } from '../shared/shared_configs';
+import { LensIconChartPie } from '../../assets/chart_pie';
+import { VizDataPanel } from '../../../explorer/visualizations/config_panel/config_editor/default_vis_editor';
+import { ConfigEditor } from '../../../explorer/visualizations/config_panel/config_editor/config_editor';
+import { ConfigValueOptions } from '../../../explorer/visualizations/config_panel/config_editor/config_controls';
+
+const sharedConfigs = getPlotlySharedConfigs();
+const VIS_CATEGORY = getPlotlyCategory();
+
+export const createBubbleVisDefinition = () => ({
+ name: 'bubble',
+ type: 'bubble',
+ id: 'bubble',
+ label: 'Bubble',
+ fullLabel: 'Bubble',
+ category: VIS_CATEGORY.BASICS,
+ selection: {
+ dataLoss: 'nothing',
+ },
+ editorConfig: {
+ panelTabs: [
+ {
+ id: 'data-panel',
+ name: 'Data',
+ mapTo: 'dataConfig',
+ editor: VizDataPanel,
+ sections: [
+ {
+ id: 'value_options',
+ name: 'Value options',
+ editor: ConfigValueOptions,
+ mapTo: 'valueOptions',
+ schemas: [
+ {
+ name: 'X-axis',
+ isSingleSelection: true,
+ component: null,
+ mapTo: 'xaxis',
+ },
+ {
+ name: 'Y-axis',
+ isSingleSelection: false,
+ component: null,
+ mapTo: 'yaxis',
+ },
+ ],
+ },
+ ],
+ },
+ {
+ id: 'style-panel',
+ name: 'Layout',
+ mapTo: 'layoutConfig',
+ editor: ConfigEditor,
+ content: [],
+ },
+ ],
+ },
+ icon: LensIconChartPie,
+ visConfig: {
+ layout: {
+ ...sharedConfigs.layout,
+ },
+ config: {
+ ...sharedConfigs.config,
+ },
+ },
+ component: Bubble,
+});
diff --git a/public/components/visualizations/charts/data_table/data_table.tsx b/public/components/visualizations/charts/data_table/data_table.tsx
new file mode 100644
index 0000000000..99f72748d2
--- /dev/null
+++ b/public/components/visualizations/charts/data_table/data_table.tsx
@@ -0,0 +1,103 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useState, useMemo, useCallback } from 'react';
+import { EuiInMemoryTable, EuiDataGrid } from '@elastic/eui';
+
+export const DataTable = ({ visualizations }: any) => {
+ const {
+ data: vizData,
+ jsonData,
+ metadata: { fields = [] },
+ } = visualizations.data.rawVizData;
+
+ const raw_data = [...jsonData];
+
+ // Pagination
+ const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 });
+ const onChangeItemsPerPage = useCallback(
+ (pageSize) =>
+ setPagination((pagination) => ({
+ ...pagination,
+ pageSize,
+ pageIndex: 0,
+ })),
+ [setPagination]
+ );
+ const onChangePage = useCallback(
+ (pageIndex) => setPagination((pagination) => ({ ...pagination, pageIndex })),
+ [setPagination]
+ );
+
+ // Sorting
+ const [sortingColumns, setSortingColumns] = useState([]);
+ const onSort = useCallback(
+ (sortingColumns) => {
+ setSortingColumns(sortingColumns);
+ },
+ [setSortingColumns]
+ );
+
+ // Sort data
+ let data = useMemo(() => {
+ return [...raw_data].sort((a, b) => {
+ for (let i = 0; i < sortingColumns.length; i++) {
+ const column = sortingColumns[i];
+ const aValue = a[column.id];
+ const bValue = b[column.id];
+
+ if (aValue < bValue) return column.direction === 'asc' ? -1 : 1;
+ if (aValue > bValue) return column.direction === 'asc' ? 1 : -1;
+ }
+
+ return 0;
+ });
+ }, [sortingColumns]);
+
+ // Pagination
+ data = useMemo(() => {
+ const rowStart = pagination.pageIndex * pagination.pageSize;
+ const rowEnd = Math.min(rowStart + pagination.pageSize, data.length);
+ return data.slice(rowStart, rowEnd);
+ }, [data, pagination]);
+
+ const columns = fields.map((field) => {
+ return {
+ id: field.name,
+ };
+ });
+
+ // Column visibility
+ const [visibleColumns, setVisibleColumns] = useState(columns.map(({ id }) => id));
+
+ const renderCellValue = useMemo(() => {
+ return ({ rowIndex, columnId }) => {
+ let adjustedRowIndex = rowIndex;
+
+ // If we are doing the pagination (instead of leaving that to the grid)
+ // then the row index must be adjusted as `data` has already been pruned to the page size
+ adjustedRowIndex = rowIndex - pagination.pageIndex * pagination.pageSize;
+
+ return data.hasOwnProperty(adjustedRowIndex) ? data[adjustedRowIndex][columnId] : null;
+ };
+ }, [data, pagination.pageIndex, pagination.pageSize]);
+
+ return (
+
+ );
+};
diff --git a/public/components/visualizations/charts/data_table/data_table_type.ts b/public/components/visualizations/charts/data_table/data_table_type.ts
new file mode 100644
index 0000000000..e3f03764a6
--- /dev/null
+++ b/public/components/visualizations/charts/data_table/data_table_type.ts
@@ -0,0 +1,37 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { DataTable } from './data_table';
+import { getPlotlyCategory } from '../shared/shared_configs';
+import { LensIconChartDatatable } from '../../assets/chart_datatable';
+
+const VIS_CATEGORY = getPlotlyCategory();
+
+export const createDatatableTypeDefinition = (params: any = {}) => ({
+ name: 'data_table',
+ type: 'data_table',
+ id: 'data_table',
+ label: 'Data Table',
+ fullLabel: 'Data Table',
+ iconType: 'visTable',
+ category: VIS_CATEGORY.BASICS,
+ selection: {
+ dataLoss: 'nothing',
+ },
+ icon: LensIconChartDatatable,
+ editorConfig: {
+ editor: null,
+ schemas: [
+ {
+ name: 'Columns',
+ isSingleSelection: true,
+ onChangeHandler: 'setXaxisSelections',
+ component: null,
+ mapTo: 'xaxis',
+ },
+ ],
+ },
+ component: DataTable,
+});
diff --git a/public/components/visualizations/charts/financial/candle_stick/candle_stick.tsx b/public/components/visualizations/charts/financial/candle_stick/candle_stick.tsx
new file mode 100644
index 0000000000..150b93ab59
--- /dev/null
+++ b/public/components/visualizations/charts/financial/candle_stick/candle_stick.tsx
@@ -0,0 +1,217 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+
+import { Plt } from '../../../plotly/plot';
+
+export const CandleStick = ({ visualizations, layout, config }) => {
+ const trace1 = {
+ x: [
+ '2017-01-04',
+ '2017-01-05',
+ '2017-01-06',
+ '2017-01-09',
+ '2017-01-10',
+ '2017-01-11',
+ '2017-01-12',
+ '2017-01-13',
+ '2017-01-17',
+ '2017-01-18',
+ '2017-01-19',
+ '2017-01-20',
+ '2017-01-23',
+ '2017-01-24',
+ '2017-01-25',
+ '2017-01-26',
+ '2017-01-27',
+ '2017-01-30',
+ '2017-01-31',
+ '2017-02-01',
+ '2017-02-02',
+ '2017-02-03',
+ '2017-02-06',
+ '2017-02-07',
+ '2017-02-08',
+ '2017-02-09',
+ '2017-02-10',
+ '2017-02-13',
+ '2017-02-14',
+ '2017-02-15',
+ ],
+
+ close: [
+ 116.019997,
+ 116.610001,
+ 117.910004,
+ 118.989998,
+ 119.110001,
+ 119.75,
+ 119.25,
+ 119.040001,
+ 120,
+ 119.989998,
+ 119.779999,
+ 120,
+ 120.080002,
+ 119.970001,
+ 121.879997,
+ 121.940002,
+ 121.949997,
+ 121.629997,
+ 121.349998,
+ 128.75,
+ 128.529999,
+ 129.080002,
+ 130.289993,
+ 131.529999,
+ 132.039993,
+ 132.419998,
+ 132.119995,
+ 133.289993,
+ 135.020004,
+ 135.509995,
+ ],
+
+ decreasing: { line: { color: '#7F7F7F' } },
+
+ high: [
+ 116.510002,
+ 116.860001,
+ 118.160004,
+ 119.43,
+ 119.379997,
+ 119.93,
+ 119.300003,
+ 119.620003,
+ 120.239998,
+ 120.5,
+ 120.089996,
+ 120.449997,
+ 120.809998,
+ 120.099998,
+ 122.099998,
+ 122.440002,
+ 122.349998,
+ 121.629997,
+ 121.389999,
+ 130.490005,
+ 129.389999,
+ 129.190002,
+ 130.5,
+ 132.089996,
+ 132.220001,
+ 132.449997,
+ 132.940002,
+ 133.820007,
+ 135.089996,
+ 136.270004,
+ ],
+
+ increasing: { line: { color: '#17BECF' } },
+
+ line: { color: 'rgba(31,119,180,1)' },
+
+ low: [
+ 115.75,
+ 115.809998,
+ 116.470001,
+ 117.940002,
+ 118.300003,
+ 118.599998,
+ 118.209999,
+ 118.809998,
+ 118.220001,
+ 119.709999,
+ 119.370003,
+ 119.730003,
+ 119.769997,
+ 119.5,
+ 120.279999,
+ 121.599998,
+ 121.599998,
+ 120.660004,
+ 120.620003,
+ 127.010002,
+ 127.779999,
+ 128.160004,
+ 128.899994,
+ 130.449997,
+ 131.220001,
+ 131.119995,
+ 132.050003,
+ 132.75,
+ 133.25,
+ 134.619995,
+ ],
+
+ open: [
+ 115.849998,
+ 115.919998,
+ 116.779999,
+ 117.949997,
+ 118.769997,
+ 118.739998,
+ 118.900002,
+ 119.110001,
+ 118.339996,
+ 120,
+ 119.400002,
+ 120.449997,
+ 120,
+ 119.550003,
+ 120.419998,
+ 121.669998,
+ 122.139999,
+ 120.93,
+ 121.150002,
+ 127.029999,
+ 127.980003,
+ 128.309998,
+ 129.130005,
+ 130.539993,
+ 131.350006,
+ 131.649994,
+ 132.460007,
+ 133.080002,
+ 133.470001,
+ 135.520004,
+ ],
+
+ type: 'candlestick',
+ xaxis: 'x',
+ yaxis: 'y',
+ };
+
+ const candleStickData = [trace1];
+
+ const finalLayout = {
+ dragmode: 'zoom',
+ margin: {
+ r: 10,
+ t: 25,
+ b: 40,
+ l: 60,
+ },
+ showlegend: false,
+ xaxis: {
+ autorange: true,
+ domain: [0, 1],
+ range: ['2017-01-03 12:00', '2017-02-15 12:00'],
+ rangeslider: { range: ['2017-01-03 12:00', '2017-02-15 12:00'] },
+ title: 'Date',
+ type: 'date',
+ },
+ yaxis: {
+ autorange: true,
+ domain: [0, 1],
+ range: [114.609999778, 137.410004222],
+ type: 'linear',
+ },
+ ...layout,
+ };
+
+ return ;
+};
diff --git a/public/components/visualizations/charts/financial/candle_stick/candle_stick_type.ts b/public/components/visualizations/charts/financial/candle_stick/candle_stick_type.ts
new file mode 100644
index 0000000000..d7d17db808
--- /dev/null
+++ b/public/components/visualizations/charts/financial/candle_stick/candle_stick_type.ts
@@ -0,0 +1,81 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { CandleStick } from './candle_stick';
+import { getPlotlySharedConfigs, getPlotlyCategory } from '../../shared/shared_configs';
+import { LensIconChartBar } from '../../../assets/chart_bar';
+import { VizDataPanel } from '../../../../explorer/visualizations/config_panel/config_editor/default_vis_editor';
+import { ConfigEditor } from '../../../../explorer/visualizations/config_panel/config_editor/config_editor';
+import { ConfigValueOptions } from '../../../../explorer/visualizations/config_panel/config_editor/config_controls';
+
+const sharedConfigs = getPlotlySharedConfigs();
+const VIS_CATEGORY = getPlotlyCategory();
+
+export interface BarTypeParams {}
+
+export const createCandleStickDefinition = (params: BarTypeParams = {}) => ({
+ name: 'candle_stick',
+ type: 'candle_stick',
+ id: 'candle_stick',
+ label: 'Candle Stick',
+ fullLabel: 'Candle Stick',
+ selection: {
+ dataLoss: 'nothing',
+ },
+ category: VIS_CATEGORY.BASICS,
+ icon: LensIconChartBar,
+ categoryAxis: 'xaxis',
+ seriesAxis: 'yaxis',
+ orientation: 'v',
+ component: CandleStick,
+ editorConfig: {
+ panelTabs: [
+ {
+ id: 'data-panel',
+ name: 'Data',
+ mapTo: 'dataConfig',
+ editor: VizDataPanel,
+ sections: [
+ {
+ id: 'value_options',
+ name: 'Value options',
+ editor: ConfigValueOptions,
+ mapTo: 'valueOptions',
+ schemas: [
+ {
+ name: 'X-axis',
+ isSingleSelection: true,
+ component: null,
+ mapTo: 'xaxis',
+ },
+ {
+ name: 'Y-axis',
+ isSingleSelection: false,
+ component: null,
+ mapTo: 'yaxis',
+ },
+ ],
+ },
+ ],
+ },
+ {
+ id: 'style-panel',
+ name: 'Layout',
+ mapTo: 'layoutConfig',
+ editor: ConfigEditor,
+ content: [],
+ },
+ ],
+ },
+ visConfig: {
+ layout: {
+ ...sharedConfigs.layout,
+ },
+ config: {
+ ...sharedConfigs.config,
+ },
+ isUniColor: false,
+ },
+});
diff --git a/public/components/visualizations/charts/financial/gauge/gauge.tsx b/public/components/visualizations/charts/financial/gauge/gauge.tsx
new file mode 100644
index 0000000000..711f4d9e2f
--- /dev/null
+++ b/public/components/visualizations/charts/financial/gauge/gauge.tsx
@@ -0,0 +1,105 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useMemo } from 'react';
+import { indexOf } from 'lodash';
+import Plotly from 'plotly.js-dist';
+import { Plt } from '../../../plotly/plot';
+import { NUMERICAL_FIELDS } from '../../../../../../common/constants/shared';
+import { PLOTLY_GAUGE_COLUMN_NUMBER } from '../../../../../../common/constants/explorer';
+
+export const Gauge = ({ visualizations, layout, config }: any) => {
+ const {
+ data,
+ metadata: { fields },
+ } = visualizations.data.rawVizData;
+
+ const { dataConfig = {}, layoutConfig = {} } = visualizations.data.userConfigs;
+
+ const series =
+ dataConfig?.valueOptions && dataConfig?.valueOptions?.series
+ ? dataConfig.valueOptions.series
+ : [];
+
+ const value =
+ dataConfig?.valueOptions && dataConfig?.valueOptions?.value
+ ? dataConfig.valueOptions.value
+ : [];
+
+ const thresholds = dataConfig?.thresholds || [];
+
+ const gaugeData: Plotly.Data[] = useMemo(() => {
+ let calculatedGaugeData: Plotly.Data[] = [];
+ if (series && series[0] && value && value[0]) {
+ if (indexOf(NUMERICAL_FIELDS, series[0].type) > 0) {
+ calculatedGaugeData = [
+ ...data[value[0].name].map((dimesionSlice, index) => ({
+ field_name: dimesionSlice,
+ value: data[series[0].name][index],
+ })),
+ ];
+ } else {
+ value.map((val) => {
+ const selectedSeriesIndex = indexOf(data[series[0].name], val.name);
+ fields.map((field) => {
+ if (field.name !== series[0].name) {
+ calculatedGaugeData.push({
+ field_name: field.name,
+ value: data[field.name][selectedSeriesIndex],
+ });
+ }
+ });
+ });
+ }
+
+ return calculatedGaugeData.map((gauge, index) => {
+ return {
+ type: 'indicator',
+ mode: 'gauge+number+delta',
+ value: gauge.value || 0,
+ title: {
+ text: gauge.field_name,
+ font: { size: 14 },
+ },
+ domain: {
+ row: Math.floor(index / PLOTLY_GAUGE_COLUMN_NUMBER),
+ column: index % PLOTLY_GAUGE_COLUMN_NUMBER,
+ },
+ gauge: {
+ ...(thresholds && {
+ threshold: {
+ line: { color: thresholds[0]?.color || 'red', width: 4 },
+ thickness: 0.75,
+ value: thresholds[0]?.value || 0,
+ },
+ }),
+ },
+ };
+ });
+ }
+ return calculatedGaugeData;
+ }, [series, value, data, fields, thresholds]);
+
+ const mergedLayout = useMemo(() => {
+ const isAtleastOneFullRow = Math.floor(gaugeData.length / PLOTLY_GAUGE_COLUMN_NUMBER) > 0;
+ return {
+ grid: {
+ rows: Math.floor(gaugeData.length / PLOTLY_GAUGE_COLUMN_NUMBER) + 1,
+ columns: isAtleastOneFullRow ? PLOTLY_GAUGE_COLUMN_NUMBER : gaugeData.length,
+ pattern: 'independent',
+ },
+ ...layout,
+ ...(layoutConfig.layout && layoutConfig.layout),
+ title: dataConfig?.panelOptions?.title || layoutConfig.layout?.title || '',
+ };
+ }, [layout, gaugeData.length, layoutConfig.layout, dataConfig?.panelOptions?.title]);
+
+ const mergedConfigs = {
+ ...config,
+ ...(layoutConfig.config && layoutConfig.config),
+ };
+
+ return ;
+};
diff --git a/public/components/visualizations/charts/financial/gauge/gauge_type.ts b/public/components/visualizations/charts/financial/gauge/gauge_type.ts
new file mode 100644
index 0000000000..8201814ca5
--- /dev/null
+++ b/public/components/visualizations/charts/financial/gauge/gauge_type.ts
@@ -0,0 +1,91 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { Gauge } from './gauge';
+import { getPlotlySharedConfigs, getPlotlyCategory } from '../../shared/shared_configs';
+import { LensIconChartLine } from '../../../assets/chart_line';
+import { VizDataPanel } from '../../../../explorer/visualizations/config_panel/config_editor/default_vis_editor';
+import { ConfigEditor } from '../../../../explorer/visualizations/config_panel/config_editor/config_editor';
+import {
+ ConfigValueOptions,
+ ConfigThresholds,
+ ConfigGaugeValueOptions,
+} from '../../../../explorer/visualizations/config_panel/config_editor/config_controls';
+
+const sharedConfigs = getPlotlySharedConfigs();
+const VIS_CATEGORY = getPlotlyCategory();
+
+export const createGaugeTypeDefinition = (params: any = {}) => ({
+ name: 'Gauge',
+ type: 'indicator',
+ id: 'gauge',
+ label: 'Gauge',
+ fullLabel: 'Gauge',
+ iconType: 'visGauge',
+ category: VIS_CATEGORY.BASICS,
+ selection: {
+ dataLoss: 'nothing',
+ },
+ icon: LensIconChartLine,
+ valueSeries: 'yaxis',
+ editorConfig: {
+ panelTabs: [
+ {
+ id: 'data-panel',
+ name: 'Data',
+ mapTo: 'dataConfig',
+ editor: VizDataPanel,
+ sections: [
+ {
+ id: 'value_options',
+ name: 'Value options',
+ editor: ConfigGaugeValueOptions,
+ mapTo: 'valueOptions',
+ schemas: [
+ {
+ name: 'Series',
+ isSingleSelection: true,
+ onChangeHandler: 'setXaxisSelections',
+ component: null,
+ mapTo: 'series',
+ },
+ {
+ name: 'Value',
+ isSingleSelection: false,
+ onChangeHandler: 'setYaxisSelections',
+ component: null,
+ mapTo: 'value',
+ },
+ ],
+ },
+ {
+ id: 'thresholds',
+ name: 'Thresholds',
+ editor: ConfigThresholds,
+ mapTo: 'thresholds',
+ defaultState: [],
+ schemas: [],
+ },
+ ],
+ },
+ {
+ id: 'style-panel',
+ name: 'Layout',
+ mapTo: 'layoutConfig',
+ editor: ConfigEditor,
+ content: [],
+ },
+ ],
+ },
+ visConfig: {
+ layout: {
+ ...sharedConfigs.layout,
+ },
+ config: {
+ ...sharedConfigs.config,
+ },
+ },
+ component: Gauge,
+});
diff --git a/public/components/visualizations/charts/helpers/index.ts b/public/components/visualizations/charts/helpers/index.ts
new file mode 100644
index 0000000000..94a4ef1448
--- /dev/null
+++ b/public/components/visualizations/charts/helpers/index.ts
@@ -0,0 +1,6 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { getDefaultVizConfigPanelTabs, getVizContainerProps } from './viz_types';
diff --git a/public/components/visualizations/charts/helpers/viz_types.ts b/public/components/visualizations/charts/helpers/viz_types.ts
new file mode 100644
index 0000000000..4b7eb2332f
--- /dev/null
+++ b/public/components/visualizations/charts/helpers/viz_types.ts
@@ -0,0 +1,54 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { isEmpty, take } from 'lodash';
+import { getVisType } from '../vis_types';
+import { IVisualizationContainerProps, IField, IQuery } from '../../../../../common/types/explorer';
+
+interface IVizContainerProps {
+ vizId: string;
+ appData?: { fromApp: boolean };
+ rawVizData?: any;
+ query?: IQuery;
+ indexFields?: IField[];
+ userConfigs?: any;
+ defaultAxes?: {
+ xaxis: IField[];
+ yaxis: IField[];
+ };
+}
+
+const getDefaultXYAxisLabels = (vizFields: string[]) => {
+ if (isEmpty(vizFields)) return {};
+ return {
+ xaxis: [vizFields[vizFields.length - 1]] || [],
+ yaxis: take(vizFields, vizFields.length - 1 > 0 ? vizFields.length - 1 : 1) || [],
+ };
+};
+
+export const getVizContainerProps = ({
+ vizId,
+ rawVizData = {},
+ query = {},
+ indexFields = {},
+ userConfigs = {},
+ appData = {},
+}: IVizContainerProps): IVisualizationContainerProps => {
+ return {
+ data: {
+ appData: { ...appData },
+ rawVizData: { ...rawVizData },
+ query: { ...query },
+ indexFields: { ...indexFields },
+ userConfigs: { ...userConfigs },
+ defaultAxes: {
+ ...getDefaultXYAxisLabels(rawVizData?.metadata?.fields),
+ },
+ },
+ vis: {
+ ...getVisType(vizId),
+ },
+ };
+};
diff --git a/public/components/visualizations/charts/histogram/histogram.tsx b/public/components/visualizations/charts/histogram/histogram.tsx
new file mode 100644
index 0000000000..28c9adb96c
--- /dev/null
+++ b/public/components/visualizations/charts/histogram/histogram.tsx
@@ -0,0 +1,42 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { take, merge, isEmpty } from 'lodash';
+import { Plt } from '../../plotly/plot';
+import { PLOTLY_COLOR } from '../../../../../common/constants/shared';
+
+export const Histogram = ({ visualizations, layout, config }: any) => {
+ const { vis } = visualizations;
+ const {
+ data = {},
+ metadata: { fields },
+ } = visualizations.data.rawVizData;
+ const { defaultAxes } = visualizations.data.defaultAxes;
+ const { xaxis = null, yaxis = null } = visualizations.data.userConfigs;
+ const lastIndex = fields.length - 1;
+
+ let valueSeries;
+ if (!isEmpty(xaxis) && !isEmpty(yaxis)) {
+ valueSeries = [
+ ...visualizations?.data?.userConfigs[vis.seriesAxis].map((item) => ({
+ ...item,
+ name: item.label,
+ })),
+ ];
+ } else {
+ valueSeries = defaultAxes?.yaxis || take(fields, lastIndex > 0 ? lastIndex : 1);
+ }
+
+ const hisValues = valueSeries.map((field: any) => {
+ return {
+ x: data[xaxis ? xaxis[0]?.label : fields[lastIndex].name],
+ type: 'histogram',
+ name: field.name,
+ };
+ });
+
+ return ;
+};
diff --git a/public/components/visualizations/charts/histogram/histogram_type.ts b/public/components/visualizations/charts/histogram/histogram_type.ts
new file mode 100644
index 0000000000..fbc9543f56
--- /dev/null
+++ b/public/components/visualizations/charts/histogram/histogram_type.ts
@@ -0,0 +1,76 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { Histogram } from './histogram';
+import { getPlotlySharedConfigs, getPlotlyCategory } from '../shared/shared_configs';
+import { LensIconChartLine } from '../../assets/chart_line';
+import { VizDataPanel } from '../../../explorer/visualizations/config_panel/config_editor/default_vis_editor';
+import { ConfigEditor } from '../../../explorer/visualizations/config_panel/config_editor/config_editor';
+import { ConfigValueOptions } from '../../../explorer/visualizations/config_panel/config_editor/config_controls';
+
+const sharedConfigs = getPlotlySharedConfigs();
+const VIS_CATEGORY = getPlotlyCategory();
+
+export const createHistogramVisDefinition = (params = {}) => ({
+ name: 'histogram',
+ type: 'histogram',
+ id: 'histogram',
+ label: 'Histogram',
+ fullLabel: 'Histogram',
+ category: VIS_CATEGORY.BASICS,
+ selection: {
+ dataLoss: 'nothing',
+ },
+ valueSeries: 'yaxis',
+ icon: LensIconChartLine,
+ editorConfig: {
+ panelTabs: [
+ {
+ id: 'data-panel',
+ name: 'Data',
+ mapTo: 'dataConfig',
+ editor: VizDataPanel,
+ sections: [
+ {
+ id: 'value_options',
+ name: 'Value options',
+ editor: ConfigValueOptions,
+ mapTo: 'valueOptions',
+ schemas: [
+ {
+ name: 'X-axis',
+ isSingleSelection: true,
+ component: null,
+ mapTo: 'xaxis',
+ },
+ {
+ name: 'Y-axis',
+ isSingleSelection: false,
+ component: null,
+ mapTo: 'yaxis',
+ },
+ ],
+ },
+ ],
+ },
+ {
+ id: 'style-panel',
+ name: 'Layout',
+ mapTo: 'layoutConfig',
+ editor: ConfigEditor,
+ content: [],
+ },
+ ],
+ },
+ visConfig: {
+ layout: {
+ ...sharedConfigs.layout,
+ },
+ config: {
+ ...sharedConfigs.config,
+ },
+ },
+ component: Histogram,
+});
diff --git a/public/components/visualizations/charts/horizontal_bar.tsx b/public/components/visualizations/charts/horizontal_bar.tsx
new file mode 100644
index 0000000000..0875f38619
--- /dev/null
+++ b/public/components/visualizations/charts/horizontal_bar.tsx
@@ -0,0 +1,47 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { merge } from 'lodash';
+import { Bar } from './bar/bar';
+
+interface IBarTrace {
+ xvalues: any[];
+ yvalues: any[];
+ mode: string;
+ name: string;
+}
+
+export interface IStackedBarProps {
+ name: string;
+ barValues: IBarTrace[];
+ layoutConfig?: any;
+}
+
+export const HorizontalBar = ({
+ visualizations,
+ layoutConfig = {},
+ dispatch,
+ customVizData,
+}: any) => {
+ // const horizontalBarLayoutConfig = merge(
+ // {
+ // yaxis: {
+ // automargin: true,
+ // },
+ // },
+ // layoutConfig
+ // );
+
+ return (
+
+ );
+};
diff --git a/public/components/visualizations/charts/lines/line.tsx b/public/components/visualizations/charts/lines/line.tsx
new file mode 100644
index 0000000000..4ce620efd9
--- /dev/null
+++ b/public/components/visualizations/charts/lines/line.tsx
@@ -0,0 +1,106 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useMemo } from 'react';
+import { take, isEmpty, last } from 'lodash';
+import { Plt } from '../../plotly/plot';
+import { AvailabilityUnitType } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_availability';
+import { ThresholdUnitType } from '../../../event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_thresholds';
+
+export const Line = ({ visualizations, layout, config }: any) => {
+ const {
+ data = {},
+ metadata: { fields },
+ } = visualizations.data.rawVizData;
+ const { defaultAxes } = visualizations.data;
+ const {
+ dataConfig = {},
+ layoutConfig = {},
+ availabilityConfig = {},
+ } = visualizations?.data?.userConfigs;
+ const xaxis =
+ dataConfig?.valueOptions && dataConfig.valueOptions.xaxis ? dataConfig.valueOptions.xaxis : [];
+ const yaxis =
+ dataConfig?.valueOptions && dataConfig.valueOptions.xaxis ? dataConfig.valueOptions.yaxis : [];
+ const lastIndex = fields.length - 1;
+ const mode =
+ dataConfig?.chartOptions && dataConfig.chartOptions.mode && dataConfig.chartOptions.mode[0]
+ ? dataConfig.chartOptions.mode[0].modeId
+ : 'line';
+
+ let valueSeries;
+ if (!isEmpty(xaxis) && !isEmpty(yaxis)) {
+ valueSeries = [...yaxis];
+ } else {
+ valueSeries = defaultAxes.yaxis || take(fields, lastIndex > 0 ? lastIndex : 1);
+ }
+
+ const [calculatedLayout, lineValues] = useMemo(() => {
+ let calculatedLineValues = valueSeries.map((field: any) => {
+ return {
+ x: data[!isEmpty(xaxis) ? xaxis[0]?.label : fields[lastIndex].name],
+ y: data[field.name],
+ type: 'line',
+ name: field.name,
+ mode,
+ };
+ });
+
+ const mergedLayout = {
+ ...layout,
+ ...layoutConfig.layout,
+ title: dataConfig?.panelOptions?.title || layoutConfig.layout?.title || '',
+ };
+
+ if (dataConfig.thresholds || availabilityConfig.level) {
+ const thresholdTraces = {
+ x: [],
+ y: [],
+ mode: 'text',
+ text: [],
+ };
+ const thresholds = dataConfig.thresholds ? dataConfig.thresholds : [];
+ const levels = availabilityConfig.level ? availabilityConfig.level : [];
+
+ const mapToLine = (list: ThresholdUnitType[] | AvailabilityUnitType[], lineStyle: any) => {
+ return list.map((thr: ThresholdUnitType) => {
+ thresholdTraces.x.push(
+ data[!isEmpty(xaxis) ? xaxis[xaxis.length - 1]?.label : fields[lastIndex].name][0]
+ );
+ thresholdTraces.y.push(thr.value * (1 + 0.06));
+ thresholdTraces.text.push(thr.name);
+ return {
+ type: 'line',
+ x0: data[!isEmpty(xaxis) ? xaxis[0]?.label : fields[lastIndex].name][0],
+ y0: thr.value,
+ x1: last(data[!isEmpty(xaxis) ? xaxis[0]?.label : fields[lastIndex].name]),
+ y1: thr.value,
+ name: thr.name || '',
+ opacity: 0.7,
+ line: {
+ color: thr.color,
+ width: 3,
+ ...lineStyle,
+ },
+ };
+ });
+ };
+
+ mergedLayout.shapes = [
+ ...mapToLine(thresholds, { dash: 'dashdot' }),
+ ...mapToLine(levels, {}),
+ ];
+ calculatedLineValues = [...calculatedLineValues, thresholdTraces];
+ }
+ return [mergedLayout, calculatedLineValues];
+ }, [data, fields, lastIndex, layout, layoutConfig, xaxis, yaxis, mode, valueSeries]);
+
+ const mergedConfigs = {
+ ...config,
+ ...(layoutConfig.config && layoutConfig.config),
+ };
+
+ return ;
+};
diff --git a/public/components/visualizations/charts/lines/line_type.ts b/public/components/visualizations/charts/lines/line_type.ts
new file mode 100644
index 0000000000..4f80a6d1a1
--- /dev/null
+++ b/public/components/visualizations/charts/lines/line_type.ts
@@ -0,0 +1,143 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { Line } from './line';
+import { getPlotlySharedConfigs, getPlotlyCategory } from '../shared/shared_configs';
+import { LensIconChartLine } from '../../assets/chart_line';
+import { PLOTLY_COLOR } from '../../../../../common/constants/shared';
+import { VizDataPanel } from '../../../explorer/visualizations/config_panel/config_editor/default_vis_editor';
+import { ConfigEditor } from '../../../explorer/visualizations/config_panel/config_editor/config_editor';
+import {
+ ConfigValueOptions,
+ ConfigThresholds,
+} from '../../../explorer/visualizations/config_panel/config_editor/config_controls';
+import { ConfigAvailability } from '../../../explorer/visualizations/config_panel/config_editor/config_controls/config_availability';
+
+const sharedConfigs = getPlotlySharedConfigs();
+const VIS_CATEGORY = getPlotlyCategory();
+
+export const createLineTypeDefinition = (params: any = {}) => ({
+ name: 'line',
+ type: 'line',
+ id: 'line',
+ label: 'Line',
+ fullLabel: 'Line',
+ iconType: 'visLine',
+ category: VIS_CATEGORY.BASICS,
+ selection: {
+ dataLoss: 'nothing',
+ },
+ icon: LensIconChartLine,
+ categoryAxis: 'xaxis',
+ seriesAxis: 'yaxis',
+ editorConfig: {
+ panelTabs: [
+ {
+ id: 'data-panel',
+ name: 'Data',
+ mapTo: 'dataConfig',
+ editor: VizDataPanel,
+ sections: [
+ {
+ id: 'value_options',
+ name: 'Value options',
+ editor: ConfigValueOptions,
+ mapTo: 'valueOptions',
+ schemas: [
+ {
+ name: 'X-axis',
+ isSingleSelection: true,
+ component: null,
+ mapTo: 'xaxis',
+ },
+ {
+ name: 'Y-axis',
+ isSingleSelection: false,
+ component: null,
+ mapTo: 'yaxis',
+ },
+ ],
+ },
+ {
+ id: 'chart_options',
+ name: 'Chart options',
+ editor: ConfigValueOptions,
+ mapTo: 'chartOptions',
+ schemas: [
+ {
+ name: 'Mode',
+ isSingleSelection: true,
+ component: null,
+ mapTo: 'mode',
+ props: {
+ dropdownList: [
+ { name: 'Markers', modeId: 'markers' },
+ { name: 'Lines', modeId: 'lines' },
+ { name: 'Lines + Markers', modeId: 'lines+markers' },
+ ],
+ defaultSelections: [{ name: 'Lines', modeId: 'lines' }],
+ },
+ },
+ ],
+ },
+ {
+ id: 'thresholds',
+ name: 'Thresholds',
+ editor: ConfigThresholds,
+ mapTo: 'thresholds',
+ defaultState: [],
+ schemas: [],
+ },
+ ],
+ },
+ {
+ id: 'style-panel',
+ name: 'Layout',
+ mapTo: 'layoutConfig',
+ editor: ConfigEditor,
+ content: [],
+ },
+ {
+ id: 'availability-panel',
+ name: 'Availability',
+ mapTo: 'availabilityConfig',
+ editor: ConfigAvailability,
+ },
+ ],
+ },
+ visConfig: {
+ layout: {
+ ...sharedConfigs.layout,
+ ...{
+ colorway: PLOTLY_COLOR,
+ plot_bgcolor: 'rgba(0, 0, 0, 0)',
+ paper_bgcolor: 'rgba(0, 0, 0, 0)',
+ xaxis: {
+ fixedrange: true,
+ showgrid: false,
+ visible: true,
+ },
+ yaxis: {
+ fixedrange: true,
+ showgrid: false,
+ visible: true,
+ },
+ },
+ },
+ config: {
+ ...sharedConfigs.config,
+ ...{
+ barmode: 'line',
+ xaxis: {
+ automargin: true,
+ },
+ yaxis: {
+ automargin: true,
+ },
+ },
+ },
+ },
+ component: Line,
+});
diff --git a/public/components/visualizations/charts/maps/heatmap.tsx b/public/components/visualizations/charts/maps/heatmap.tsx
new file mode 100644
index 0000000000..cb565284f3
--- /dev/null
+++ b/public/components/visualizations/charts/maps/heatmap.tsx
@@ -0,0 +1,106 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useMemo } from 'react';
+import { uniq, has, isArray, isEmpty } from 'lodash';
+import Plotly from 'plotly.js-dist';
+import { Plt } from '../../plotly/plot';
+import { PLOTLY_COLOR } from '../../../../../common/constants/shared';
+import { EmptyPlaceholder } from '../../../../components/explorer/visualizations/shared_components/empty_placeholder';
+
+export const HeatMap = ({ visualizations, layout, config }: any) => {
+ const {
+ data,
+ metadata: { fields },
+ } = visualizations.data.rawVizData;
+ const { dataConfig = {}, layoutConfig = {} } = visualizations?.data?.userConfigs;
+
+ if (fields.length < 3) return ;
+
+ const xaxisField = fields[fields.length - 2];
+ const yaxisField = fields[fields.length - 1];
+ const zMetrics =
+ dataConfig?.valueOptions && dataConfig?.valueOptions.zaxis
+ ? dataConfig?.valueOptions.zaxis[0]
+ : fields[fields.length - 3];
+ const uniqueYaxis = uniq(data[yaxisField.name]);
+ const uniqueXaxis = uniq(data[xaxisField.name]);
+ const uniqueYaxisLength = uniqueYaxis.length;
+ const uniqueXaxisLength = uniqueXaxis.length;
+
+ if (
+ isEmpty(xaxisField) ||
+ isEmpty(yaxisField) ||
+ isEmpty(zMetrics) ||
+ isEmpty(data[xaxisField.name]) ||
+ isEmpty(data[yaxisField.name]) ||
+ isEmpty(data[zMetrics.name])
+ )
+ return ;
+
+ const colorScaleValues = [...PLOTLY_COLOR.map((clr, index) => [index, clr])];
+
+ const calculatedHeapMapZaxis: Plotly.Data[] = useMemo(() => {
+ const heapMapZaxis = [];
+ const buckets = {};
+
+ // maps bukcets to metrics
+ for (let i = 0; i < data[xaxisField.name].length; i++) {
+ buckets[`${data[xaxisField.name][i]},${data[yaxisField.name][i]}`] = data[zMetrics.name][i];
+ }
+
+ // initialize empty 2 dimensional array, inner loop for each xaxis field, outer loop for yaxis
+ for (let i = 0; i < uniqueYaxisLength; i++) {
+ const innerBuckets = [];
+ for (let j = 0; j < uniqueXaxisLength; j++) {
+ innerBuckets.push(null);
+ }
+ heapMapZaxis.push(innerBuckets);
+ }
+
+ // fill in each bucket
+ for (let i = 0; i < uniqueYaxisLength; i++) {
+ for (let j = 0; j < uniqueXaxisLength; j++) {
+ if (has(buckets, `${uniqueXaxis[j]},${uniqueYaxis[i]}`)) {
+ heapMapZaxis[i][j] = buckets[`${uniqueXaxis[j]},${uniqueYaxis[i]}`];
+ }
+ }
+ }
+
+ return heapMapZaxis;
+ }, [
+ data,
+ uniqueYaxis,
+ uniqueXaxis,
+ uniqueYaxisLength,
+ uniqueXaxisLength,
+ xaxisField,
+ yaxisField,
+ zMetrics,
+ ]);
+
+ const heapMapData = [
+ {
+ z: calculatedHeapMapZaxis,
+ x: uniqueXaxis,
+ y: uniqueYaxis,
+ colorscale: colorScaleValues,
+ type: 'heatmap',
+ },
+ ];
+
+ const mergedLayout = {
+ ...layout,
+ ...(layoutConfig.layout && layoutConfig.layout),
+ title: dataConfig?.panelOptions?.title || layoutConfig.layout?.title || zMetrics.name || '',
+ };
+
+ const mergedConfigs = {
+ ...config,
+ ...(layoutConfig.config && layoutConfig.config),
+ };
+
+ return ;
+};
diff --git a/public/components/visualizations/charts/maps/heatmap_type.ts b/public/components/visualizations/charts/maps/heatmap_type.ts
new file mode 100644
index 0000000000..daa5fa3b85
--- /dev/null
+++ b/public/components/visualizations/charts/maps/heatmap_type.ts
@@ -0,0 +1,75 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { HeatMap } from './heatmap';
+import { getPlotlySharedConfigs, getPlotlyCategory } from '../shared/shared_configs';
+import { LensIconChartPie } from '../../assets/chart_pie';
+import { VizDataPanel } from '../../../explorer/visualizations/config_panel/config_editor/default_vis_editor';
+import { ConfigEditor } from '../../../explorer/visualizations/config_panel/config_editor/config_editor';
+import { ConfigValueOptions } from '../../../explorer/visualizations/config_panel/config_editor/config_controls';
+
+const sharedConfigs = getPlotlySharedConfigs();
+const VIS_CATEGORY = getPlotlyCategory();
+
+export const createMapsVisDefinition = () => ({
+ name: 'heatmap',
+ type: 'heatmap',
+ id: 'heatmap',
+ label: 'Heatmap',
+ fullLabel: 'Hubble',
+ iconType: 'heatmap',
+ category: VIS_CATEGORY.BASICS,
+ selection: {
+ dataLoss: 'nothing',
+ },
+ icon: LensIconChartPie,
+ editorConfig: {
+ panelTabs: [
+ {
+ id: 'data-panel',
+ name: 'Data',
+ mapTo: 'dataConfig',
+ editor: VizDataPanel,
+ sections: [
+ {
+ id: 'value_options',
+ name: 'Value options',
+ editor: ConfigValueOptions,
+ mapTo: 'valueOptions',
+ schemas: [
+ {
+ name: 'Z-axis',
+ isSingleSelection: true,
+ component: null,
+ mapTo: 'zaxis',
+ },
+ ],
+ },
+ ],
+ },
+ {
+ id: 'style-panel',
+ name: 'Layout',
+ mapTo: 'layoutConfig',
+ editor: ConfigEditor,
+ content: [],
+ },
+ ],
+ },
+ visConfig: {
+ layout: {
+ ...sharedConfigs.layout,
+ ...{
+ plot_bgcolor: 'rgba(0, 0, 0, 0)',
+ paper_bgcolor: 'rgba(0, 0, 0, 0)',
+ margin: { left: 60 },
+ },
+ },
+ config: {
+ ...sharedConfigs.config,
+ },
+ },
+ component: HeatMap,
+});
diff --git a/public/components/visualizations/charts/maps/treemap_type.ts b/public/components/visualizations/charts/maps/treemap_type.ts
new file mode 100644
index 0000000000..d25665e1ec
--- /dev/null
+++ b/public/components/visualizations/charts/maps/treemap_type.ts
@@ -0,0 +1,81 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { TreeMap } from './treemaps';
+import { getPlotlySharedConfigs, getPlotlyCategory } from '../shared/shared_configs';
+import { LensIconChartBar } from '../../assets/chart_bar';
+import { VizDataPanel } from '../../../explorer/visualizations/config_panel/config_editor/default_vis_editor';
+import { ConfigEditor } from '../../../explorer/visualizations/config_panel/config_editor/config_editor';
+import { ConfigValueOptions } from '../../../explorer/visualizations/config_panel/config_editor/config_controls';
+
+const sharedConfigs = getPlotlySharedConfigs();
+const VIS_CATEGORY = getPlotlyCategory();
+
+export interface BarTypeParams {}
+
+export const createTreeMapDefinition = (params: BarTypeParams = {}) => ({
+ name: 'tree_map',
+ type: 'tree_map',
+ id: 'tree_map',
+ label: 'Tree Map',
+ fullLabel: 'Tree Map',
+ selection: {
+ dataLoss: 'nothing',
+ },
+ category: VIS_CATEGORY.BASICS,
+ icon: LensIconChartBar,
+ categoryAxis: 'xaxis',
+ seriesAxis: 'yaxis',
+ orientation: 'v',
+ component: TreeMap,
+ editorConfig: {
+ panelTabs: [
+ {
+ id: 'data-panel',
+ name: 'Data',
+ mapTo: 'dataConfig',
+ editor: VizDataPanel,
+ sections: [
+ {
+ id: 'value_options',
+ name: 'Value options',
+ editor: ConfigValueOptions,
+ mapTo: 'valueOptions',
+ schemas: [
+ {
+ name: 'X-axis',
+ isSingleSelection: true,
+ component: null,
+ mapTo: 'xaxis',
+ },
+ {
+ name: 'Y-axis',
+ isSingleSelection: false,
+ component: null,
+ mapTo: 'yaxis',
+ },
+ ],
+ },
+ ],
+ },
+ {
+ id: 'style-panel',
+ name: 'Layout',
+ mapTo: 'layoutConfig',
+ editor: ConfigEditor,
+ content: [],
+ },
+ ],
+ },
+ visConfig: {
+ layout: {
+ ...sharedConfigs.layout,
+ },
+ config: {
+ ...sharedConfigs.config,
+ },
+ isUniColor: false,
+ },
+});
diff --git a/public/components/visualizations/charts/maps/treemaps.tsx b/public/components/visualizations/charts/maps/treemaps.tsx
new file mode 100644
index 0000000000..bdd014e64b
--- /dev/null
+++ b/public/components/visualizations/charts/maps/treemaps.tsx
@@ -0,0 +1,59 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+
+import { Plt } from '../../plotly/plot';
+
+export const TreeMap = ({ visualizations, layout, config }) => {
+ const labels = ['Eve', 'Cain', 'Seth', 'Enos', 'Noam', 'Abel', 'Awan', 'Enoch', 'Azura'];
+ const parents = ['', 'Eve', 'Eve', 'Seth', 'Seth', 'Eve', 'Eve', 'Awan', 'Eve'];
+ const treemapData = [
+ {
+ type: 'treemap',
+ labels,
+ parents,
+ values: [10, 14, 12, 10, 2, 6, 6, 1, 4],
+ textinfo: 'label+value+percent parent+percent entry',
+ domain: { x: [0, 0.48] },
+ outsidetextfont: { size: 20, color: '#377eb8' },
+ marker: { line: { width: 2 } },
+ pathbar: { visible: false },
+ },
+ {
+ type: 'treemap',
+ branchvalues: 'total',
+ labels,
+ parents,
+ domain: { x: [0.52, 1] },
+ values: [65, 14, 12, 10, 2, 6, 6, 1, 4],
+ textinfo: 'label+value+percent parent+percent entry',
+ outsidetextfont: { size: 20, color: '#377eb8' },
+ marker: { line: { width: 2 } },
+ pathbar: { visible: false },
+ },
+ ];
+ const finalLayout = {
+ annotations: [
+ {
+ showarrow: false,
+ text: 'branchvalues: remainder ',
+ x: 0.25,
+ xanchor: 'center',
+ y: 1.1,
+ yanchor: 'bottom',
+ },
+ {
+ showarrow: false,
+ text: 'branchvalues: total ',
+ x: 0.75,
+ xanchor: 'center',
+ y: 1.1,
+ yanchor: 'bottom',
+ },
+ ],
+ };
+ return ;
+};
diff --git a/public/components/visualizations/charts/pie/pie.tsx b/public/components/visualizations/charts/pie/pie.tsx
new file mode 100644
index 0000000000..961d090d15
--- /dev/null
+++ b/public/components/visualizations/charts/pie/pie.tsx
@@ -0,0 +1,69 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { take, merge, isEmpty } from 'lodash';
+import { Plt } from '../../plotly/plot';
+import { PLOTLY_COLOR } from '../../../../../common/constants/shared';
+
+export const Pie = ({ visualizations, layout, config }: any) => {
+ const { vis } = visualizations;
+ const {
+ data,
+ metadata: { fields },
+ } = visualizations.data.rawVizData;
+ const { defaultAxes } = visualizations.data;
+ const { dataConfig = {}, layoutConfig = {} } = visualizations?.data?.userConfigs;
+ const xaxis =
+ dataConfig?.valueOptions && dataConfig.valueOptions.xaxis ? dataConfig.valueOptions.xaxis : [];
+ const yaxis =
+ dataConfig?.valueOptions && dataConfig.valueOptions.yaxis ? dataConfig.valueOptions.yaxis : [];
+ const type = dataConfig?.chartOptions?.mode ? dataConfig?.chartOptions?.mode[0]?.modeId : 'pie';
+ const lastIndex = fields.length - 1;
+
+ let valueSeries;
+ if (!isEmpty(xaxis) && !isEmpty(yaxis)) {
+ valueSeries = [...yaxis];
+ } else {
+ valueSeries = defaultAxes.yaxis || take(fields, lastIndex > 0 ? lastIndex : 1);
+ }
+
+ const pies = valueSeries.map((field: any, index) => {
+ return {
+ labels: data[xaxis ? xaxis[0]?.label : fields[lastIndex].name],
+ values: data[field.name],
+ type: 'pie',
+ name: field.name,
+ hole: type === 'pie' ? 0 : 0.5,
+ text: field.name,
+ textinfo: 'percent',
+ automargin: true,
+ textposition: 'outside',
+ domain: {
+ row: Math.floor(index / 3),
+ column: index % 3,
+ },
+ };
+ });
+
+ const isAtleastOneFullRow = Math.floor(valueSeries.length / 3) > 0;
+
+ const mergedLayout = {
+ grid: {
+ rows: Math.floor(valueSeries.length / 3) + 1,
+ columns: isAtleastOneFullRow ? 3 : valueSeries.length,
+ },
+ ...layout,
+ ...(layoutConfig.layout && layoutConfig.layout),
+ title: dataConfig?.panelOptions?.title || layoutConfig.layout?.title || '',
+ };
+
+ const mergedConfigs = {
+ ...config,
+ ...(layoutConfig.config && layoutConfig.config),
+ };
+
+ return ;
+};
diff --git a/public/components/visualizations/charts/pie/pie_type.ts b/public/components/visualizations/charts/pie/pie_type.ts
new file mode 100644
index 0000000000..721c4211d6
--- /dev/null
+++ b/public/components/visualizations/charts/pie/pie_type.ts
@@ -0,0 +1,117 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { Pie } from './pie';
+import { getPlotlySharedConfigs, getPlotlyCategory } from '../shared/shared_configs';
+import { LensIconChartPie } from '../../assets/chart_pie';
+import { PLOTLY_COLOR } from '../../../../../common/constants/shared';
+import { VizDataPanel } from '../../../explorer/visualizations/config_panel/config_editor/default_vis_editor';
+import { ConfigEditor } from '../../../explorer/visualizations/config_panel/config_editor/config_editor';
+import { ConfigValueOptions } from '../../../explorer/visualizations/config_panel/config_editor/config_controls';
+
+const sharedConfigs = getPlotlySharedConfigs();
+const VIS_CATEGORY = getPlotlyCategory();
+
+export const createPieTypeDefinition = (params: any) => ({
+ name: 'pie',
+ type: 'pie',
+ id: 'pie',
+ label: 'Pie',
+ fullLabel: 'Pie',
+ iconType: 'visPie',
+ category: VIS_CATEGORY.BASICS,
+ selection: {
+ dataLoss: 'nothing',
+ },
+ categoryAxis: 'xaxis',
+ seriesAxis: 'yaxis',
+ icon: LensIconChartPie,
+ editorConfig: {
+ panelTabs: [
+ {
+ id: 'data-panel',
+ name: 'Data',
+ mapTo: 'dataConfig',
+ editor: VizDataPanel,
+ sections: [
+ {
+ id: 'value_options',
+ name: 'Value options',
+ editor: ConfigValueOptions,
+ mapTo: 'valueOptions',
+ schemas: [
+ {
+ name: 'Label',
+ onChangeHandler: 'setXaxisSelections',
+ isSingleSelection: false,
+ component: null,
+ mapTo: 'xaxis',
+ },
+ {
+ name: 'Value',
+ onChangeHandler: 'setYaxisSelections',
+ isSingleSelection: false,
+ component: null,
+ mapTo: 'yaxis',
+ },
+ ],
+ },
+ {
+ id: 'chart_options',
+ name: 'Chart options',
+ editor: ConfigValueOptions,
+ mapTo: 'chartOptions',
+ schemas: [
+ {
+ name: 'Mode',
+ isSingleSelection: true,
+ component: null,
+ mapTo: 'mode',
+ props: {
+ dropdownList: [
+ { name: 'Pie', modeId: 'pie' },
+ { name: 'Donut', modeId: 'donut' },
+ ],
+ defaultSelections: [{ name: 'Pie', modeId: 'pie' }],
+ },
+ },
+ ],
+ },
+ ],
+ },
+ {
+ id: 'style-panel',
+ name: 'Layout',
+ mapTo: 'layoutConfig',
+ editor: ConfigEditor,
+ content: [],
+ },
+ ],
+ },
+ visConfig: {
+ layout: {
+ ...sharedConfigs.layout,
+ ...{
+ colorway: PLOTLY_COLOR,
+ plot_bgcolor: 'rgba(0, 0, 0, 0)',
+ paper_bgcolor: 'rgba(0, 0, 0, 0)',
+ xaxis: {
+ fixedrange: true,
+ showgrid: false,
+ visible: true,
+ },
+ yaxis: {
+ fixedrange: true,
+ showgrid: false,
+ visible: true,
+ },
+ },
+ },
+ config: {
+ ...sharedConfigs.config,
+ },
+ },
+ component: Pie,
+});
diff --git a/public/components/visualizations/charts/shared/shared_configs.ts b/public/components/visualizations/charts/shared/shared_configs.ts
new file mode 100644
index 0000000000..062f387856
--- /dev/null
+++ b/public/components/visualizations/charts/shared/shared_configs.ts
@@ -0,0 +1,47 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { forIn } from 'lodash';
+
+export const getPlotlySharedConfigs = () => {
+ return {
+ layout: {
+ showlegend: true,
+ margin: {
+ l: 60,
+ r: 30,
+ b: 30,
+ t: 50,
+ pad: 0,
+ },
+ height: 500,
+ legend: {
+ orientation: 'v',
+ traceorder: 'normal',
+ },
+ },
+ config: {
+ displaylogo: false,
+ responsive: true,
+ },
+ };
+};
+
+enum VIS_CATEGORY {
+ BASICS = 'Visualizations',
+}
+
+export const getPlotlyCategory = (type = 'enum') => {
+ switch (type) {
+ case 'enum':
+ return VIS_CATEGORY;
+ case 'list':
+ return Object.values(VIS_CATEGORY);
+ case 'keys':
+ return Object.keys(VIS_CATEGORY);
+ default:
+ return VIS_CATEGORY;
+ }
+};
diff --git a/public/components/visualizations/charts/text/text.tsx b/public/components/visualizations/charts/text/text.tsx
new file mode 100644
index 0000000000..f6248c3d0c
--- /dev/null
+++ b/public/components/visualizations/charts/text/text.tsx
@@ -0,0 +1,23 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { EuiMarkdownFormat } from '@elastic/eui';
+
+const DEFAULT_MARKDOWN = `## Text
+
+Welcome to text editor!
+
+With text editor, you are able to add text description(s) to your dashboards.`;
+
+export const Text = ({ visualizations }: any) => {
+ const { dataConfig = {} } = visualizations?.data?.userConfigs;
+
+ return (
+
+ {dataConfig.text?.markdown ? dataConfig.text?.markdown : DEFAULT_MARKDOWN}
+
+ );
+};
diff --git a/public/components/visualizations/charts/text/text_type.ts b/public/components/visualizations/charts/text/text_type.ts
new file mode 100644
index 0000000000..3a826498a5
--- /dev/null
+++ b/public/components/visualizations/charts/text/text_type.ts
@@ -0,0 +1,82 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { Text } from './text';
+import { getPlotlySharedConfigs, getPlotlyCategory } from '../shared/shared_configs';
+import { LensIconChartLine } from '../../assets/chart_line';
+import { PLOTLY_COLOR } from '../../../../../common/constants/shared';
+import { VizDataPanel } from '../../../explorer/visualizations/config_panel/config_editor/default_vis_editor';
+import { ConfigText } from '../../../explorer/visualizations/config_panel/config_editor/config_controls';
+
+const sharedConfigs = getPlotlySharedConfigs();
+const VIS_CATEGORY = getPlotlyCategory();
+
+export const createTextTypeDefinition = (params: any = {}) => ({
+ name: 'text',
+ type: 'text',
+ id: 'text',
+ label: 'Text',
+ fullLabel: 'Text',
+ iconType: 'visText',
+ category: VIS_CATEGORY.BASICS,
+ selection: {
+ dataLoss: 'nothing',
+ },
+ icon: LensIconChartLine,
+ categoryAxis: 'xaxis',
+ seriesAxis: 'yaxis',
+ editorConfig: {
+ panelTabs: [
+ {
+ id: 'data-panel',
+ name: 'Data',
+ mapTo: 'dataConfig',
+ editor: VizDataPanel,
+ sections: [
+ {
+ id: 'text_editor',
+ name: 'Text',
+ editor: ConfigText,
+ mapTo: 'text',
+ schemas: [],
+ },
+ ],
+ },
+ ],
+ },
+ visConfig: {
+ layout: {
+ ...sharedConfigs.layout,
+ ...{
+ colorway: PLOTLY_COLOR,
+ plot_bgcolor: 'rgba(0, 0, 0, 0)',
+ paper_bgcolor: 'rgba(0, 0, 0, 0)',
+ xaxis: {
+ fixedrange: true,
+ showgrid: false,
+ visible: true,
+ },
+ yaxis: {
+ fixedrange: true,
+ showgrid: false,
+ visible: true,
+ },
+ },
+ },
+ config: {
+ ...sharedConfigs.config,
+ ...{
+ barmode: 'line',
+ xaxis: {
+ automargin: true,
+ },
+ yaxis: {
+ automargin: true,
+ },
+ },
+ },
+ },
+ component: Text,
+});
diff --git a/public/components/visualizations/charts/vis_types.ts b/public/components/visualizations/charts/vis_types.ts
new file mode 100644
index 0000000000..0d3998547d
--- /dev/null
+++ b/public/components/visualizations/charts/vis_types.ts
@@ -0,0 +1,34 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { createBarTypeDefinition } from './bar/bar_type';
+import { createHorizontalBarTypeDefinition } from './bar/horizontal_bar_type';
+import { createLineTypeDefinition } from './lines/line_type';
+import { createPieTypeDefinition } from './pie/pie_type';
+import { createHistogramVisDefinition } from './histogram/histogram_type';
+import { createBubbleVisDefinition } from './bubble/bubble_type';
+import { createMapsVisDefinition } from './maps/heatmap_type';
+import { createDatatableTypeDefinition } from './data_table/data_table_type';
+import { createGaugeTypeDefinition } from './financial/gauge/gauge_type';
+import { createTreeMapDefinition } from './maps/treemap_type';
+import { createTextTypeDefinition } from './text/text_type';
+
+export const VIS_TYPES = {
+ bar: createBarTypeDefinition,
+ horizontal_bar: createHorizontalBarTypeDefinition,
+ line: createLineTypeDefinition,
+ pie: createPieTypeDefinition,
+ histogram: createHistogramVisDefinition,
+ data_table: createDatatableTypeDefinition,
+ gauge: createGaugeTypeDefinition,
+ bubble: createBubbleVisDefinition,
+ heatmap: createMapsVisDefinition,
+ tree_map: createTreeMapDefinition,
+ text: createTextTypeDefinition,
+};
+
+export const getVisType = (visType: string, params: any = {}) => {
+ return VIS_TYPES[visType](params);
+};
diff --git a/public/components/visualizations/plotly/__tests__/__snapshots__/plotly.test.tsx.snap b/public/components/visualizations/plotly/__tests__/__snapshots__/plotly.test.tsx.snap
new file mode 100644
index 0000000000..5499f90258
--- /dev/null
+++ b/public/components/visualizations/plotly/__tests__/__snapshots__/plotly.test.tsx.snap
@@ -0,0 +1,321 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Ploty base component Renders Ploty base component 1`] = `
+
+
+
+
+
+`;
+
+exports[`Ploty base component Renders Ploty base component 2`] = `
+
+
+
+
+
+`;
diff --git a/public/components/visualizations/plotly/__tests__/plotly.test.tsx b/public/components/visualizations/plotly/__tests__/plotly.test.tsx
new file mode 100644
index 0000000000..02fab5123e
--- /dev/null
+++ b/public/components/visualizations/plotly/__tests__/plotly.test.tsx
@@ -0,0 +1,69 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configure, mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import React from 'react';
+import { waitFor } from '@testing-library/react';
+import { Plt } from '../plot';
+import { LAYOUT_CONFIG } from '../../../../../test/event_analytics_constants';
+
+describe('Ploty base component', () => {
+ configure({ adapter: new Adapter() });
+
+ it('Renders Ploty base component', async () => {
+
+ const barValues = [{
+ displaylogo: false,
+ marker: {
+ color: [
+ "#3CA1C7",
+ "#8C55A3",
+ "#DB748A",
+ "#F2BE4B"
+ ]
+ },
+ name: "avg(FlightDelayMin)",
+ responsive: true,
+ type: 'bar',
+ x: [
+ "JetBeats",
+ "Logstash Airways",
+ "OpenSearch Dashboards Airlines",
+ "OpenSearch-Air"
+ ],
+ y: [
+ 45.957544288332315,
+ 49.55268688081657,
+ 46.368274582560296,
+ 47.41304347826087
+ ]
+ }];
+
+ const wrapper = mount(
+
+ );
+
+ wrapper.update();
+
+ await waitFor(() => {
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+});
\ No newline at end of file
diff --git a/public/components/visualizations/plotly/plot.tsx b/public/components/visualizations/plotly/plot.tsx
new file mode 100644
index 0000000000..1d7a7f1e9b
--- /dev/null
+++ b/public/components/visualizations/plotly/plot.tsx
@@ -0,0 +1,83 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import plotComponentFactory from 'react-plotly.js/factory';
+import Plotly from 'plotly.js-dist';
+import { uiSettingsService } from '../../../../common/utils';
+
+interface PltProps {
+ data: Plotly.Data[];
+ layout?: Partial;
+ config?: Partial;
+ onHoverHandler?: (event: Readonly) => void;
+ onUnhoverHandler?: (event: Readonly) => void;
+ onClickHandler?: (event: Readonly) => void;
+ height?: string;
+ dispatch?: (props: any) => void;
+}
+
+export function Plt(props: PltProps) {
+ const PlotComponent = plotComponentFactory(Plotly);
+ const darkLayout = uiSettingsService.get('theme:darkMode')
+ ? {
+ paper_bgcolor: '#1D1E24',
+ plot_bgcolor: '#1D1E24',
+ font: {
+ color: '#DFE5EF',
+ },
+ }
+ : {};
+
+ const finalLayout = {
+ autosize: true,
+ margin: {
+ l: 30,
+ r: 5,
+ b: 30,
+ t: 5,
+ pad: 4,
+ },
+ barmode: 'stack',
+ legend: {
+ orientation: 'h',
+ traceorder: 'normal',
+ },
+ showlegend: false,
+ hovermode: 'closest',
+ xaxis: {
+ showgrid: true,
+ zeroline: false,
+ rangemode: 'normal',
+ automargin: true,
+ },
+ yaxis: {
+ showgrid: true,
+ zeroline: false,
+ rangemode: 'normal',
+ },
+ ...darkLayout,
+ ...props.layout,
+ };
+
+ const finalConfig = {
+ displayModeBar: false,
+ ...props.config,
+ };
+
+ return (
+
+ );
+}
diff --git a/public/components/visualizations/plotly_default_config.ts b/public/components/visualizations/plotly_default_config.ts
new file mode 100644
index 0000000000..da1f83ddf7
--- /dev/null
+++ b/public/components/visualizations/plotly_default_config.ts
@@ -0,0 +1,34 @@
+export const DEFAULT_CONFIG = {
+ layout: {
+ autosize: true,
+ margin: {
+ l: 30,
+ r: 5,
+ b: 30,
+ t: 5,
+ pad: 4,
+ },
+ barmode: 'stack',
+ legend: {
+ orientation: 'h',
+ traceorder: 'normal',
+ },
+ showlegend: false,
+ hovermode: 'closest',
+ xaxis: {
+ showgrid: true,
+ zeroline: false,
+ rangemode: 'normal',
+ automargin: true,
+ },
+ yaxis: {
+ showgrid: true,
+ zeroline: false,
+ rangemode: 'normal',
+ },
+ displayModeBar: false,
+ },
+ config: {
+ displayModeBar: false,
+ },
+};
diff --git a/public/components/visualizations/visualization.tsx b/public/components/visualizations/visualization.tsx
new file mode 100644
index 0000000000..fb22f6bf64
--- /dev/null
+++ b/public/components/visualizations/visualization.tsx
@@ -0,0 +1,33 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { isArray } from 'lodash';
+import { VisualizationChart } from './visualization_chart';
+import { EmptyPlaceholder } from '../../components/explorer/visualizations/shared_components/empty_placeholder';
+
+interface IVisualizationProps {}
+
+export const Visualization = ({ visualizations }: IVisualizationProps) => {
+ const { data, vis } = visualizations;
+ const { metadata = {} } = visualizations?.data?.rawVizData;
+ const { fields = [] } = metadata;
+
+ // check viz data
+ const isVizDataValid = data && vis && visualizations?.data?.rawVizData;
+
+ // check fields
+ const isVizFieldValid = fields && isArray(fields) && fields.length > 0;
+
+ return (
+ <>
+ {isVizDataValid && isVizFieldValid ? (
+
+ ) : (
+
+ )}
+ >
+ );
+};
diff --git a/public/components/visualizations/visualization_chart.tsx b/public/components/visualizations/visualization_chart.tsx
new file mode 100644
index 0000000000..88bb34edd5
--- /dev/null
+++ b/public/components/visualizations/visualization_chart.tsx
@@ -0,0 +1,40 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useMemo } from 'react';
+import { take, merge, isEmpty } from 'lodash';
+
+interface IVisualizationChart {}
+
+export const VisualizationChart = ({ visualizations }: IVisualizationChart) => {
+ const { data, vis } = visualizations;
+ const {
+ metadata: { fields },
+ } = visualizations?.data?.rawVizData;
+ const { layout = {}, config = {} } = visualizations?.data?.userConfigs;
+ const Visualization = visualizations?.vis?.component;
+
+ const finalFigureConfig = useMemo(() => {
+ return {
+ ...vis.visConfig?.config,
+ ...config,
+ };
+ }, [config, vis]);
+
+ const finalFigureLayout = useMemo(() => {
+ return {
+ ...vis.visConfig?.layout,
+ ...layout,
+ };
+ }, [layout, vis]);
+
+ return (
+
+ );
+};
diff --git a/public/framework/redux/reducers/index.ts b/public/framework/redux/reducers/index.ts
new file mode 100644
index 0000000000..18565c69ce
--- /dev/null
+++ b/public/framework/redux/reducers/index.ts
@@ -0,0 +1,29 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { combineReducers } from 'redux';
+
+import queriesReducer from '../../../components/explorer/slices/query_slice';
+import queryResultsReducer from '../../../components/explorer/slices/query_result_slice';
+import queryTabReducer from '../../../components/explorer/slices/query_tab_slice';
+import FieldsReducer from '../../../components/explorer/slices/field_slice';
+import countDistributionReducer from '../../../components/explorer/slices/count_distribution_slice';
+import explorerVisualizationReducer from '../../../components/explorer/slices/visualization_slice';
+import explorerVisualizationConfigReducer from '../../../components/explorer/slices/viualization_config_slice';
+
+const rootReducer = combineReducers({
+ // explorer reducers
+ queries: queriesReducer,
+ queryResults: queryResultsReducer,
+ explorerTabs: queryTabReducer,
+ fields: FieldsReducer,
+ countDistribution: countDistributionReducer,
+ explorerVisualization: explorerVisualizationReducer,
+ explorerVisualizationConfig: explorerVisualizationConfigReducer,
+});
+
+export type RootState = ReturnType;
+
+export default rootReducer;
diff --git a/public/framework/redux/store/index.ts b/public/framework/redux/store/index.ts
new file mode 100644
index 0000000000..7efcf287db
--- /dev/null
+++ b/public/framework/redux/store/index.ts
@@ -0,0 +1,25 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { configureStore } from '@reduxjs/toolkit';
+import rootReducer from '../reducers';
+
+const store = configureStore({
+ reducer: rootReducer,
+ middleware: (getDefaultMiddleware) => getDefaultMiddleware(),
+ devTools: process.env.NODE_ENV !== 'production',
+ enhancers: [],
+});
+
+if (process.env.NODE_ENV === 'development' && module.hot) {
+ module.hot.accept('./rootReducer', () => {
+ const newRootReducer = require('./rootReducer').default;
+ store.replaceReducer(newRootReducer);
+ });
+}
+
+export type AppDispatch = typeof store.dispatch;
+
+export default store;
diff --git a/public/framework/redux/store/shared_state.ts b/public/framework/redux/store/shared_state.ts
new file mode 100644
index 0000000000..9cfce53513
--- /dev/null
+++ b/public/framework/redux/store/shared_state.ts
@@ -0,0 +1,9 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { uniqueId } from 'lodash';
+import { TAB_ID_TXT_PFX } from '../../../../common/constants/explorer';
+
+export const initialTabId: string = uniqueId(TAB_ID_TXT_PFX);
diff --git a/public/index.ts b/public/index.ts
new file mode 100644
index 0000000000..97037a9f7d
--- /dev/null
+++ b/public/index.ts
@@ -0,0 +1,16 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import './components/trace_analytics/index.scss';
+import './components/notebooks/index.scss'
+
+import { PluginInitializer, PluginInitializerContext } from '../../../src/core/public';
+import {
+ ObservabilityPlugin
+} from './plugin';
+
+export { ObservabilityPlugin as Plugin };
+
+export const plugin = (initializerContext: PluginInitializerContext) => new ObservabilityPlugin(initializerContext);
\ No newline at end of file
diff --git a/public/plugin.ts b/public/plugin.ts
new file mode 100644
index 0000000000..5180cf3e38
--- /dev/null
+++ b/public/plugin.ts
@@ -0,0 +1,64 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { AppMountParameters, CoreSetup, CoreStart, Plugin } from '../../../src/core/public';
+import {
+ observabilityID,
+ observabilityPluginOrder,
+ observabilityTitle,
+} from '../common/constants/shared';
+import PPLService from './services/requests/ppl';
+import DSLService from './services/requests/dsl';
+import TimestampUtils from './services/timestamp/timestamp';
+import SavedObjects from './services/saved_objects/event_analytics/saved_objects';
+import { AppPluginStartDependencies, ObservabilitySetup, ObservabilityStart } from './types';
+import { convertLegacyNotebooksUrl } from './components/notebooks/components/helpers/legacy_route_helpers';
+import { uiSettingsService } from '../common/utils';
+
+export class ObservabilityPlugin implements Plugin {
+ public setup(core: CoreSetup): ObservabilitySetup {
+ uiSettingsService.init(core.uiSettings, core.notifications);
+
+ // redirect legacy notebooks URL to current URL under observability
+ if (window.location.pathname.includes('notebooks-dashboards')) {
+ window.location.assign(convertLegacyNotebooksUrl(window.location));
+ }
+
+ core.application.register({
+ id: observabilityID,
+ title: observabilityTitle,
+ category: {
+ id: 'opensearch',
+ label: 'OpenSearch Plugins',
+ order: 2000,
+ },
+ order: observabilityPluginOrder,
+ async mount(params: AppMountParameters) {
+ const { Observability } = await import('./components/index');
+ const [coreStart, depsStart] = await core.getStartServices();
+ const pplService = new PPLService(coreStart.http);
+ const dslService = new DSLService(coreStart.http);
+ const savedObjects = new SavedObjects(coreStart.http);
+ const timestampUtils = new TimestampUtils(dslService);
+ return Observability(
+ coreStart,
+ depsStart as AppPluginStartDependencies,
+ params,
+ pplService,
+ dslService,
+ savedObjects,
+ timestampUtils
+ );
+ },
+ });
+
+ // Return methods that should be available to other plugins
+ return {};
+ }
+ public start(core: CoreStart): ObservabilityStart {
+ return {};
+ }
+ public stop() {}
+}
diff --git a/public/services/requests/dsl.ts b/public/services/requests/dsl.ts
new file mode 100644
index 0000000000..5ce0ce0570
--- /dev/null
+++ b/public/services/requests/dsl.ts
@@ -0,0 +1,41 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { CoreStart } from '../../../../../src/core/public';
+import { DSL_BASE, DSL_SEARCH, DSL_CAT, DSL_MAPPING } from '../../../common/constants/shared';
+
+export default class DSLService {
+ private http;
+ constructor(http: CoreStart['http']) {
+ this.http = http;
+ }
+ fetch = async (request: any) => {
+ return this.http
+ .post(`${DSL_BASE}${DSL_SEARCH}`, {
+ body: JSON.stringify(request),
+ })
+ .catch((error) => console.error(error));
+ };
+
+ fetchIndices = async () => {
+ return this.http
+ .get(`${DSL_BASE}${DSL_CAT}`, {
+ query: {
+ format: 'json',
+ },
+ })
+ .catch((error) => console.error(error));
+ };
+
+ fetchFields = async (index: string) => {
+ return this.http
+ .get(`${DSL_BASE}${DSL_MAPPING}`, {
+ query: {
+ index,
+ },
+ })
+ .catch((error) => console.error(error));
+ };
+}
diff --git a/public/services/requests/ppl.ts b/public/services/requests/ppl.ts
new file mode 100644
index 0000000000..f9343bc93c
--- /dev/null
+++ b/public/services/requests/ppl.ts
@@ -0,0 +1,31 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { CoreStart } from '../../../../../src/core/public';
+import { PPL_BASE, PPL_SEARCH } from '../../../common/constants/shared';
+
+export default class PPLService {
+ private http;
+ constructor(http: CoreStart['http']) {
+ this.http = http;
+ }
+
+ fetch = async (
+ params: {
+ query: string;
+ format: string;
+ },
+ errorHandler?: (error: any) => void
+ ) => {
+ return this.http
+ .post(`${PPL_BASE}${PPL_SEARCH}`, {
+ body: JSON.stringify(params),
+ })
+ .catch((error) => {
+ console.error(error);
+ if (errorHandler) errorHandler(error);
+ });
+ };
+}
diff --git a/public/services/saved_objects/event_analytics/saved_objects.ts b/public/services/saved_objects/event_analytics/saved_objects.ts
new file mode 100644
index 0000000000..880aad65c0
--- /dev/null
+++ b/public/services/saved_objects/event_analytics/saved_objects.ts
@@ -0,0 +1,283 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { has, isEmpty, isArray } from 'lodash';
+import { IField } from 'common/types/explorer';
+import {
+ OBSERVABILITY_BASE,
+ EVENT_ANALYTICS,
+ SAVED_OBJECTS,
+ SAVED_QUERY,
+ SAVED_VISUALIZATION,
+} from '../../../../common/constants/shared';
+import { CUSTOM_PANELS_API_PREFIX } from '../../../../common/constants/custom_panels';
+
+const CONCAT_FIELDS = ['objectIdList', 'objectType'];
+
+interface ISavedObjectRequestParams {
+ objectId?: string;
+ objectIdList?: string[] | string;
+ objectType?: string[] | string;
+ sortField?: string;
+ sortOrder?: 'asc' | 'desc';
+ fromIndex?: number;
+ maxItems?: number;
+ name?: string;
+ lastUpdatedTimeMs?: string;
+ createdTimeMs?: string;
+}
+
+interface ISelectedPanelsParams {
+ selectedCustomPanels: any[];
+ savedVisualizationId: string;
+}
+
+interface IBulkUpdateSavedVisualizationRquest {
+ query: string;
+ fields: IField[];
+ dateRange: string[];
+ type: string;
+ name: string;
+ savedObjectList: any[];
+}
+
+// eslint-disable-next-line import/no-default-export
+export default class SavedObjects {
+ constructor(private readonly http: any) {}
+
+ buildRequestBody({
+ query,
+ fields,
+ dateRange,
+ timestamp,
+ name = '',
+ chartType = '',
+ description = '',
+ applicationId = '',
+ userConfigs = '',
+ }: any) {
+ const objRequest: any = {
+ object: {
+ query,
+ selected_date_range: {
+ start: dateRange[0] || 'now/15m',
+ end: dateRange[1] || 'now',
+ text: '',
+ },
+ selected_timestamp: {
+ name: timestamp || '',
+ type: 'timestamp',
+ },
+ selected_fields: {
+ tokens: fields,
+ text: '',
+ },
+ name: name || '',
+ description: description || '',
+ },
+ };
+
+ if (!isEmpty(chartType)) {
+ objRequest.object.type = chartType;
+ }
+
+ if (!isEmpty(applicationId)) {
+ objRequest.object.application_id = applicationId;
+ }
+
+ if (!isEmpty(userConfigs)) {
+ objRequest.object.user_configs = userConfigs;
+ }
+
+ return objRequest;
+ }
+
+ private stringifyList(targetObj: any, key: string, joinBy: string) {
+ if (has(targetObj, key) && isArray(targetObj[key])) {
+ targetObj[key] = targetObj[key].join(joinBy);
+ }
+ return targetObj;
+ }
+
+ async fetchSavedObjects(params: ISavedObjectRequestParams) {
+ // turn array into string. exmaple objectType ['savedQuery', 'savedVisualization'] =>
+ // 'savedQuery,savedVisualization'
+ CONCAT_FIELDS.map((arrayField) => {
+ this.stringifyList(params, arrayField, ',');
+ });
+
+ return await this.http.get(`${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}`, {
+ query: {
+ ...params,
+ },
+ });
+ }
+
+ async fetchCustomPanels() {
+ return await this.http.get(`${CUSTOM_PANELS_API_PREFIX}/panels`);
+ }
+
+ async bulkUpdateCustomPanel(params: ISelectedPanelsParams) {
+ const finalParams = {
+ panelId: '',
+ savedVisualizationId: params.savedVisualizationId,
+ };
+
+ return await Promise.all(
+ params.selectedCustomPanels.map((panel) => {
+ finalParams.panelId = panel.panel.id;
+ return this.http.post(`${CUSTOM_PANELS_API_PREFIX}/visualizations`, {
+ body: JSON.stringify(finalParams),
+ });
+ })
+ );
+ }
+
+ async bulkUpdateSavedVisualization(params: IBulkUpdateSavedVisualizationRquest) {
+ const finalParams = this.buildRequestBody({
+ query: params.query,
+ fields: params.fields,
+ dateRange: params.dateRange,
+ chartType: params.type,
+ name: params.name,
+ });
+
+ return await Promise.all(
+ params.savedObjectList.map((objectToUpdate) => {
+ finalParams.object_id = objectToUpdate.saved_object.objectId;
+ return this.http.put(
+ `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}${SAVED_VISUALIZATION}`,
+ {
+ body: JSON.stringify(finalParams),
+ }
+ );
+ })
+ );
+ }
+
+ async updateSavedVisualizationById(params: any) {
+ const finalParams = this.buildRequestBody({
+ query: params.query,
+ fields: params.fields,
+ dateRange: params.dateRange,
+ chartType: params.type,
+ name: params.name,
+ timestamp: params.timestamp,
+ userConfigs: params.userConfigs,
+ description: params.description,
+ });
+
+ finalParams.object_id = params.objectId;
+
+ return await this.http.put(
+ `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}${SAVED_VISUALIZATION}`,
+ {
+ body: JSON.stringify(finalParams),
+ }
+ );
+ }
+
+ async updateSavedQueryById(params: any) {
+ const finalParams = this.buildRequestBody({
+ query: params.query,
+ fields: params.fields,
+ dateRange: params.dateRange,
+ chartType: params.type,
+ name: params.name,
+ timestamp: params.timestamp,
+ });
+
+ finalParams.object_id = params.objectId;
+
+ return await this.http.put(
+ `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}${SAVED_QUERY}`,
+ {
+ body: JSON.stringify(finalParams),
+ }
+ );
+ }
+
+ async createSavedQuery(params: any) {
+ const finalParams = this.buildRequestBody({
+ query: params.query,
+ fields: params.fields,
+ dateRange: params.dateRange,
+ name: params.name,
+ timestamp: params.timestamp,
+ });
+
+ return await this.http.post(
+ `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}${SAVED_QUERY}`,
+ {
+ body: JSON.stringify(finalParams),
+ }
+ );
+ }
+
+ async createSavedVisualization(params: any) {
+ const finalParams = this.buildRequestBody({
+ query: params.query,
+ fields: params.fields,
+ dateRange: params.dateRange,
+ chartType: params.type,
+ name: params.name,
+ timestamp: params.timestamp,
+ applicationId: params.applicationId,
+ userConfigs: params.userConfigs,
+ description: params.description,
+ });
+
+ return await this.http.post(
+ `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}${SAVED_VISUALIZATION}`,
+ {
+ body: JSON.stringify(finalParams),
+ }
+ );
+ }
+
+ async createSavedTimestamp(params: any) {
+ const finalParams = {
+ index: params.index,
+ name: params.name,
+ type: params.type,
+ dsl_type: params.dsl_type,
+ };
+
+ return await this.http.post(
+ `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}/timestamp`,
+ {
+ body: JSON.stringify(finalParams),
+ }
+ );
+ }
+
+ async updateTimestamp(params: any) {
+ const finalParams = {
+ objectId: params.index,
+ timestamp: {
+ name: params.name,
+ index: params.index,
+ type: params.type,
+ dsl_type: params.dsl_type,
+ },
+ };
+ return await this.http.put(
+ `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}/timestamp`,
+ {
+ body: JSON.stringify(finalParams),
+ }
+ );
+ }
+
+ async deleteSavedObjectsList(deleteObjectRequest: any) {
+ return await this.http.delete(
+ `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}/${deleteObjectRequest.objectIdList.join(
+ ','
+ )}`
+ );
+ }
+
+ deleteSavedObjectsByIdList(deleteObjectRequesList: any) {}
+}
diff --git a/public/services/timestamp/timestamp.ts b/public/services/timestamp/timestamp.ts
new file mode 100644
index 0000000000..281f528dc5
--- /dev/null
+++ b/public/services/timestamp/timestamp.ts
@@ -0,0 +1,65 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { isEmpty, isEqual, values, keys } from 'lodash';
+import DSLService from '../requests/dsl';
+import { IDefaultTimestampState } from '../../../common/types/explorer';
+
+// eslint-disable-next-line import/no-default-export
+export default class TimestampUtils {
+ constructor(private dslService: DSLService) {}
+
+ isTimeField(type: string) {
+ return ['date', 'date_nanos'].some((dateTimeType) => isEqual(type, dateTimeType));
+ }
+
+ async getTimestamp(index: string): Promise {
+ const indexMappings = await this.getIndexMappings(index);
+ const timestamp: IDefaultTimestampState = {
+ hasSchemaConflict: false,
+ default_timestamp: '',
+ message: 'Index does not contain a valid time field.',
+ };
+
+ // expect indexes to have the same schema, then go over the mapping to find timestamp
+ const mappingValues = values(indexMappings);
+
+ // check if all indexes have the same schema
+ if (
+ mappingValues.length > 1 &&
+ mappingValues.some(
+ (mapping) => !isEqual(mappingValues[0]?.mappings?.properties, mapping.mappings?.properties)
+ )
+ ) {
+ timestamp.message = 'Indexes have different schemas, and may lead to unexpected behaviors';
+ timestamp.hasSchemaConflict = true;
+ }
+
+ for (let i = 0; i < keys(indexMappings).length; i++) {
+ const fieldMapping = mappingValues[i]?.mappings?.properties || {};
+ if (!isEmpty(fieldMapping)) {
+ const mfields = keys(fieldMapping);
+ const mvalues = values(fieldMapping);
+ for (let j = 0; j < mfields.length; j++) {
+ if (
+ mvalues[j].type &&
+ this.isTimeField(mvalues[j].type) &&
+ isEmpty(timestamp.default_timestamp)
+ ) {
+ timestamp.default_timestamp = mfields[j];
+ timestamp.message = timestamp.hasSchemaConflict ? timestamp.message : '';
+ break;
+ }
+ }
+ }
+ if (timestamp.default_timestamp) break;
+ }
+ return timestamp;
+ }
+
+ async getIndexMappings(index: string) {
+ return await this.dslService.fetchFields(index);
+ }
+}
diff --git a/public/types.ts b/public/types.ts
new file mode 100644
index 0000000000..82bd6543a4
--- /dev/null
+++ b/public/types.ts
@@ -0,0 +1,16 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { DashboardStart } from '../../../src/plugins/dashboard/public';
+import { NavigationPublicPluginStart } from '../../../src/plugins/navigation/public';
+
+export interface AppPluginStartDependencies {
+ navigation: NavigationPublicPluginStart;
+ dashboard: DashboardStart;
+}
+
+export interface ObservabilitySetup {}
+
+export interface ObservabilityStart {}
diff --git a/server/adaptors/application_analytics/app_analytics_adaptor.ts b/server/adaptors/application_analytics/app_analytics_adaptor.ts
new file mode 100644
index 0000000000..45458564e5
--- /dev/null
+++ b/server/adaptors/application_analytics/app_analytics_adaptor.ts
@@ -0,0 +1,140 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ ApplicationRequestType,
+ ApplicationType,
+} from '../../../common/types/application_analytics';
+import { ILegacyScopedClusterClient } from '../../../../../src/core/server';
+
+export class AppAnalyticsAdaptor {
+ // Fetch all existing applications
+ fetchApps = async (client: ILegacyScopedClusterClient): Promise => {
+ try {
+ const response = await client.callAsCurrentUser('observability.getObject', {
+ objectType: 'application',
+ });
+ return response.observabilityObjectList.map((object: any) => {
+ return {
+ id: object.objectId,
+ dateCreated: object.createdTimeMs,
+ dateModified: object.lastUpdatedTimeMs,
+ name: object.application.name,
+ description: object.application.description,
+ baseQuery: object.application.baseQuery,
+ servicesEntities: object.application.servicesEntities.map((rec: string) =>
+ decodeURI(rec)
+ ),
+ traceGroups: object.application.traceGroups.map((rec: string) => decodeURI(rec)),
+ panelId: object.application.panelId,
+ availability: {
+ name: '',
+ color: '',
+ availabilityVisId: object.application.availabilityVisId || '',
+ },
+ };
+ });
+ } catch (err: any) {
+ throw new Error('Fetch All Applications Error: ' + err);
+ }
+ };
+
+ // Fetch application by id
+ fetchAppById = async (
+ client: ILegacyScopedClusterClient,
+ appId: string
+ ): Promise => {
+ try {
+ const response = await client.callAsCurrentUser('observability.getObjectById', {
+ objectId: appId,
+ });
+ const app = response.observabilityObjectList[0];
+ return {
+ id: appId,
+ dateCreated: app.createdTimeMs,
+ dateModified: app.lastUpdatedTimeMs,
+ name: app.application.name,
+ description: app.application.description,
+ baseQuery: app.application.baseQuery,
+ servicesEntities: app.application.servicesEntities.map((rec: string) => decodeURI(rec)),
+ traceGroups: app.application.traceGroups.map((rec: string) => decodeURI(rec)),
+ panelId: app.application.panelId,
+ availability: {
+ name: '',
+ color: '',
+ availabilityVisId: app.application.availabilityVisId || '',
+ },
+ };
+ } catch (err: any) {
+ throw new Error('Fetch Application By Id Error: ' + err);
+ }
+ };
+
+ // Create a new application
+ createNewApp = async (
+ client: ILegacyScopedClusterClient,
+ appBody: Partial
+ ) => {
+ try {
+ const response = await client.callAsCurrentUser('observability.createObject', {
+ body: {
+ application: appBody,
+ },
+ });
+ return response.objectId;
+ } catch (err) {
+ throw new Error('Create New Application Error: ' + err);
+ }
+ };
+
+ // Rename an existing application
+ renameApp = async (client: ILegacyScopedClusterClient, appId: string, name: string) => {
+ const updateApplicationBody = {
+ name,
+ };
+ try {
+ const response = await client.callAsCurrentUser('observability.updateObjectById', {
+ objectId: appId,
+ body: {
+ application: updateApplicationBody,
+ },
+ });
+ return response.objectId;
+ } catch (err: any) {
+ throw new Error('Rename Application Error: ' + err);
+ }
+ };
+
+ // Update an existing application
+ updateApp = async (
+ client: ILegacyScopedClusterClient,
+ appId: string,
+ updateAppBody: Partial
+ ) => {
+ try {
+ const response = await client.callAsCurrentUser('observability.updateObjectById', {
+ objectId: appId,
+ body: {
+ application: updateAppBody,
+ },
+ });
+ return response.objectId;
+ } catch (err: any) {
+ throw new Error('Update Panel Error: ' + err);
+ }
+ };
+
+ // Delete existing applications
+ deleteApp = async (client: ILegacyScopedClusterClient, appList: string) => {
+ try {
+ const response = await client.callAsCurrentUser('observability.deleteObjectByIdList', {
+ objectIdList: appList,
+ });
+ return { status: 'OK', message: response };
+ } catch (err: any) {
+ throw new Error('Delete Application Error: ' + err);
+ }
+ };
+}
diff --git a/server/adaptors/custom_panels/custom_panel_adaptor.ts b/server/adaptors/custom_panels/custom_panel_adaptor.ts
new file mode 100644
index 0000000000..a11bff645d
--- /dev/null
+++ b/server/adaptors/custom_panels/custom_panel_adaptor.ts
@@ -0,0 +1,424 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { v4 as uuidv4 } from 'uuid';
+import { PanelType, VisualizationType } from '../../../common/types/custom_panels';
+import { ILegacyScopedClusterClient } from '../../../../../src/core/server';
+import { createDemoPanel } from '../../common/helpers/custom_panels/sample_panels';
+
+interface boxType {
+ x1: number;
+ y1: number;
+ x2: number;
+ y2: number;
+}
+
+export class CustomPanelsAdaptor {
+ // index a panel
+ indexPanel = async function (
+ client: ILegacyScopedClusterClient,
+ panelBody: PanelType
+ ): Promise<{ objectId: string }> {
+ try {
+ const response = await client.callAsCurrentUser('observability.createObject', {
+ body: {
+ operationalPanel: panelBody,
+ },
+ });
+ return response;
+ } catch (error) {
+ throw new Error('Index Panel Error:' + error);
+ }
+ };
+
+ // update a panel
+ updatePanel = async function (
+ client: ILegacyScopedClusterClient,
+ panelId: string,
+ updatePanelBody: Partial
+ ) {
+ try {
+ const response = await client.callAsCurrentUser('observability.updateObjectById', {
+ objectId: panelId,
+ body: {
+ operationalPanel: updatePanelBody,
+ },
+ });
+ return response;
+ } catch (error) {
+ throw new Error('Update Panel Error:' + error);
+ }
+ };
+
+ // fetch a panel by id
+ getPanel = async function (client: ILegacyScopedClusterClient, panelId: string) {
+ try {
+ const response = await client.callAsCurrentUser('observability.getObjectById', {
+ objectId: panelId,
+ });
+ return response.observabilityObjectList[0];
+ } catch (error) {
+ throw new Error('Get Panel Error:' + error);
+ }
+ };
+
+ // gets list of panels stored in index
+ viewPanelList = async function (client: ILegacyScopedClusterClient) {
+ try {
+ const response = await client.callAsCurrentUser('observability.getObject', {
+ objectType: 'operationalPanel',
+ maxItems: 10000,
+ });
+ return response.observabilityObjectList
+ .filter((panel: any) => !panel.operationalPanel.applicationId)
+ .map((panel: any) => ({
+ name: panel.operationalPanel.name,
+ id: panel.objectId,
+ dateCreated: panel.createdTimeMs,
+ dateModified: panel.lastUpdatedTimeMs,
+ }));
+ } catch (error) {
+ throw new Error('View Panel List Error:' + error);
+ }
+ };
+
+ // Delete a panel by Id
+ deletePanel = async function (client: ILegacyScopedClusterClient, panelId: string) {
+ try {
+ const response = await client.callAsCurrentUser('observability.deleteObjectById', {
+ objectId: panelId,
+ });
+ return { status: 'OK', message: response };
+ } catch (error) {
+ throw new Error('Delete Panel Error:' + error);
+ }
+ };
+
+ // Delete a panel by Id
+ deletePanelList = async function (client: ILegacyScopedClusterClient, panelIdList: string) {
+ try {
+ const response = await client.callAsCurrentUser('observability.deleteObjectByIdList', {
+ objectIdList: panelIdList,
+ });
+ return { status: 'OK', message: response };
+ } catch (error) {
+ throw new Error('Delete Panel List Error:' + error);
+ }
+ };
+
+ // Create a new Panel
+ createNewPanel = async (
+ client: ILegacyScopedClusterClient,
+ panelName: string,
+ appId?: string
+ ) => {
+ const panelBody: PanelType = {
+ name: panelName,
+ visualizations: [],
+ timeRange: {
+ to: 'now',
+ from: 'now-1d',
+ },
+ queryFilter: {
+ query: '',
+ language: 'ppl',
+ },
+ };
+ if (appId) {
+ panelBody.applicationId = appId;
+ panelBody.timeRange = {
+ to: 'now',
+ from: 'now-24h',
+ };
+ }
+
+ try {
+ const response = await this.indexPanel(client, panelBody);
+ return response.objectId;
+ } catch (error) {
+ throw new Error('Create Panel Error:' + error);
+ }
+ };
+
+ // Rename an existing panel
+ renamePanel = async (client: ILegacyScopedClusterClient, panelId: string, panelName: string) => {
+ const updatePanelBody = {
+ name: panelName,
+ };
+ try {
+ const response = await this.updatePanel(client, panelId, updatePanelBody);
+ return response.objectId;
+ } catch (error) {
+ throw new Error('Rename Panel Error:' + error);
+ }
+ };
+
+ // Clone an existing panel
+ clonePanel = async (client: ILegacyScopedClusterClient, panelId: string, panelName: string) => {
+ const updatePanelBody = {
+ name: panelName,
+ };
+ try {
+ const getPanel = await this.getPanel(client, panelId);
+ const clonePanelBody = {
+ name: panelName,
+ visualizations: getPanel.operationalPanel.visualizations,
+ timeRange: getPanel.operationalPanel.timeRange,
+ queryFilter: getPanel.operationalPanel.queryFilter,
+ };
+ const indexResponse = await this.indexPanel(client, clonePanelBody);
+ const getClonedPanel = await this.getPanel(client, indexResponse.objectId);
+ return {
+ clonePanelId: getClonedPanel.objectId,
+ dateCreated: getClonedPanel.createdTimeMs,
+ dateModified: getClonedPanel.lastUpdatedTimeMs,
+ };
+ } catch (error) {
+ throw new Error('Clone Panel Error:' + error);
+ }
+ };
+
+ // Add filters to an existing panel
+ addPanelFilter = async (
+ client: ILegacyScopedClusterClient,
+ panelId: string,
+ query: string,
+ language: string,
+ to: string,
+ from: string
+ ) => {
+ const updatePanelBody = {
+ timeRange: {
+ to,
+ from,
+ },
+ queryFilter: {
+ query,
+ language,
+ },
+ };
+ try {
+ const response = await this.updatePanel(client, panelId, updatePanelBody);
+ return response.objectId;
+ } catch (error) {
+ throw new Error('Add Panel Filter Error:' + error);
+ }
+ };
+
+ // parses fetched saved visualization
+ parseSavedVisualizations = (visualization: any) => {
+ return {
+ id: visualization.objectId,
+ name: visualization.savedVisualization.name,
+ query: visualization.savedVisualization.query,
+ type: visualization.savedVisualization.type,
+ timeField: visualization.savedVisualization.selected_timestamp.name,
+ selected_date_range: visualization.savedVisualization.selected_date_range,
+ selected_fields: visualization.savedVisualization.selected_fields,
+ user_configs: visualization.savedVisualization.hasOwnProperty('user_configs')
+ ? JSON.parse(visualization.savedVisualization.user_configs)
+ : {},
+ ...(visualization.savedVisualization.application_id
+ ? { application_id: visualization.savedVisualization.application_id }
+ : {}),
+ };
+ };
+
+ // gets all saved visualizations
+ getAllSavedVisualizations = async (client: ILegacyScopedClusterClient) => {
+ try {
+ const response = await client.callAsCurrentUser('observability.getObject', {
+ objectType: 'savedVisualization',
+ });
+ return response.observabilityObjectList.map((visualization: any) =>
+ this.parseSavedVisualizations(visualization)
+ );
+ } catch (error) {
+ throw new Error('View Saved Visualizations Error:' + error);
+ }
+ };
+
+ // gets list of savedVisualizations by Id
+ getSavedVisualizationById = async (
+ client: ILegacyScopedClusterClient,
+ savedVisualizationId: string
+ ) => {
+ try {
+ const response = await client.callAsCurrentUser('observability.getObjectById', {
+ objectId: savedVisualizationId,
+ });
+ const visualization = response.observabilityObjectList[0];
+ return this.parseSavedVisualizations(visualization);
+ } catch (error) {
+ throw new Error('Fetch Saved Visualizations By Id Error:' + error);
+ }
+ };
+
+ // Get All Visualizations from a Panel
+ getVisualizations = async (client: ILegacyScopedClusterClient, panelId: string) => {
+ try {
+ const response = await client.callAsCurrentUser('observability.getObjectById', {
+ objectId: panelId,
+ });
+ return response.observabilityObjectList[0].operationalPanel.visualizations;
+ } catch (error) {
+ throw new Error('Get Visualizations Error:' + error);
+ }
+ };
+
+ calculatOverlapArea = (bb1: boxType, bb2: boxType) => {
+ const x_left = Math.max(bb1.x1, bb2.x1);
+ const y_top = Math.max(bb1.y1, bb2.y1);
+ const x_right = Math.min(bb1.x2, bb2.x2);
+ const y_bottom = Math.min(bb1.y2, bb2.y2);
+
+ if (x_right < x_left || y_bottom < y_top) return 0;
+ return (x_right - x_left) * (y_bottom - y_top);
+ };
+
+ getTotalOverlapArea = (panelVisualizations: VisualizationType[]) => {
+ const newVizBox = { x1: 0, y1: 0, x2: 6, y2: 4 };
+ const currentVizBoxes = panelVisualizations.map((visualization) => {
+ return {
+ x1: visualization.x,
+ y1: visualization.y,
+ x2: visualization.x + visualization.w,
+ y2: visualization.y + visualization.h,
+ };
+ });
+
+ let isOverlapping = 0;
+ currentVizBoxes.map((viz) => {
+ isOverlapping += this.calculatOverlapArea(viz, newVizBox);
+ });
+ return isOverlapping;
+ };
+
+ // We want to check if the new visualization being added, can be placed at { x: 0, y: 0, w: 6, h: 4 };
+ // To check this we try to calculate overlap between all the current visualizations and new visualization
+ // if there is no overalap (i.e Total Overlap Area is 0), we place the new viz. in default position
+ // else, we add it to the bottom of the panel
+ getNewVizDimensions = (panelVisualizations: VisualizationType[]) => {
+ let maxY: number = 0;
+ let maxYH: number = 0;
+
+ // check if we can place the new visualization at default location
+ if (this.getTotalOverlapArea(panelVisualizations) === 0) {
+ return { x: 0, y: 0, w: 6, h: 4 };
+ }
+
+ // else place the new visualization at the bottom of the panel
+ panelVisualizations.map((panelVisualization: VisualizationType) => {
+ if (panelVisualization.y >= maxY) {
+ maxY = panelVisualization.y;
+ maxYH = panelVisualization.h;
+ }
+ });
+
+ return { x: 0, y: maxY + maxYH, w: 6, h: 4 };
+ };
+
+ // Add Visualization in the Panel
+ addVisualization = async (
+ client: ILegacyScopedClusterClient,
+ panelId: string,
+ savedVisualizationId: string,
+ oldVisualizationId?: string
+ ) => {
+ try {
+ const allPanelVisualizations = await this.getVisualizations(client, panelId);
+
+ let newDimensions;
+ let visualizationsList = [] as VisualizationType[];
+ if (oldVisualizationId === undefined) {
+ newDimensions = this.getNewVizDimensions(allPanelVisualizations);
+ visualizationsList = allPanelVisualizations;
+ } else {
+ allPanelVisualizations.map((visualization: VisualizationType) => {
+ if (visualization.id !== oldVisualizationId) {
+ visualizationsList.push(visualization);
+ } else {
+ newDimensions = {
+ x: visualization.x,
+ y: visualization.y,
+ w: visualization.w,
+ h: visualization.h,
+ };
+ }
+ });
+ }
+ const newPanelVisualizations = [
+ ...visualizationsList,
+ {
+ id: 'panel_viz_' + uuidv4(),
+ savedVisualizationId,
+ ...newDimensions,
+ },
+ ];
+ const updatePanelResponse = await this.updatePanel(client, panelId, {
+ visualizations: newPanelVisualizations,
+ });
+ return newPanelVisualizations;
+ } catch (error) {
+ throw new Error('Add/Replace Visualization Error:' + error);
+ }
+ };
+
+ // Edits all Visualizations in the Panel
+ editVisualization = async (
+ client: ILegacyScopedClusterClient,
+ panelId: string,
+ visualizationParams: Array<{
+ i: string;
+ x: number;
+ y: number;
+ w: number;
+ h: number;
+ }>
+ ) => {
+ try {
+ const allPanelVisualizations = await this.getVisualizations(client, panelId);
+ const filteredPanelVisualizations = [] as VisualizationType[];
+
+ for (let i = 0; i < allPanelVisualizations.length; i++) {
+ for (let j = 0; j < visualizationParams.length; j++) {
+ if (allPanelVisualizations[i].id === visualizationParams[j].i) {
+ filteredPanelVisualizations.push({
+ ...allPanelVisualizations[i],
+ x: visualizationParams[j].x,
+ y: visualizationParams[j].y,
+ w: visualizationParams[j].w,
+ h: visualizationParams[j].h,
+ });
+ }
+ }
+ }
+ const updatePanelResponse = await this.updatePanel(client, panelId, {
+ visualizations: filteredPanelVisualizations,
+ });
+ return filteredPanelVisualizations;
+ } catch (error) {
+ throw new Error('Edit Visualizations Error:' + error);
+ }
+ };
+
+ // Create Sample Panels
+ addSamplePanels = async (client: ILegacyScopedClusterClient, savedVisualizationIds: string[]) => {
+ try {
+ const panelBody = createDemoPanel(savedVisualizationIds);
+ const indexResponse = await this.indexPanel(client, panelBody);
+ const fetchPanel = await this.getPanel(client, indexResponse.objectId);
+ const fetchResponse = {
+ name: fetchPanel.operationalPanel.name,
+ id: fetchPanel.objectId,
+ dateCreated: fetchPanel.createdTimeMs,
+ dateModified: fetchPanel.lastUpdatedTimeMs,
+ };
+ return [fetchResponse];
+ } catch (error) {
+ throw new Error('Create Panel Error:' + error);
+ }
+ };
+}
diff --git a/server/adaptors/notebooks/default_backend.ts b/server/adaptors/notebooks/default_backend.ts
new file mode 100644
index 0000000000..66fc0bb9b0
--- /dev/null
+++ b/server/adaptors/notebooks/default_backend.ts
@@ -0,0 +1,609 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import now from 'performance-now';
+import { v4 as uuid } from 'uuid';
+import { ILegacyScopedClusterClient } from '../../../../../src/core/server';
+import { optionsType } from '../../../common/types/notebooks';
+import {
+ DefaultNotebooks,
+ DefaultOutput,
+ DefaultParagraph,
+} from '../../common/helpers/notebooks/default_notebook_schema';
+import { formatNotRecognized, inputIsQuery } from '../../common/helpers/notebooks/query_helpers';
+import { getSampleNotebooks } from '../../common/helpers/notebooks/sample_notebooks';
+import { NotebookAdaptor } from './notebook_adaptor';
+
+export class DefaultBackend implements NotebookAdaptor {
+ backend = 'Default Backend';
+
+ // Creates a new notebooks with sample markdown text
+ createNewNotebook = (newNotebookName: string) => {
+ const noteObject: DefaultNotebooks = {
+ dateCreated: new Date().toISOString(),
+ name: newNotebookName,
+ dateModified: new Date().toISOString(),
+ backend: 'Default',
+ paragraphs: [],
+ };
+
+ return {
+ object: noteObject,
+ };
+ };
+
+ // indexes a notebook with body provided
+ indexNote = async function (
+ client: ILegacyScopedClusterClient,
+ body: any
+ ): Promise<{ objectId: string }> {
+ try {
+ const response = await client.callAsCurrentUser('observability.createObject', {
+ body: {
+ notebook: body,
+ },
+ });
+ return response;
+ } catch (error) {
+ throw new Error('Index Doc Error:' + error);
+ }
+ };
+
+ // updates a notebook with updateBody provided as parameter
+ updateNote = async function (
+ client: ILegacyScopedClusterClient,
+ noteId: string,
+ updateBody: Partial
+ ) {
+ try {
+ const response = await client.callAsCurrentUser('observability.updateObjectById', {
+ objectId: noteId,
+ body: {
+ notebook: updateBody,
+ },
+ });
+ return response;
+ } catch (error) {
+ throw new Error('Update Doc Error:' + error);
+ }
+ };
+
+ // fetched a notebook by Id
+ getNote = async function (client: ILegacyScopedClusterClient, noteId: string) {
+ try {
+ const response = await client.callAsCurrentUser('observability.getObjectById', {
+ objectId: noteId,
+ });
+ if (response.observabilityObjectList.length === 0) {
+ throw 'notebook id not found';
+ }
+ return response.observabilityObjectList[0];
+ } catch (error) {
+ throw new Error('Get Doc Error:' + error);
+ }
+ };
+
+ // gets first `FETCH_SIZE` notebooks available
+ viewNotes = async function (client: ILegacyScopedClusterClient, _wreckOptions: optionsType) {
+ try {
+ const response = await client.callAsCurrentUser('observability.getObject', {
+ objectType: 'notebook',
+ });
+ return response.observabilityObjectList.map((notebook) => ({
+ path: notebook.notebook.name,
+ id: notebook.objectId,
+ dateCreated: notebook.notebook.dateCreated,
+ dateModified: notebook.notebook.dateModified,
+ }));
+ } catch (error) {
+ if (error.body.error.type === 'index_not_found_exception') {
+ return [];
+ } else throw new Error('View Notebooks Error:' + error);
+ }
+ };
+
+ /* Fetches a notebook by id
+ * Param: noteId -> Id of notebook to be fetched
+ */
+ fetchNote = async function (
+ client: ILegacyScopedClusterClient,
+ noteId: string,
+ _wreckOptions: optionsType
+ ) {
+ try {
+ const noteObject = await this.getNote(client, noteId);
+ return {
+ path: noteObject.notebook.name,
+ dateCreated: noteObject.notebook.dateCreated,
+ dateModified: noteObject.notebook.dateModified,
+ paragraphs: noteObject.notebook.paragraphs,
+ };
+ } catch (error) {
+ throw new Error('Fetching Notebook Error:' + error);
+ }
+ };
+
+ /* Adds a notebook to storage
+ * Param: name -> name of new notebook
+ */
+ addNote = async function (
+ client: ILegacyScopedClusterClient,
+ params: { name: string },
+ _wreckOptions: optionsType
+ ) {
+ try {
+ const newNotebook = this.createNewNotebook(params.name);
+ const opensearchClientResponse = await this.indexNote(client, newNotebook.object);
+ return {
+ status: 'OK',
+ message: opensearchClientResponse,
+ body: opensearchClientResponse.objectId,
+ };
+ } catch (error) {
+ throw new Error('Creating New Notebook Error:' + error);
+ }
+ };
+
+ /* Adds sample notebooks to storage
+ * Param: name -> name of new notebook
+ */
+ addSampleNotes = async function (
+ client: ILegacyScopedClusterClient,
+ visIds: string[],
+ _wreckOptions: optionsType
+ ) {
+ try {
+ const notebooks = getSampleNotebooks(visIds);
+ const newNotebooks: any[] = [];
+ for (let i = 0; i < notebooks.length; i++) {
+ const notebook = notebooks[i];
+ await this.indexNote(client, notebook.notebook).then((response) => {
+ newNotebooks.push({
+ id: response.objectId,
+ name: notebook.notebook.name,
+ dateModified: notebook.dateModified,
+ dateCreated: notebook.dateCreated,
+ });
+ });
+ }
+ return { status: 'OK', message: '', body: newNotebooks };
+ } catch (error) {
+ throw new Error('Creating New Notebook Error:' + error);
+ }
+ };
+
+ /* Renames a notebook
+ * Params: name -> new name for the notebook to be renamed
+ * noteId -> Id of notebook to be fetched
+ */
+ renameNote = async function (
+ client: ILegacyScopedClusterClient,
+ params: { name: string; noteId: string },
+ _wreckOptions: optionsType
+ ) {
+ try {
+ const updateNotebook = {
+ name: params.name,
+ dateModified: new Date().toISOString(),
+ };
+ const opensearchClientResponse = await this.updateNote(client, params.noteId, updateNotebook);
+ return { status: 'OK', message: opensearchClientResponse };
+ } catch (error) {
+ throw new Error('Renaming Notebook Error:' + error);
+ }
+ };
+
+ /* Clone a notebook
+ * Params: name -> new name for the cloned notebook
+ * noteId -> Id for the notebook to be cloned
+ */
+ cloneNote = async function (
+ client: ILegacyScopedClusterClient,
+ params: { name: string; noteId: string },
+ _wreckOptions: optionsType
+ ) {
+ try {
+ const noteObject = await this.getNote(client, params.noteId);
+ const newNotebook = this.createNewNotebook(params.name);
+ const cloneNotebook = { ...newNotebook.object };
+ cloneNotebook.paragraphs = noteObject.notebook.paragraphs;
+ const opensearchClientIndexResponse = await this.indexNote(client, cloneNotebook);
+ return {
+ status: 'OK',
+ body: { ...cloneNotebook, id: opensearchClientIndexResponse.objectId },
+ };
+ } catch (error) {
+ throw new Error('Cloning Notebook Error:' + error);
+ }
+ };
+
+ /* Delete a notebook
+ * Param: noteId -> Id for the notebook to be deleted
+ */
+ deleteNote = async function (
+ client: ILegacyScopedClusterClient,
+ noteList: string,
+ _wreckOptions: optionsType
+ ) {
+ try {
+ const response = await client.callAsCurrentUser('observability.deleteObjectByIdList', {
+ objectIdList: noteList,
+ });
+ return { status: 'OK', message: response };
+ } catch (error) {
+ throw new Error('Deleting Notebook Error:' + error);
+ }
+ };
+
+ /* Export a notebook
+ * Param: noteId -> Id for the notebook to be exported
+ */
+ exportNote = async function (
+ client: ILegacyScopedClusterClient,
+ noteId: string,
+ _wreckOptions: optionsType
+ ) {
+ try {
+ const opensearchClientGetResponse = await this.getNote(client, noteId);
+ return { status: 'OK', body: opensearchClientGetResponse };
+ } catch (error) {
+ throw new Error('Export Notebook Error:' + error);
+ }
+ };
+
+ /* Import a notebook
+ * Params: noteObj -> note Object to be imported
+ */
+ importNote = async function (
+ client: ILegacyScopedClusterClient,
+ noteObj: any,
+ _wreckOptions: optionsType
+ ) {
+ try {
+ let newNoteObject = { ...noteObj };
+ newNoteObject.id = 'note_' + uuid();
+ newNoteObject.dateCreated = new Date().toISOString();
+ newNoteObject.dateModified = new Date().toISOString();
+ const opensearchClientIndexResponse = await this.indexNote(client, newNoteObject);
+ return {
+ status: 'OK',
+ message: opensearchClientIndexResponse,
+ body: opensearchClientIndexResponse.objectId,
+ };
+ } catch (error) {
+ throw new Error('Import Notebook Error:' + error);
+ }
+ };
+
+ /* Updates input for required paragraphs
+ * Params: paragraphs -> list of paragraphs
+ * paragraphId -> Id of paragraph to be updated
+ * paragraphInput -> Input to be added
+ */
+ updateParagraph = function (
+ paragraphs: Array,
+ paragraphId: string,
+ paragraphInput: string,
+ paragraphType?: string
+ ) {
+ try {
+ const updatedParagraphs: DefaultParagraph[] = [];
+ paragraphs.map((paragraph: DefaultParagraph) => {
+ const updatedParagraph = { ...paragraph };
+ if (paragraph.id === paragraphId) {
+ updatedParagraph.dateModified = new Date().toISOString();
+ updatedParagraph.input.inputText = paragraphInput;
+ if (paragraphType.length > 0) {
+ updatedParagraph.input.inputType = paragraphType;
+ }
+ }
+ updatedParagraphs.push(updatedParagraph);
+ });
+ return updatedParagraphs;
+ } catch (error) {
+ throw new Error('Update Paragraph Error:' + error);
+ }
+ };
+
+ // Creates new paragraph with the given input and input type
+ createParagraph = function (paragraphInput: string, inputType: string) {
+ try {
+ let paragraphType = 'MARKDOWN';
+ if (inputType === 'VISUALIZATION') {
+ paragraphType = 'VISUALIZATION';
+ }
+ if (inputType === 'OBSERVABILITY_VISUALIZATION') {
+ paragraphType = 'OBSERVABILITY_VISUALIZATION';
+ }
+ if (paragraphInput.substring(0, 3) === '%sql' || paragraphInput.substring(0, 3) === '%ppl') {
+ paragraphType = 'QUERY';
+ }
+ const inputObject = {
+ inputType: paragraphType,
+ inputText: paragraphInput,
+ };
+ const outputObjects: Array = [
+ {
+ outputType: paragraphType,
+ result: '',
+ execution_time: '0s',
+ },
+ ];
+ const newParagraph = {
+ id: 'paragraph_' + uuid(),
+ dateCreated: new Date().toISOString(),
+ dateModified: new Date().toISOString(),
+ input: inputObject,
+ output: outputObjects,
+ };
+
+ return newParagraph;
+ } catch (error) {
+ throw new Error('Create Paragraph Error:' + error);
+ }
+ };
+
+ /* Runs a paragraph
+ * Currently only runs markdown by copying input.inputText to result
+ * UI renders Markdown
+ */
+ runParagraph = async function (
+ paragraphs: Array,
+ paragraphId: string,
+ client: ILegacyScopedClusterClient
+ ) {
+ try {
+ const updatedParagraphs = [];
+ let index = 0;
+ for (index = 0; index < paragraphs.length; ++index) {
+ const startTime = now();
+ const updatedParagraph = { ...paragraphs[index] };
+ if (paragraphs[index].id === paragraphId) {
+ updatedParagraph.dateModified = new Date().toISOString();
+ if (inputIsQuery(paragraphs[index].input.inputText)) {
+ updatedParagraph.output = [
+ {
+ outputType: 'QUERY',
+ result: paragraphs[index].input.inputText.substring(
+ 4,
+ paragraphs[index].input.inputText.length
+ ),
+ execution_time: `${(now() - startTime).toFixed(3)} ms`,
+ },
+ ];
+ } else if (paragraphs[index].input.inputText.substring(0, 3) === '%md') {
+ updatedParagraph.output = [
+ {
+ outputType: 'MARKDOWN',
+ result: paragraphs[index].input.inputText.substring(
+ 4,
+ paragraphs[index].input.inputText.length
+ ),
+ execution_time: `${(now() - startTime).toFixed(3)} ms`,
+ },
+ ];
+ } else if (paragraphs[index].input.inputType === 'VISUALIZATION') {
+ updatedParagraph.dateModified = new Date().toISOString();
+ updatedParagraph.output = [
+ {
+ outputType: 'VISUALIZATION',
+ result: '',
+ execution_time: `${(now() - startTime).toFixed(3)} ms`,
+ },
+ ];
+ } else if (paragraphs[index].input.inputType === 'OBSERVABILITY_VISUALIZATION') {
+ updatedParagraph.dateModified = new Date().toISOString();
+ updatedParagraph.output = [
+ {
+ outputType: 'OBSERVABILITY_VISUALIZATION',
+ result: '',
+ execution_time: `${(now() - startTime).toFixed(3)} ms`,
+ },
+ ];
+ } else if (formatNotRecognized(paragraphs[index].input.inputText)) {
+ updatedParagraph.output = [
+ {
+ outputType: 'MARKDOWN',
+ result: 'Please select an input type (%sql, %ppl, or %md)',
+ execution_time: `${(now() - startTime).toFixed(3)} ms`,
+ },
+ ];
+ }
+ }
+ updatedParagraphs.push(updatedParagraph);
+ }
+ return updatedParagraphs;
+ } catch (error) {
+ throw new Error('Running Paragraph Error:' + error);
+ }
+ };
+
+ /* --> Updates a Paragraph with input content
+ * --> Runs it
+ * --> Updates the notebook in index
+ * --> Fetches the updated Paragraph (with new input content and output result)
+ * Params: noteId -> Id of the notebook
+ * paragraphId -> Id of the paragraph to be updated
+ * paragraphInput -> paragraph input code
+ */
+ updateRunFetchParagraph = async function (
+ client: ILegacyScopedClusterClient,
+ request: any,
+ _wreckOptions: optionsType
+ ) {
+ try {
+ const scopedClient = client.asScoped(request);
+ const params = request.body;
+ const opensearchClientGetResponse = await this.getNote(scopedClient, params.noteId);
+ const updatedInputParagraphs = this.updateParagraph(
+ opensearchClientGetResponse.notebook.paragraphs,
+ params.paragraphId,
+ params.paragraphInput,
+ params.paragraphType
+ );
+ const updatedOutputParagraphs = await this.runParagraph(
+ updatedInputParagraphs,
+ params.paragraphId,
+ client
+ );
+ const updateNotebook = {
+ paragraphs: updatedOutputParagraphs,
+ dateModified: new Date().toISOString(),
+ };
+ const opensearchClientResponse = await this.updateNote(
+ scopedClient,
+ params.noteId,
+ updateNotebook
+ );
+ let resultParagraph = {};
+ let index = 0;
+
+ for (index = 0; index < updatedOutputParagraphs.length; ++index) {
+ if (params.paragraphId === updatedOutputParagraphs[index].id) {
+ resultParagraph = updatedOutputParagraphs[index];
+ }
+ }
+ return resultParagraph;
+ } catch (error) {
+ throw new Error('Update/Run Paragraph Error:' + error);
+ }
+ };
+
+ /* --> Updates a Paragraph with input content
+ * --> Updates the notebook in index
+ * --> Fetches the updated Paragraph (with new input content)
+ * Params: noteId -> Id of the notebook
+ * paragraphId -> Id of the paragraph to be updated
+ * paragraphInput -> paragraph input code
+ */
+ updateFetchParagraph = async function (
+ client: ILegacyScopedClusterClient,
+ params: { noteId: string; paragraphId: string; paragraphInput: string },
+ _wreckOptions: optionsType
+ ) {
+ try {
+ const opensearchClientGetResponse = await this.getNote(client, params.noteId);
+ const updatedInputParagraphs = this.updateParagraph(
+ opensearchClientGetResponse.notebook.paragraphs,
+ params.paragraphId,
+ params.paragraphInput
+ );
+
+ const updateNotebook = {
+ paragraphs: updatedInputParagraphs,
+ dateModified: new Date().toISOString(),
+ };
+ const opensearchClientResponse = await this.updateNote(client, params.noteId, updateNotebook);
+
+ let resultParagraph = {};
+ updatedInputParagraphs.map((paragraph: DefaultParagraph) => {
+ if (params.paragraphId === paragraph.id) {
+ resultParagraph = paragraph;
+ }
+ });
+ return resultParagraph;
+ } catch (error) {
+ throw new Error('Save Paragraph Error:' + error);
+ }
+ };
+
+ /* --> Fetches the Paragraph
+ * --> Adds a Paragraph with input content
+ * --> Updates the notebook in index
+ * Params: noteId -> Id of the notebook
+ * paragraphId -> Id of the paragraph to be fetched
+ */
+ addFetchNewParagraph = async function (
+ client: ILegacyScopedClusterClient,
+ params: { noteId: string; paragraphIndex: number; paragraphInput: string; inputType: string },
+ _wreckOptions: optionsType
+ ) {
+ try {
+ const opensearchClientGetResponse = await this.getNote(client, params.noteId);
+ const paragraphs = opensearchClientGetResponse.notebook.paragraphs;
+ const newParagraph = this.createParagraph(params.paragraphInput, params.inputType);
+ paragraphs.splice(params.paragraphIndex, 0, newParagraph);
+ const updateNotebook = {
+ paragraphs: paragraphs,
+ dateModified: new Date().toISOString(),
+ };
+ const opensearchClientResponse = await this.updateNote(client, params.noteId, updateNotebook);
+
+ return newParagraph;
+ } catch (error) {
+ throw new Error('add/Fetch Paragraph Error:' + error);
+ }
+ };
+
+ /* --> Deletes a Paragraph with id
+ * --> Fetches the all other Paragraphs as a list
+ * --> Updates the notebook in index
+ * Params: noteId -> Id of the notebook
+ * paragraphId -> Id of the paragraph to be deleted
+ */
+ deleteFetchParagraphs = async function (
+ client: ILegacyScopedClusterClient,
+ params: { noteId: string; paragraphId: string | undefined },
+ _wreckOptions: optionsType
+ ) {
+ try {
+ const opensearchClientGetResponse = await this.getNote(client, params.noteId);
+ const updatedparagraphs: DefaultParagraph[] = [];
+ if (params.paragraphId !== undefined) {
+ opensearchClientGetResponse.notebook.paragraphs.map(
+ (paragraph: DefaultParagraph, index: number) => {
+ if (paragraph.id !== params.paragraphId) {
+ updatedparagraphs.push(paragraph);
+ }
+ }
+ );
+ }
+
+ const updateNotebook = {
+ paragraphs: updatedparagraphs,
+ dateModified: new Date().toISOString(),
+ };
+ const opensearchClientResponse = await this.updateNote(client, params.noteId, updateNotebook);
+
+ return { paragraphs: updatedparagraphs };
+ } catch (error) {
+ console.log('error', error);
+ throw new Error('Delete Paragraph Error:' + error);
+ }
+ };
+
+ /* --> Clears output for all the paragraphs
+ * --> Fetches the all Paragraphs as a list (with cleared outputs)
+ * --> Updates the notebook in index
+ * Param: noteId -> Id of notebook to be cleared
+ */
+ clearAllFetchParagraphs = async function (
+ client: ILegacyScopedClusterClient,
+ params: { noteId: string },
+ _wreckOptions: optionsType
+ ) {
+ try {
+ const opensearchClientGetResponse = await this.getNote(client, params.noteId);
+ let updatedparagraphs: DefaultParagraph[] = [];
+ opensearchClientGetResponse.notebook.paragraphs.map(
+ (paragraph: DefaultParagraph, index: number) => {
+ let updatedParagraph = { ...paragraph };
+ updatedParagraph.output = [];
+ updatedparagraphs.push(updatedParagraph);
+ }
+ );
+
+ const updateNotebook = {
+ paragraphs: updatedparagraphs,
+ dateModified: new Date().toISOString(),
+ };
+ const opensearchClientResponse = await this.updateNote(client, params.noteId, updateNotebook);
+
+ return { paragraphs: updatedparagraphs };
+ } catch (error) {
+ throw new Error('Clear Paragraph Error:' + error);
+ }
+ };
+}
diff --git a/server/adaptors/notebooks/index.ts b/server/adaptors/notebooks/index.ts
new file mode 100644
index 0000000000..ae35674ed9
--- /dev/null
+++ b/server/adaptors/notebooks/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { ZeppelinBackend } from './zeppelin_backend';
+import { DefaultBackend } from './default_backend';
+import { NOTEBOOKS_SELECTED_BACKEND } from '../../../common/constants/notebooks';
+
+// Selects backend based on config
+let BACKEND = new DefaultBackend();
+
+if (NOTEBOOKS_SELECTED_BACKEND == 'ZEPPELIN') {
+ BACKEND = new ZeppelinBackend();
+}
+
+export default BACKEND;
diff --git a/server/adaptors/notebooks/notebook_adaptor.ts b/server/adaptors/notebooks/notebook_adaptor.ts
new file mode 100644
index 0000000000..0ede5ffb22
--- /dev/null
+++ b/server/adaptors/notebooks/notebook_adaptor.ts
@@ -0,0 +1,136 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { ILegacyScopedClusterClient } from '../../../../../src/core/server';
+import { optionsType } from '../../../common/types/notebooks';
+
+export interface NotebookAdaptor {
+ backend: string;
+
+ // Gets all the notebooks available
+ viewNotes: (client: ILegacyScopedClusterClient, wreckOptions: optionsType) => Promise;
+
+ /* Fetches a notebook by id
+ * Param: noteId -> Id of notebook to be fetched
+ */
+ fetchNote: (
+ client: ILegacyScopedClusterClient,
+ noteId: string,
+ wreckOptions: optionsType
+ ) => Promise;
+
+ /* Adds a notebook to storage
+ * Param: name -> name of new notebook
+ */
+ addNote: (
+ client: ILegacyScopedClusterClient,
+ params: { name: string },
+ wreckOptions: optionsType
+ ) => Promise;
+
+ /* Renames a notebook
+ * Params: name -> new name for the notebook to be renamed
+ * noteId -> Id of notebook to be fetched
+ */
+ renameNote: (
+ client: ILegacyScopedClusterClient,
+ params: { name: string; noteId: string },
+ wreckOptions: optionsType
+ ) => Promise;
+
+ /* Clone a notebook
+ * Params: name -> new name for the cloned notebook
+ * noteId -> Id for the notebook to be cloned
+ */
+ cloneNote: (
+ client: ILegacyScopedClusterClient,
+ params: { name: string; noteId: string },
+ wreckOptions: optionsType
+ ) => Promise;
+
+ /* Delete a notebook
+ * Param: noteId -> Id for the notebook to be deleted
+ */
+ deleteNote: (
+ client: ILegacyScopedClusterClient,
+ noteId: string,
+ wreckOptions: optionsType
+ ) => Promise;
+
+ /* Export a notebook
+ * Param: noteId -> Id for the notebook to be exported
+ */
+ exportNote: (
+ client: ILegacyScopedClusterClient,
+ noteId: string,
+ wreckOptions: optionsType
+ ) => Promise;
+
+ /* Import a notebook
+ * Params: noteObj -> note Object to be imported
+ */
+ importNote: (
+ client: ILegacyScopedClusterClient,
+ noteObj: any,
+ wreckOptions: optionsType
+ ) => Promise;
+
+ /* --> Updates a Paragraph with input content
+ * --> Runs it
+ * --> Fetches the updated Paragraph (with new input content and output result)
+ * Params: noteId -> Id of the notebook
+ * paragraphId -> Id of the paragraph to be updated
+ * paragraphInput -> paragraph input code
+ */
+ updateRunFetchParagraph: (
+ client: ILegacyScopedClusterClient,
+ request: any,
+ wreckOptions: optionsType
+ ) => Promise;
+
+ /* --> Updates a Paragraph with input content
+ * --> Fetches the updated Paragraph (with new input content)
+ * Params: noteId -> Id of the notebook
+ * paragraphId -> Id of the paragraph to be updated
+ * paragraphInput -> paragraph input code
+ */
+ updateFetchParagraph: (
+ client: ILegacyScopedClusterClient,
+ params: { noteId: string; paragraphId: string; paragraphInput: string },
+ wreckOptions: optionsType
+ ) => Promise;
+
+ /* --> Adds a Paragraph with input content
+ * --> Fetches the Paragraph
+ * Params: noteId -> Id of the notebook
+ * paragraphId -> Id of the paragraph to be fetched
+ */
+ addFetchNewParagraph: (
+ client: ILegacyScopedClusterClient,
+ params: { noteId: string; paragraphIndex: number; paragraphInput: string; inputType: string },
+ wreckOptions: optionsType
+ ) => Promise;
+
+ /* --> Deletes a Paragraph with id
+ * --> Fetches the all other Paragraphs as a list
+ * Params: noteId -> Id of the notebook
+ * paragraphId -> Id of the paragraph to be deleted
+ */
+ deleteFetchParagraphs: (
+ client: ILegacyScopedClusterClient,
+ params: { noteId: string; paragraphId: string },
+ wreckOptions: optionsType
+ ) => Promise<{ paragraphs: any }>;
+
+ /* --> Clears output for all the paragraphs
+ * --> Fetches the all Paragraphs as a list (with cleared outputs)
+ * Param: noteId -> Id of notebook to be cleared
+ */
+ clearAllFetchParagraphs: (
+ client: ILegacyScopedClusterClient,
+ params: { noteId: string },
+ wreckOptions: optionsType
+ ) => Promise<{ paragraphs: any }>;
+}
diff --git a/server/adaptors/notebooks/zeppelin_backend.ts b/server/adaptors/notebooks/zeppelin_backend.ts
new file mode 100644
index 0000000000..1c2bb1b88b
--- /dev/null
+++ b/server/adaptors/notebooks/zeppelin_backend.ts
@@ -0,0 +1,411 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { ILegacyScopedClusterClient } from '../../../../../src/core/server';
+import { optionsType } from '../../../common/types/notebooks';
+import { requestor } from '../../common/helpers/notebooks/wreck_requests';
+import { NotebookAdaptor } from './notebook_adaptor';
+
+export class ZeppelinBackend implements NotebookAdaptor {
+ backend = 'Zeppelin Backend';
+
+ // Gets all the notebooks available from Zeppelin Server
+ // ZS Endpoint => http://[zeppelin-server]:[zeppelin-port]/api/notebook
+ viewNotes = async function (client: ILegacyScopedClusterClient, wreckOptions: optionsType) {
+ try {
+ let output = [];
+ const body = await requestor('GET', 'api/notebook/', wreckOptions);
+ output = JSON.parse(body.toString()).body;
+ return output;
+ } catch (error) {
+ throw new Error('View Notebooks Error:' + error);
+ }
+ };
+
+ /* Fetches a notebook by id from Zeppelin Server
+ * Param: noteId -> Id of notebook to be fetched
+ * ZS Endpoint => http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]
+ */
+ fetchNote = async function (
+ client: ILegacyScopedClusterClient,
+ noteId: string,
+ wreckOptions: optionsType
+ ) {
+ try {
+ const body = await requestor('GET', 'api/notebook/' + noteId, wreckOptions);
+ return JSON.parse(body.toString()).body.paragraphs;
+ } catch (error) {
+ throw new Error('Fetching Notebook Error:' + error);
+ }
+ };
+
+ /* Add a notebook to the Zeppelin Server
+ * Param: name -> name of new notebook
+ * ZS Endpoint => http://[zeppelin-server]:[zeppelin-port]/api/notebook
+ */
+ addNote = async function (
+ client: ILegacyScopedClusterClient,
+ params: { name: string },
+ wreckOptions: optionsType
+ ) {
+ wreckOptions.payload = params;
+ try {
+ const body = await requestor('POST', 'api/notebook/', wreckOptions);
+ return JSON.parse(body.toString());
+ } catch (error) {
+ throw new Error('Creating New Notebook Error:' + error);
+ }
+ };
+
+ /* Rename a notebook in Zeppelin Server
+ * Params: name -> new name for the notebook to be renamed
+ * noteId -> Id of notebook to be fetched
+ * ZS Endpoint => http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/rename
+ */
+ renameNote = async function (
+ client: ILegacyScopedClusterClient,
+ params: { name: string; noteId: string },
+ wreckOptions: optionsType
+ ) {
+ wreckOptions.payload = { name: params.name };
+ try {
+ const body = await requestor(
+ 'PUT',
+ 'api/notebook/' + params.noteId + '/rename/',
+ wreckOptions
+ );
+ return JSON.parse(body.toString());
+ } catch (error) {
+ throw new Error('Renaming Notebook Error:' + error);
+ }
+ };
+
+ /* Clone a notebook in Zeppelin Server
+ * Params: name -> new name for the cloned notebook
+ * noteId -> Id for the notebook to be cloned
+ * ZS Endpoint => http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]
+ */
+ cloneNote = async function (
+ client: ILegacyScopedClusterClient,
+ params: { name: string; noteId: string },
+ wreckOptions: optionsType
+ ) {
+ wreckOptions.payload = { name: params.name };
+ try {
+ const body = await requestor('POST', 'api/notebook/' + params.noteId, wreckOptions);
+ return JSON.parse(body.toString());
+ } catch (error) {
+ throw new Error('Cloning Notebook Error:' + error);
+ }
+ };
+
+ /* Delete a notebook in Zeppelin Server
+ * Param: noteId -> Id for the notebook to be deleted
+ * ZS Endpoint => http://[zeppelin-server]:[zeppelin-port]/api/notebook
+ */
+ deleteNote = async function (
+ client: ILegacyScopedClusterClient,
+ noteId: string,
+ wreckOptions: optionsType
+ ) {
+ try {
+ const body = await requestor('DELETE', 'api/notebook/' + noteId, wreckOptions);
+ return JSON.parse(body.toString());
+ } catch (error) {
+ throw new Error('Deleting Notebook Error:' + error);
+ }
+ };
+
+ /* Export a notebook from Zeppelin Server
+ * Param: noteId -> Id for the notebook to be exported
+ * ZS Endpoint => http://[zeppelin-server]:[zeppelin-port]/api/notebook/export/{noteid}
+ */
+ exportNote = async function (
+ client: ILegacyScopedClusterClient,
+ noteId: string,
+ wreckOptions: optionsType
+ ) {
+ try {
+ const body = await requestor('GET', 'api/notebook/export/' + noteId, wreckOptions);
+ return JSON.parse(body.toString());
+ } catch (error) {
+ throw new Error('Export Notebook Error:' + error);
+ }
+ };
+
+ /* Import a notebook in Zeppelin Server
+ * Params: noteObj -> note Object to be imported
+ * ZS Endpoint => http://[zeppelin-server]:[zeppelin-port]/api/notebook/import
+ */
+ importNote = async function (
+ client: ILegacyScopedClusterClient,
+ noteObj: any,
+ wreckOptions: optionsType
+ ) {
+ wreckOptions.payload = noteObj;
+ try {
+ const body = await requestor('POST', 'api/notebook/import', wreckOptions);
+ const respBody = JSON.parse(body.toString());
+ return respBody;
+ } catch (error) {
+ throw new Error('Import Notebook Error:' + error);
+ }
+ };
+
+ /* Add a paragraph in notebook
+ * Params: noteId -> Id for the notebook
+ * paragraphIndex -> index(position) to add a new paragraph
+ * paragraphInput -> paragraph input code
+ * ZS Endpoint => http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/paragraph
+ */
+ addParagraph = async function (
+ wreckOptions: optionsType,
+ params: { paragraphIndex: number; noteId: string; paragraphInput: string; inputType: string }
+ ) {
+ const visualizationPrefix = '%sh #vizobject:';
+ const observabilityVisualizationPrefix = '%sh #observabilityviz:';
+ let paragraphText = params.paragraphInput;
+
+ if (
+ params.inputType === 'VISUALIZATION' &&
+ params.paragraphInput.substring(0, 15) !== visualizationPrefix
+ ) {
+ paragraphText = visualizationPrefix + paragraphText;
+ }
+
+ if (
+ params.inputType === 'OBSERVABILITY_VISUALIZATION' &&
+ params.paragraphInput.substring(0, 22) !== observabilityVisualizationPrefix
+ ) {
+ paragraphText = visualizationPrefix + paragraphText;
+ }
+
+ if (params.paragraphInput === '') {
+ paragraphText = '%md\n';
+ }
+
+ wreckOptions.payload = {
+ title: params.inputType,
+ text: paragraphText,
+ index: params.paragraphIndex,
+ };
+
+ try {
+ const body = await requestor(
+ 'POST',
+ 'api/notebook/' + params.noteId + '/paragraph',
+ wreckOptions
+ );
+ const respBody = JSON.parse(body.toString());
+ return respBody;
+ } catch (error) {
+ throw new Error('Adding Paragraph Error:' + error);
+ }
+ };
+
+ /* Update a Paragraph in notebook
+ * Params: noteId -> Id of the notebook
+ * paragraphId -> Id of the paragraph to be updated
+ * paragraphInput -> paragraph input code
+ * ZS Endpoint => http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/paragraph/[paragraphId]
+ */
+ updateParagraph = async function (
+ wreckOptions: optionsType,
+ params: { noteId: string; paragraphId: string; paragraphInput: string; paragraphType?: string }
+ ) {
+ wreckOptions.payload = {
+ text: params.paragraphInput,
+ };
+ if (params.paragraphType !== undefined) wreckOptions.payload.title = params.paragraphType;
+ try {
+ const body = await requestor(
+ 'PUT',
+ 'api/notebook/' + params.noteId + '/paragraph/' + params.paragraphId,
+ wreckOptions
+ );
+ return JSON.parse(body.toString());
+ } catch (error) {
+ throw new Error('Updating Paragraph Error:' + error);
+ }
+ };
+
+ /* Run a Paragraph in notebook
+ * Params: noteId -> Id of the notebook
+ * paragraphId -> Id of the paragraph to be run
+ * ZS Endpoint => http://[zeppelin-server]:[zeppelin-port]/api/notebook/run/[noteId]/[paragraphId]
+ */
+ runPara = async function (
+ wreckOptions: optionsType,
+ params: { noteId: string; paragraphId: string }
+ ) {
+ wreckOptions.payload = {};
+ try {
+ const body = await requestor(
+ 'POST',
+ 'api/notebook/run/' + params.noteId + '/' + params.paragraphId,
+ wreckOptions
+ );
+ return JSON.parse(body.toString()).status;
+ } catch (error) {
+ throw new Error('Running Paragraph Error:' + error);
+ }
+ };
+
+ /* Fetch a Paragraph from notebook
+ * Params: noteId -> Id of the notebook
+ * paragraphId -> Id of the paragraph to be fetched
+ * ZS Endpoint => http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/paragraph/[paragraphId]
+ */
+ fetchParagraph = async function (
+ wreckOptions: optionsType,
+ params: { noteId: string; paragraphId: string }
+ ) {
+ try {
+ const body = await requestor(
+ 'GET',
+ 'api/notebook/' + params.noteId + '/paragraph/' + params.paragraphId,
+ wreckOptions
+ );
+ return JSON.parse(body.toString()).body;
+ } catch (error) {
+ throw new Error('Fetching Paragraph Error:' + error);
+ }
+ };
+
+ /* Delete a Paragraph in notebook
+ * Params: noteId -> Id of the notebook
+ * paragraphId -> Id of the paragraph to be deleted
+ * ZS Endpoint => http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/paragraph/[paragraphId]
+ */
+ deleteParagraph = async function (
+ wreckOptions: optionsType,
+ params: { noteId: string; paragraphId: string }
+ ) {
+ wreckOptions.payload = {};
+ try {
+ const body = await requestor(
+ 'DELETE',
+ 'api/notebook/' + params.noteId + '/paragraph/' + params.paragraphId,
+ wreckOptions
+ );
+ return JSON.parse(body.toString()).status;
+ } catch (error) {
+ throw new Error('Deleting Paragraph Error:' + error);
+ }
+ };
+
+ /* Clear all the paragraphs in the notebook
+ * Param: noteId -> Id of notebook to be cleared
+ * ZS Endpoint => http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/clear
+ */
+ clearAllParagraphs = async function (wreckOptions: optionsType, noteid: string) {
+ try {
+ const body = await requestor('PUT', 'api/notebook/' + noteid + '/clear', wreckOptions);
+ return JSON.parse(body.toString()).status;
+ } catch (error) {
+ throw new Error('Clearing Paragraph Error:' + error);
+ }
+ };
+
+ /* --> Updates a Paragraph with input content
+ * --> Runs it
+ * --> Fetches the updated Paragraph (with new input content and output result)
+ * Params: noteId -> Id of the notebook
+ * paragraphId -> Id of the paragraph to be updated
+ * paragraphInput -> paragraph input code
+ */
+ updateRunFetchParagraph = async function (
+ client: ILegacyScopedClusterClient,
+ request: any,
+ wreckOptions: optionsType
+ ) {
+ const params = request.params;
+ try {
+ const updateInfo = await this.updateParagraph(wreckOptions, params);
+ const runInfo = await this.runPara(wreckOptions, params);
+ const getInfo = await this.fetchParagraph(wreckOptions, params);
+ return getInfo;
+ } catch (error) {
+ throw new Error('Update/Run Paragraph Error:' + error);
+ }
+ };
+
+ /* --> Updates a Paragraph with input content
+ * --> Fetches the updated Paragraph (with new input content)
+ * Params: noteId -> Id of the notebook
+ * paragraphId -> Id of the paragraph to be updated
+ * paragraphInput -> paragraph input code
+ */
+ updateFetchParagraph = async function (
+ client: ILegacyScopedClusterClient,
+ params: { noteId: string; paragraphId: string; paragraphInput: string },
+ wreckOptions: optionsType
+ ) {
+ try {
+ const updateInfo = await this.updateParagraph(wreckOptions, params);
+ const getInfo = await this.fetchParagraph(wreckOptions, params);
+ return getInfo;
+ } catch (error) {
+ throw new Error('Save Paragraph Error:' + error);
+ }
+ };
+
+ /* --> Adds a Paragraph with input content
+ * --> Fetches the Paragraph
+ * Params: noteId -> Id of the notebook
+ * paragraphId -> Id of the paragraph to be fetched
+ */
+ addFetchNewParagraph = async function (
+ client: ILegacyScopedClusterClient,
+ params: { noteId: string; paragraphIndex: number; paragraphInput: string; inputType: string },
+ wreckOptions: optionsType
+ ) {
+ try {
+ const respBody = await this.addParagraph(wreckOptions, params);
+ const payload = { ...params, paragraphId: respBody.body };
+ const getinfo = await this.fetchParagraph(wreckOptions, payload);
+ return getinfo;
+ } catch (error) {
+ throw new Error('add/Fetch Paragraph Error:' + error);
+ }
+ };
+
+ /* --> Deletes a Paragraph with id
+ * --> Fetches the all other Paragraphs as a list
+ * Params: noteId -> Id of the notebook
+ * paragraphId -> Id of the paragraph to be deleted
+ */
+ deleteFetchParagraphs = async function (
+ client: ILegacyScopedClusterClient,
+ params: { noteId: string; paragraphId: string },
+ wreckOptions: optionsType
+ ) {
+ try {
+ const delinfo = await this.deleteParagraph(wreckOptions, params);
+ const notebookinfo = await this.fetchNote(client, params.noteId, wreckOptions);
+ return { paragraphs: notebookinfo };
+ } catch (error) {
+ throw new Error('Delete Paragraph Error:' + error);
+ }
+ };
+
+ /* --> Clears output for all the paragraphs
+ * --> Fetches the all Paragraphs as a list (with cleared outputs)
+ * Param: noteId -> Id of notebook to be cleared
+ */
+ clearAllFetchParagraphs = async function (
+ client: ILegacyScopedClusterClient,
+ params: { noteId: string },
+ wreckOptions: optionsType
+ ) {
+ try {
+ const clearinfo = await this.clearAllParagraphs(wreckOptions, params.noteId);
+ const notebookinfo = await this.fetchNote(client, params.noteId, wreckOptions);
+ return { paragraphs: notebookinfo };
+ } catch (error) {
+ throw new Error('Clear Paragraph Error:' + error);
+ }
+ };
+}
diff --git a/server/adaptors/opensearch_observability_plugin.ts b/server/adaptors/opensearch_observability_plugin.ts
new file mode 100644
index 0000000000..2a99187c65
--- /dev/null
+++ b/server/adaptors/opensearch_observability_plugin.ts
@@ -0,0 +1,123 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { OPENSEARCH_PANELS_API } from "../../common/constants/shared";
+
+export function OpenSearchObservabilityPlugin(
+ Client: any,
+ config: any,
+ components: any
+) {
+ const clientAction = components.clientAction.factory;
+
+ Client.prototype.observability = components.clientAction.namespaceFactory();
+ const observability = Client.prototype.observability.prototype;
+
+ // Get Object
+ observability.getObject = clientAction({
+ url: {
+ fmt: OPENSEARCH_PANELS_API.OBJECT,
+ params: {
+ objectId: {
+ type: "string",
+ },
+ objectIdList: {
+ type: "string",
+ },
+ objectType: {
+ type: "string",
+ },
+ sortField: {
+ type: "string",
+ },
+ sortOrder: {
+ type: "string",
+ },
+ fromIndex: {
+ type: "number",
+ },
+ maxItems: {
+ type: "number",
+ },
+ name: {
+ type: "string",
+ },
+ lastUpdatedTimeMs: {
+ type: "string",
+ },
+ createdTimeMs: {
+ type: "string",
+ },
+ },
+ },
+ method: "GET",
+ });
+
+ // Get Object by Id
+ observability.getObjectById = clientAction({
+ url: {
+ fmt: `${OPENSEARCH_PANELS_API.OBJECT}/<%=objectId%>`,
+ req: {
+ objectId: {
+ type: "string",
+ required: true,
+ },
+ },
+ },
+ method: "GET",
+ });
+
+ // Create new Object
+ observability.createObject = clientAction({
+ url: {
+ fmt: OPENSEARCH_PANELS_API.OBJECT,
+ },
+ method: "POST",
+ needBody: true,
+ });
+
+ // Update Object by Id
+ observability.updateObjectById = clientAction({
+ url: {
+ fmt: `${OPENSEARCH_PANELS_API.OBJECT}/<%=objectId%>`,
+ req: {
+ objectId: {
+ type: "string",
+ required: true,
+ },
+ },
+ },
+ method: "PUT",
+ needBody: true,
+ });
+
+ // Delete Object by Id
+ observability.deleteObjectById = clientAction({
+ url: {
+ fmt: `${OPENSEARCH_PANELS_API.OBJECT}/<%=objectId%>`,
+ req: {
+ objectId: {
+ type: "string",
+ required: true,
+ },
+ },
+ },
+ method: "DELETE",
+ });
+
+ // Delete Object by Id List
+ observability.deleteObjectByIdList = clientAction({
+ url: {
+ fmt: OPENSEARCH_PANELS_API.OBJECT,
+ params: {
+ objectIdList: {
+ type: "string",
+ required: true,
+ },
+ },
+ },
+ method: "DELETE",
+ });
+}
diff --git a/server/adaptors/ppl_datasource.ts b/server/adaptors/ppl_datasource.ts
new file mode 100644
index 0000000000..f5b6262f94
--- /dev/null
+++ b/server/adaptors/ppl_datasource.ts
@@ -0,0 +1,93 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import _ from 'lodash';
+import {
+ IPPLEventsDataSource,
+ IPPLVisualizationDataSource
+} from '../common/types';
+
+type PPLResponse = IPPLEventsDataSource & IPPLVisualizationDataSource;
+
+export class PPLDataSource {
+
+ constructor(
+ private pplDataSource: PPLResponse,
+ private dataType: string
+ ) {
+ if (this.dataType === 'jdbc') {
+ this.addSchemaRowMapping();
+ } else if (this.dataType === 'viz') {
+ this.addStatsMapping();
+ }
+ }
+
+ private addStatsMapping = () => {
+ const visData = this.pplDataSource;
+
+ /**
+ * Add vis mapping for runtime fields
+ * json data structure added to response will be
+ * [{
+ * agent: "mozilla",
+ * avg(bytes): 5756
+ * ...
+ * }, {
+ * agent: "MSIE",
+ * avg(bytes): 5605
+ * ...
+ * }, {
+ * agent: "chrome",
+ * avg(bytes): 5648
+ * ...
+ * }]
+ */
+ let res = [];
+ if (visData?.metadata?.fields) {
+ const queriedFields = visData.metadata.fields;
+ for (let i = 0; i < visData.size; i++) {
+ const entry: any = {};
+ queriedFields.map((field: any) => {
+ const statsDataSet = visData?.data;
+ entry[field.name] = statsDataSet[field.name][i];
+ });
+ res.push(entry);
+ }
+ visData['jsonData'] = res;
+ }
+ }
+
+ /**
+ * Add 'schemaName: data' entries for UI rendering
+ */
+ private addSchemaRowMapping = () => {
+
+ const pplRes = this.pplDataSource;
+
+ const data: any[] = [];
+
+ _.forEach(pplRes.datarows, (row) => {
+ const record: any = {};
+
+ for (let i = 0; i < pplRes.schema.length; i++) {
+
+ const cur = pplRes.schema[i];
+
+ if (typeof(row[i]) === 'object') {
+ record[cur.name] = JSON.stringify(row[i]);
+ } else if (typeof(row[i]) === 'boolean') {
+ record[cur.name] = row[i].toString();
+ } else {
+ record[cur.name] = row[i];
+ }
+ }
+
+ data.push(record);
+ });
+ pplRes['jsonData'] = data;
+ };
+
+ public getDataSource = () : PPLResponse => this.pplDataSource;
+}
\ No newline at end of file
diff --git a/server/adaptors/ppl_plugin.ts b/server/adaptors/ppl_plugin.ts
new file mode 100644
index 0000000000..304d196e3f
--- /dev/null
+++ b/server/adaptors/ppl_plugin.ts
@@ -0,0 +1,40 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { PPL_ENDPOINT, SQL_ENDPOINT } from '../../common/constants/shared';
+
+export const PPLPlugin = function (Client, config, components) {
+ const ca = components.clientAction.factory;
+ Client.prototype.ppl = components.clientAction.namespaceFactory();
+ const ppl = Client.prototype.ppl.prototype;
+
+ ppl.pplQuery = ca({
+ url: {
+ fmt: `${PPL_ENDPOINT}`,
+ params: {
+ format: {
+ type: 'string',
+ required: true,
+ },
+ },
+ },
+ needBody: true,
+ method: 'POST',
+ });
+
+ ppl.sqlQuery = ca({
+ url: {
+ fmt: `${SQL_ENDPOINT}`,
+ params: {
+ format: {
+ type: 'string',
+ required: true,
+ },
+ },
+ },
+ needBody: true,
+ method: 'POST',
+ });
+};
diff --git a/server/common/helpers/custom_panels/sample_panels.ts b/server/common/helpers/custom_panels/sample_panels.ts
new file mode 100644
index 0000000000..3ef7a31c8e
--- /dev/null
+++ b/server/common/helpers/custom_panels/sample_panels.ts
@@ -0,0 +1,80 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { v4 as uuidv4 } from 'uuid';
+
+export const createDemoPanel = (savedVisualizationIds: string[]) => {
+ return {
+ name: '[Logs] Web traffic Panel',
+ visualizations: [
+ {
+ id: 'panel_viz_' + uuidv4(),
+ savedVisualizationId: savedVisualizationIds[0],
+ x: 4,
+ y: 6,
+ w: 8,
+ h: 2,
+ },
+ {
+ id: 'panel_viz_' + uuidv4(),
+ savedVisualizationId: savedVisualizationIds[1],
+ x: 0,
+ y: 2,
+ w: 12,
+ h: 2,
+ },
+ {
+ id: 'panel_viz_' + uuidv4(),
+ savedVisualizationId: savedVisualizationIds[2],
+ x: 0,
+ y: 0,
+ w: 4,
+ h: 2,
+ },
+ {
+ id: 'panel_viz_' + uuidv4(),
+ savedVisualizationId: savedVisualizationIds[3],
+ x: 4,
+ y: 0,
+ w: 4,
+ h: 2,
+ },
+ {
+ id: 'panel_viz_' + uuidv4(),
+ savedVisualizationId: savedVisualizationIds[4],
+ x: 8,
+ y: 0,
+ w: 4,
+ h: 2,
+ },
+ {
+ id: 'panel_viz_' + uuidv4(),
+ savedVisualizationId: savedVisualizationIds[5],
+ x: 0,
+ y: 4,
+ w: 4,
+ h: 2,
+ },
+ {
+ id: 'panel_viz_' + uuidv4(),
+ savedVisualizationId: savedVisualizationIds[6],
+ x: 0,
+ y: 6,
+ w: 4,
+ h: 2,
+ },
+ {
+ id: 'panel_viz_' + uuidv4(),
+ savedVisualizationId: savedVisualizationIds[7],
+ x: 4,
+ y: 4,
+ w: 8,
+ h: 2,
+ },
+ ],
+ timeRange: { to: 'now/y', from: 'now/y' },
+ queryFilter: { query: '', language: 'ppl' },
+ };
+};
diff --git a/server/common/helpers/events_explorer/sample_savedObjects.ts b/server/common/helpers/events_explorer/sample_savedObjects.ts
new file mode 100644
index 0000000000..fadcbfc308
--- /dev/null
+++ b/server/common/helpers/events_explorer/sample_savedObjects.ts
@@ -0,0 +1,383 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export const sampleVisualizations = [
+ {
+ name: '[Logs] Daily average bytes',
+ description: '',
+ query:
+ 'source = opensearch_dashboards_sample_data_logs | stats avg(bytes) by span(timestamp,1d)',
+ type: 'line',
+ selected_date_range: {
+ start: 'now/y',
+ end: 'now',
+ text: '',
+ },
+ selected_timestamp: {
+ name: 'timestamp',
+ type: 'timestamp',
+ },
+ selected_fields: {
+ text: '',
+ tokens: [],
+ },
+ },
+ {
+ name: '[Logs] Daily count for error response codes',
+ description: '',
+ query:
+ "source = opensearch_dashboards_sample_data_logs | where response='503' or response='404' | stats count() by span(timestamp,1d)",
+ type: 'bar',
+ selected_date_range: {
+ start: 'now/y',
+ end: 'now',
+ text: '',
+ },
+ selected_timestamp: {
+ name: 'timestamp',
+ type: 'timestamp',
+ },
+ selected_fields: {
+ text: '',
+ tokens: [],
+ },
+ },
+ {
+ name: '[Logs] Average ram usage by operating systems',
+ description: '',
+ query:
+ 'source = opensearch_dashboards_sample_data_logs | stats avg(machine.ram) by machine.os',
+ type: 'horizontal_bar',
+ selected_date_range: {
+ start: 'now/y',
+ end: 'now',
+ text: '',
+ },
+ selected_timestamp: {
+ name: 'timestamp',
+ type: 'timestamp',
+ },
+ selected_fields: {
+ text: '',
+ tokens: [],
+ },
+ },
+ {
+ name: '[Logs] Average ram usage per day by apple os',
+ description: '',
+ query:
+ "source = opensearch_dashboards_sample_data_logs | where machine.os='osx' or machine.os='ios' | stats avg(machine.ram) by span(timestamp,1d)",
+ type: 'line',
+ selected_date_range: {
+ start: 'now/y',
+ end: 'now',
+ text: '',
+ },
+ selected_timestamp: {
+ name: 'timestamp',
+ type: 'timestamp',
+ },
+ selected_fields: {
+ text: '',
+ tokens: [],
+ },
+ },
+ {
+ name: '[Logs] Average ram usage per day by windows os ',
+ description: '',
+ query:
+ "source = opensearch_dashboards_sample_data_logs | where match(machine.os,'win') | stats avg(machine.ram) by span(timestamp,1d)",
+ type: 'line',
+ selected_date_range: {
+ start: 'now/y',
+ end: 'now',
+ text: '',
+ },
+ selected_timestamp: {
+ name: 'timestamp',
+ type: 'timestamp',
+ },
+ selected_fields: {
+ text: '',
+ tokens: [],
+ },
+ },
+
+ {
+ name: '[Logs] Count requests from US to CN, IN and JP',
+ description: '',
+ query:
+ "source = opensearch_dashboards_sample_data_logs | where geo.src='US' | where geo.dest='JP' or geo.dest='CN' or geo.dest='IN' | stats count() by geo.dest",
+ type: 'bar',
+ selected_date_range: {
+ start: 'now/y',
+ end: 'now',
+ text: '',
+ },
+ selected_timestamp: {
+ name: 'timestamp',
+ type: 'timestamp',
+ },
+ selected_fields: {
+ text: '',
+ tokens: [],
+ },
+ },
+ {
+ name: '[Logs] Count total requests by tags ',
+ description: '',
+ query: 'source = opensearch_dashboards_sample_data_logs | stats count() by tags',
+ type: 'bar',
+ selected_date_range: {
+ start: 'now/y',
+ end: 'now',
+ text: '',
+ },
+ selected_timestamp: {
+ name: 'timestamp',
+ type: 'timestamp',
+ },
+ selected_fields: {
+ text: '',
+ tokens: [],
+ },
+ },
+ {
+ name: '[Logs] Max and average bytes by host',
+ description: '',
+ query: 'source = opensearch_dashboards_sample_data_logs | stats max(bytes), avg(bytes) by host',
+ type: 'line',
+ selected_date_range: {
+ start: 'now/y',
+ end: 'now',
+ text: '',
+ },
+ selected_timestamp: {
+ name: 'timestamp',
+ type: 'timestamp',
+ },
+ selected_fields: {
+ text: '',
+ tokens: [],
+ },
+ },
+];
+
+export const sampleQueries = [
+ {
+ name: '[Flights] Show all flights sorted by most delayed',
+ description: '',
+ query: 'source=opensearch_dashboards_sample_data_flights | sort -FlightDelayMin',
+ selected_date_range: {
+ start: 'now/M',
+ end: 'now',
+ text: '',
+ },
+ selected_timestamp: {
+ name: 'timestamp',
+ type: 'timestamp',
+ },
+ selected_fields: {
+ text: '',
+ tokens: [
+ {
+ name: 'Carrier',
+ type: 'string',
+ },
+ {
+ name: 'Dest',
+ type: 'string',
+ },
+ {
+ name: 'DestAirportID',
+ type: 'string',
+ },
+ {
+ name: 'FlightDelayMin',
+ type: 'integer',
+ },
+ {
+ name: 'OriginAirportID',
+ type: 'string',
+ },
+ ],
+ },
+ },
+ {
+ name: '[Logs] Show all logs lines where error code is 404 or 503',
+ description: '',
+ query: "source=opensearch_dashboards_sample_data_logs | where response='503' or response='404'",
+ selected_date_range: {
+ start: 'now/y',
+ end: 'now',
+ text: '',
+ },
+ selected_timestamp: {
+ name: 'timestamp',
+ type: 'timestamp',
+ },
+ selected_fields: {
+ text: '',
+ tokens: [],
+ },
+ },
+ {
+ name:
+ '[Logs] Show all logs lines where error code is 404 or 503 and deduplicate consecutive entries only',
+ description: '',
+ query:
+ "source=opensearch_dashboards_sample_data_logs | where response='503' or response='404' | dedup host consecutive=true",
+ selected_date_range: {
+ start: 'now/y',
+ end: 'now',
+ text: '',
+ },
+ selected_timestamp: {
+ name: 'timestamp',
+ type: 'timestamp',
+ },
+ selected_fields: {
+ text: '',
+ tokens: [],
+ },
+ },
+ {
+ name: '[Logs] Show all hosts with errors aggregated by response, count of ips and tags',
+ description: '',
+ query:
+ "source=opensearch_dashboards_sample_data_logs | where response='503' or response='404' | stats count() as ip_count by response , host , tags",
+ selected_date_range: {
+ start: 'now/y',
+ end: 'now',
+ text: '',
+ },
+ selected_timestamp: {
+ name: 'timestamp',
+ type: 'timestamp',
+ },
+ selected_fields: {
+ text: '',
+ tokens: [],
+ },
+ },
+ {
+ name: '[Flights] Show the count of flights by Destination and Country',
+ description: '',
+ query:
+ 'source=opensearch_dashboards_sample_data_flights | stats count() by DestCountry , Dest',
+ selected_date_range: {
+ start: 'now/M',
+ end: 'now',
+ text: '',
+ },
+ selected_timestamp: {
+ name: 'timestamp',
+ type: 'timestamp',
+ },
+ selected_fields: {
+ text: '',
+ tokens: [],
+ },
+ },
+ {
+ name: '[Flights] Show all Carriers sorted by average delay',
+ description: '',
+ query:
+ 'source=opensearch_dashboards_sample_data_flights |where FlightDelayMin > 0 | stats sum(FlightDelayMin) as total_delay_min, count() as total_delayed by Carrier |eval avg_delay=total_delay_min / total_delayed | sort - avg_delay',
+ selected_date_range: {
+ start: 'now/y',
+ end: 'now',
+ text: '',
+ },
+ selected_timestamp: {
+ name: 'timestamp',
+ type: 'timestamp',
+ },
+ selected_fields: {
+ text: '',
+ tokens: [],
+ },
+ },
+ {
+ name: '[Logs] Show errors sorted by list of hostnames and average bytes per ip',
+ description: '',
+ query:
+ "source=opensearch_dashboards_sample_data_logs | where response='503' or response='404' | stats count() as ip_count, sum(bytes) as sum_bytes by host, response | rename response as resp_code | sort - ip_count, + sum_bytes | eval per_ip_bytes=sum_bytes/ip_count",
+ selected_date_range: {
+ start: 'now/y',
+ end: 'now',
+ text: '',
+ },
+ selected_timestamp: {
+ name: 'timestamp',
+ type: 'timestamp',
+ },
+ selected_fields: {
+ text: '',
+ tokens: [],
+ },
+ },
+ {
+ name: '[Logs] Show errors sorted by list of hostnames, by summation of bytes',
+ description: '',
+ query:
+ "source=opensearch_dashboards_sample_data_logs | where response='503' or response='404' | stats count() as ip_count, sum(bytes) as sum_bytes by host, response | sort -sum_bytes",
+ selected_date_range: {
+ start: 'now/y',
+ end: 'now',
+ text: '',
+ },
+ selected_timestamp: {
+ name: 'timestamp',
+ type: 'timestamp',
+ },
+ selected_fields: {
+ text: '',
+ tokens: [],
+ },
+ },
+ {
+ name: '[Logs] Show errors sorted by list of hostnames, by summation of bytes and complex evals',
+ description: '',
+ query:
+ "source=opensearch_dashboards_sample_data_logs | where response='503' or response='404' | stats count() as ip_count, sum(bytes) as sum_bytes by host, response | rename response as resp_code | sort - ip_count, + sum_bytes | eval per_ip_bytes=sum_bytes/ip_count, double_per_ip_bytes = 2 * per_ip_bytes",
+ selected_date_range: {
+ start: 'now/y',
+ end: 'now',
+ text: '',
+ },
+ selected_timestamp: {
+ name: 'timestamp',
+ type: 'timestamp',
+ },
+ selected_fields: {
+ text: '',
+ tokens: [],
+ },
+ },
+ {
+ name: '[Logs] Show all logs where request matches filebeat',
+ description: '',
+ query: "source = opensearch_dashboards_sample_data_logs | where match(request,'filebeat')",
+ selected_date_range: {
+ start: 'now/y',
+ end: 'now',
+ text: '',
+ },
+ selected_timestamp: {
+ name: 'timestamp',
+ type: 'timestamp',
+ },
+ selected_fields: {
+ text: '',
+ tokens: [
+ {
+ name: 'message',
+ type: 'string',
+ },
+ ],
+ },
+ },
+];
diff --git a/server/common/helpers/notebooks/default_notebook_schema.ts b/server/common/helpers/notebooks/default_notebook_schema.ts
new file mode 100644
index 0000000000..ca0c7969ed
--- /dev/null
+++ b/server/common/helpers/notebooks/default_notebook_schema.ts
@@ -0,0 +1,31 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+// Default Backend Notebook Schema
+
+export type DefaultInput = {
+ inputType: string;
+ inputText: string;
+};
+
+export type DefaultOutput = {
+ outputType: string;
+ result: string;
+ execution_time: string;
+};
+export type DefaultParagraph = {
+ id: string;
+ dateCreated: string;
+ dateModified: string;
+ input: DefaultInput;
+ output: Array;
+};
+export type DefaultNotebooks = {
+ name: string;
+ dateCreated: string;
+ dateModified: string;
+ backend: string;
+ paragraphs: Array;
+};
diff --git a/server/common/helpers/notebooks/query_helpers.ts b/server/common/helpers/notebooks/query_helpers.ts
new file mode 100644
index 0000000000..3da7e2ba60
--- /dev/null
+++ b/server/common/helpers/notebooks/query_helpers.ts
@@ -0,0 +1,35 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import QueryService from "../../../services/queryService";
+
+export const inputIsQuery = (inputText: string) => {
+ return (inputIsSQL(inputText) || inputIsPPL(inputText));
+}
+
+export const inputIsSQL = (inputText: string) => {
+ return inputText.substring(0, 4) === '%sql';
+}
+
+export const inputIsPPL = (inputText: string) => {
+ return inputText.substring(0, 4) === '%ppl';
+}
+
+export const getQueryOutput = async (inputText: string, queryService: QueryService) => {
+ let output = {};
+ if (inputIsSQL(inputText)) {
+ output = await queryService.describeSQLQuery(inputText);
+ }
+ else if (inputIsPPL(inputText)) {
+ output = await queryService.describePPLQuery(inputText);
+ }
+ return output;
+}
+
+export const formatNotRecognized = (inputText: string) => {
+ return (inputText.substring(0, 4) != '%sql' &&
+ inputText.substring(0, 4) != '%ppl' &&
+ inputText.substring(0, 3) != '%md')
+}
\ No newline at end of file
diff --git a/server/common/helpers/notebooks/sample_notebooks.ts b/server/common/helpers/notebooks/sample_notebooks.ts
new file mode 100644
index 0000000000..aceb72361e
--- /dev/null
+++ b/server/common/helpers/notebooks/sample_notebooks.ts
@@ -0,0 +1,1234 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { v4 as uuid } from 'uuid';
+
+const getDemoNotebook = (dateString: string, visId: string) => {
+ const uuids = [uuid()];
+ const oneWeekAgo = new Date();
+ oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);
+ return {
+ name: 'OpenSearch Notebooks Quick Start Guide',
+ dateCreated: dateString,
+ dateModified: dateString,
+ backend: 'Default',
+ paragraphs: [
+ {
+ output: [
+ {
+ result:
+ `An OpenSearch Dashboards notebook is an interface that lets you easily combine code snippets, live visualizations, and narrative text in a single notebook interface.
+
+Notebooks let you interactively explore data by running different visualizations that you can share with team members to collaborate on a project.
+
+A notebook is a document composed of two elements: code blocks (Markdown/SQL/PPL) and visualizations.
+
+Common use cases include creating postmortem reports, designing runbooks, building live infrastructure reports, and writing documentation.
+
+You can also generate [reports](https://opensearch.org/docs/dashboards/reporting/) directly from your notebooks.
+
+For more information, refer to the [documentation](https://opensearch.org/docs/dashboards/notebooks/).`,
+ outputType: 'MARKDOWN',
+ execution_time: '0 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+An OpenSearch Dashboards notebook is an interface that lets you easily combine code snippets, live visualizations, and narrative text in a single notebook interface.
+
+Notebooks let you interactively explore data by running different visualizations that you can share with team members to collaborate on a project.
+
+A notebook is a document composed of two elements: code blocks (Markdown/SQL/PPL) and visualizations.
+
+Common use cases include creating postmortem reports, designing runbooks, building live infrastructure reports, and writing documentation.
+
+You can also generate [reports](https://opensearch.org/docs/dashboards/reporting/) directly from your notebooks.
+
+For more information, refer to the [documentation](https://opensearch.org/docs/dashboards/notebooks/).`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: 'Notebooks combine code blocks and visualizations for describing data. Code blocks support markdown, SQL, and PPL languages. Specify the input language on the first line using %\[language type\] syntax. For example, type %md for markdown, %sql for SQL, and %ppl for PPL. A sample visualization is shown below:',
+ outputType: 'MARKDOWN',
+ execution_time: '0 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+Notebooks combine code blocks and visualizations for describing data. Code blocks support markdown, SQL, and PPL languages. Specify the input language on the first line using %\[language type\] syntax. For example, type %md for markdown, %sql for SQL, and %ppl for PPL. A sample visualization is shown below:`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: '',
+ outputType: 'VISUALIZATION',
+ execution_time: '0.017 ms',
+ },
+ ],
+ input: {
+ inputText: `{"viewMode":"view","panels":{"1":{"gridData":{"x":0,"y":0,"w":50,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"${visId}"}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"${uuids[0]}","timeRange":{"to":"${dateString}","from":"${oneWeekAgo}"},"title":"embed_viz_${uuids[0]}","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}`,
+ inputType: 'VISUALIZATION',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result:
+ 'You can add a new paragraph from the **Paragraph actions** menu on the top right of the page, the context menu on the top right of each paragraph, or the **Add paragraph** button on the bottom of the page.',
+ outputType: 'MARKDOWN',
+ execution_time: '0 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+You can add a new paragraph from the **Paragraph actions** menu on the top right of the page, the context menu on the top right of each paragraph, or the **Add paragraph** button on the bottom of the page.`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: 'You can also reorder, duplicate, or delete paragraphs from these menus.',
+ outputType: 'MARKDOWN',
+ execution_time: '0 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+You can also reorder, duplicate, or delete paragraphs from these menus.`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result:
+ 'To execute a paragraph, choose **Run**. To make changes to the input block, choose the downward arrow that\'s next to the paragraph title.',
+ outputType: 'MARKDOWN',
+ execution_time: '0 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+To execute a paragraph, choose **Run**. To make changes to the input block, choose the downward arrow that's next to the paragraph title.`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `There are three view modes:
+- **View both**: allows you to edit paragraphs and view outputs on the same page.
+- **Input only**: only shows input of each paragraph, allowing easier editing.
+- **Output only**: only shows output of each paragraph and hides panels.`,
+ outputType: 'MARKDOWN',
+ execution_time: '0 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+There are three view modes:
+- **View both**: allows you to edit paragraphs and view outputs on the same page.
+- **Input only**: only shows input of each paragraph, allowing easier editing.
+- **Output only**: only shows output of each paragraph and hides panels.`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: 'To go back, choose **Notebooks** on the top left of your screen.',
+ outputType: 'MARKDOWN',
+ execution_time: '0 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+To go back, choose **Notebooks** on the top left of your screen.`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ ],
+ };
+};
+
+const getRootCauseNotebook = (dateString: string, visIds: string[]) => {
+ const uuids = [uuid(), uuid()];
+ const oneWeekAgo = new Date();
+ oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);
+ return {
+ name: '[Logs] Sample Root Cause Event Analysis',
+ dateCreated: dateString,
+ dateModified: dateString,
+ backend: 'Default',
+ paragraphs: [
+ {
+ output: [
+ {
+ result:
+ 'This notebook goes through a sample root cause event analysis using PPL and visualizations with the OpenSearch Dashboards sample web logs data.',
+ outputType: 'MARKDOWN',
+ execution_time: '0.016 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+This notebook goes through a sample root cause event analysis using PPL and visualizations with the OpenSearch Dashboards sample web logs data.`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: "First, let's bring up a few visualizations for a quick overview.",
+ outputType: 'MARKDOWN',
+ execution_time: '0.046 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+First, let's bring up a few visualizations for a quick overview.`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: '',
+ outputType: 'VISUALIZATION',
+ execution_time: '0.017 ms',
+ },
+ ],
+ input: {
+ inputText: `{"viewMode":"view","panels":{"1":{"gridData":{"x":0,"y":0,"w":50,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"${visIds[0]}"}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"${uuids[0]}","timeRange":{"to":"${dateString}","from":"${oneWeekAgo}"},"title":"embed_viz_${uuids[0]}","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}`,
+ inputType: 'VISUALIZATION',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: '',
+ outputType: 'VISUALIZATION',
+ execution_time: '0.017 ms',
+ },
+ ],
+ input: {
+ inputText: `{"viewMode":"view","panels":{"1":{"gridData":{"x":0,"y":0,"w":50,"h":20,"i":"1"},"type":"visualization","explicitInput":{"id":"1","savedObjectId":"${visIds[1]}"}}},"isFullScreenMode":false,"filters":[],"useMargins":false,"id":"${uuids[1]}","timeRange":{"to":"${dateString}","from":"${oneWeekAgo}"},"title":"embed_viz_${uuids[1]}","query":{"query":"","language":"lucene"},"refreshConfig":{"pause":true,"value":15}}`,
+ inputType: 'VISUALIZATION',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `Let's take a look at the source data by the selected fields (search and fields).`,
+ outputType: 'MARKDOWN',
+ execution_time: '0.013 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+Let's take a look at the source data by the selected fields (search and fields).`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `
+ source=opensearch_dashboards_sample_data_logs | fields host, clientip,
+ response, bytes | head 20
+
+`,
+ outputType: 'QUERY',
+ execution_time: '0.008 ms',
+ },
+ ],
+ input: {
+ inputText: `%ppl
+ source=opensearch_dashboards_sample_data_logs | fields host, clientip,
+ response, bytes | head 20
+
+`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: 'Check for any error log with response code 404 or 503 (filter).',
+ outputType: 'MARKDOWN',
+ execution_time: '0.009 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+Check for any error log with response code 404 or 503 (filter).`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `
+ source=opensearch_dashboards_sample_data_logs | fields host, clientip, response, bytes | where response='503' or response='404' | head 20
+`,
+ outputType: 'QUERY',
+ execution_time: '0.007 ms',
+ },
+ ],
+ input: {
+ inputText: `%ppl
+ source=opensearch_dashboards_sample_data_logs | fields host, clientip, response, bytes | where response='503' or response='404' | head 20
+`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: 'We see too many events. Let\'s quickly check which host has the issue (dedup).',
+ outputType: 'MARKDOWN',
+ execution_time: '0.014 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+We see too many events. Let's quickly check which host has the issue (dedup).`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `
+ source=opensearch_dashboards_sample_data_logs | fields host, clientip, response,
+ bytes | where response='503' or response='404' | dedup host | head 20
+`,
+ outputType: 'QUERY',
+ execution_time: '0.010 ms',
+ },
+ ],
+ input: {
+ inputText: `%ppl
+ source=opensearch_dashboards_sample_data_logs | fields host, clientip, response,
+ bytes | where response='503' or response='404' | dedup host | head 20
+`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: 'We get too few events. Let\'s dedup in consecutive mode (dedup).',
+ outputType: 'MARKDOWN',
+ execution_time: '0.006 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+We get too few events. Let's dedup in consecutive mode (dedup).`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `
+ source=opensearch_dashboards_sample_data_logs | fields host, clientip, response,
+ bytes | where response='503' or response='404' |
+ dedup host consecutive=true | head 20
+`,
+ outputType: 'QUERY',
+ execution_time: '0.007 ms',
+ },
+ ],
+ input: {
+ inputText: `%ppl
+ source=opensearch_dashboards_sample_data_logs | fields host, clientip, response,
+ bytes | where response='503' or response='404' |
+ dedup host consecutive=true | head 20
+`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: 'How many IP addresses for each response (stats).',
+ outputType: 'MARKDOWN',
+ execution_time: '0.006 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+How many IP addresses for each response (stats).`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `
+ source=opensearch_dashboards_sample_data_logs | fields host, clientip, response,
+ bytes | where response='503' or response='404' |
+ stats count() as ip_count by response | head 20
+`,
+ outputType: 'QUERY',
+ execution_time: '0.008 ms',
+ },
+ ],
+ input: {
+ inputText: `%ppl
+ source=opensearch_dashboards_sample_data_logs | fields host, clientip, response,
+ bytes | where response='503' or response='404' |
+ stats count() as ip_count by response | head 20
+`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: 'To dive deep, let\'s group by host and response, count, and sum (stats).',
+ outputType: 'MARKDOWN',
+ execution_time: '0.006 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+To dive deep, let's group by host and response, count, and sum (stats).`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `
+ source=opensearch_dashboards_sample_data_logs | fields host, clientip, response,
+ bytes | where response='503' or response='404' |
+ stats count() as ip_count, sum(bytes)
+ as sum_bytes by host, response | head 20
+`,
+ outputType: 'QUERY',
+ execution_time: '0.007 ms',
+ },
+ ],
+ input: {
+ inputText: `%ppl
+ source=opensearch_dashboards_sample_data_logs | fields host, clientip, response,
+ bytes | where response='503' or response='404' |
+ stats count() as ip_count, sum(bytes)
+ as sum_bytes by host, response | head 20
+`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `We don't see a meaningful response. Let's change to resp_code (rename).`,
+ outputType: 'MARKDOWN',
+ execution_time: '0.006 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+We don't see a meaningful response. Let's change to resp_code (rename).`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `
+ source=opensearch_dashboards_sample_data_logs | fields host, clientip, response,
+ bytes | where response='503' or response='404' |
+ stats count() as ip_count, sum(bytes)
+ as sum_bytes by host, response |
+ rename response as resp_code | head 20
+
+`,
+ outputType: 'QUERY',
+ execution_time: '0.009 ms',
+ },
+ ],
+ input: {
+ inputText: `%ppl
+ source=opensearch_dashboards_sample_data_logs | fields host, clientip, response,
+ bytes | where response='503' or response='404' |
+ stats count() as ip_count, sum(bytes)
+ as sum_bytes by host, response |
+ rename response as resp_code | head 20
+
+`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: 'The data looks better now. Let\'s sort by `DESC count` and `ASC sum_bytes` (sort).',
+ outputType: 'MARKDOWN',
+ execution_time: '0.006 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+The data looks better now. Let's sort by \`DESC count\` and \`ASC sum_bytes\` (sort).`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `
+ source=opensearch_dashboards_sample_data_logs | fields host, clientip, response,
+ bytes | where response='503' or response='404' |
+ stats count() as ip_count, sum(bytes)
+ as sum_bytes by host, response |
+ rename response as resp_code |
+ sort - ip_count, + sum_bytes | head 20
+`,
+ outputType: 'QUERY',
+ execution_time: '0.006 ms',
+ },
+ ],
+ input: {
+ inputText: `%ppl
+ source=opensearch_dashboards_sample_data_logs | fields host, clientip, response,
+ bytes | where response='503' or response='404' |
+ stats count() as ip_count, sum(bytes)
+ as sum_bytes by host, response |
+ rename response as resp_code |
+ sort - ip_count, + sum_bytes | head 20
+`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: 'Let\'s check if we can perform aggregations after stats (eval).',
+ outputType: 'MARKDOWN',
+ execution_time: '0.006 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+Let's check if we can perform aggregations after stats (eval).`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `
+ source=opensearch_dashboards_sample_data_logs | fields host, clientip, response,
+ bytes | where response='503' or response='404' |
+ stats count() as ip_count, sum(bytes)
+ as sum_bytes by host, response |
+ rename response as resp_code |
+ sort - ip_count, + sum_bytes |
+ eval per_ip_bytes=sum_bytes/ip_count | head 20
+`,
+ outputType: 'QUERY',
+ execution_time: '0.006 ms',
+ },
+ ],
+ input: {
+ inputText: `%ppl
+ source=opensearch_dashboards_sample_data_logs | fields host, clientip, response,
+ bytes | where response='503' or response='404' |
+ stats count() as ip_count, sum(bytes)
+ as sum_bytes by host, response |
+ rename response as resp_code |
+ sort - ip_count, + sum_bytes |
+ eval per_ip_bytes=sum_bytes/ip_count | head 20
+`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `Wait, what's meant by an evaluation. Can we really perform an evaluation?`,
+ outputType: 'MARKDOWN',
+ execution_time: '0.007 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+Wait, what's meant by an evaluation. Can we really perform an evaluation?`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `
+ source=opensearch_dashboards_sample_data_logs | fields host, clientip, response,
+ bytes | where response='503' or response='404' |
+ stats count() as ip_count, sum(bytes)
+ as sum_bytes by host, response |
+ rename response as resp_code |
+ sort - ip_count, + sum_bytes |
+ eval per_ip_bytes=sum_bytes/ip_count,
+ double_per_ip_bytes = 2 * per_ip_bytes | head 20
+`,
+ outputType: 'QUERY',
+ execution_time: '0.010 ms',
+ },
+ ],
+ input: {
+ inputText: `%ppl
+ source=opensearch_dashboards_sample_data_logs | fields host, clientip, response,
+ bytes | where response='503' or response='404' |
+ stats count() as ip_count, sum(bytes)
+ as sum_bytes by host, response |
+ rename response as resp_code |
+ sort - ip_count, + sum_bytes |
+ eval per_ip_bytes=sum_bytes/ip_count,
+ double_per_ip_bytes = 2 * per_ip_bytes | head 20
+`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ ],
+ };
+};
+
+const getSQLNotebook = (dateString: string) => {
+ return {
+ name: '[Flights] OpenSearch SQL Quick Start Guide',
+ dateCreated: dateString,
+ dateModified: dateString,
+ backend: 'Default',
+ paragraphs: [
+ {
+ output: [
+ {
+ result:
+ `OpenSearch SQL lets you write queries in SQL rather than the [OpenSearch query domain-specific language (DSL)](https://opensearch.org/docs/opensearch/query-dsl/full-text/). If you’re already familiar with SQL and don’t want to learn the query DSL, this feature is a great option.
+
+For more information, please refer to the [documentation](https://opensearch.org/docs/search-plugins/sql/index/).`,
+ outputType: 'MARKDOWN',
+ execution_time: '0.013 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+OpenSearch SQL lets you write queries in SQL rather than the [OpenSearch query domain-specific language (DSL)](https://opensearch.org/docs/opensearch/query-dsl/full-text/). If you’re already familiar with SQL and don’t want to learn the query DSL, this feature is a great option.
+
+For more information, please refer to the [documentation](https://opensearch.org/docs/search-plugins/sql/index/).`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result:
+ 'This notebook shows you how to use SQL with the [OpenSearch Dashboards sample flight data](/app/home#/tutorial_directory).',
+ outputType: 'MARKDOWN',
+ execution_time: '0.010 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+This notebook shows you how to use SQL with the [OpenSearch Dashboards sample flight data](/app/home#/tutorial_directory).`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result:
+ 'To use SQL, add a code paragraph, type %sql on the first line, and then add SQL queries on the next line.',
+ outputType: 'MARKDOWN',
+ execution_time: '0.007 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+To use SQL, add a code paragraph, type %sql on the first line, and then add SQL queries on the next line.`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: 'Select * from opensearch_dashboards_sample_data_flights limit 20;',
+ outputType: 'QUERY',
+ execution_time: '0.007 ms',
+ },
+ ],
+ input: {
+ inputText: `%sql
+Select * from opensearch_dashboards_sample_data_flights limit 20;`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result:
+ 'You can specify fields in the `SELECT` clause and use the `WHERE` clause to filter results. The following query finds flights heading to countries that start with \'A\' that are more than 5000 miles away.',
+ outputType: 'MARKDOWN',
+ execution_time: '0.006 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+You can specify fields in the \`SELECT\` clause and use the \`WHERE\` clause to filter results. The following query finds flights heading to countries that start with 'A' that are more than 5000 miles away.`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `SELECT FlightNum,OriginCountry,OriginCityName,DestCountry,DestCityName,DistanceMiles FROM opensearch_dashboards_sample_data_flights WHERE DistanceMiles > 5000 AND DestCountry LIKE 'A%' LIMIT 20;`,
+ outputType: 'QUERY',
+ execution_time: '0.006 ms',
+ },
+ ],
+ input: {
+ inputText: `%sql
+SELECT FlightNum,OriginCountry,OriginCityName,DestCountry,DestCityName,DistanceMiles FROM opensearch_dashboards_sample_data_flights WHERE DistanceMiles > 5000 AND DestCountry LIKE 'A%' LIMIT 20;`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result:
+ 'OpenSearch SQL also supports subqueries:',
+ outputType: 'MARKDOWN',
+ execution_time: '0.007 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+OpenSearch SQL also supports subqueries:`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `SELECT opensearch_dashboards_sample_data_flights.FlightNum,opensearch_dashboards_sample_data_flights.OriginCountry,opensearch_dashboards_sample_data_flights.OriginCityName,opensearch_dashboards_sample_data_flights.DestCountry,opensearch_dashboards_sample_data_flights.DestCityName,opensearch_dashboards_sample_data_flights.DistanceMiles FROM opensearch_dashboards_sample_data_flights WHERE FlightNum IN (SELECT FlightNum FROM opensearch_dashboards_sample_data_flights WHERE DistanceMiles > 5000 AND DestCountry = 'AU') LIMIT 20;`,
+ outputType: 'QUERY',
+ execution_time: '0.009 ms',
+ },
+ ],
+ input: {
+ inputText: `%sql
+SELECT opensearch_dashboards_sample_data_flights.FlightNum,opensearch_dashboards_sample_data_flights.OriginCountry,opensearch_dashboards_sample_data_flights.OriginCityName,opensearch_dashboards_sample_data_flights.DestCountry,opensearch_dashboards_sample_data_flights.DestCityName,opensearch_dashboards_sample_data_flights.DistanceMiles FROM opensearch_dashboards_sample_data_flights WHERE FlightNum IN (SELECT FlightNum FROM opensearch_dashboards_sample_data_flights WHERE DistanceMiles > 5000 AND DestCountry = 'AU') LIMIT 20;`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result:
+ 'OpenSearch SQL supports inner joins, cross joins, and left outer joins. The following query joins the flights index with itself to find flights departed from countries that are both origins and destinations.',
+ outputType: 'MARKDOWN',
+ execution_time: '0.007 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+OpenSearch SQL supports inner joins, cross joins, and left outer joins. The following query joins the flights index with itself to find flights departed from countries that are both origins and destinations.`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `
+SELECT a.FlightNum,a.OriginCountry,a.OriginCityName,a.DestCountry,a.DestCityName,a.DistanceMiles FROM opensearch_dashboards_sample_data_flights a JOIN opensearch_dashboards_sample_data_flights b on a.OriginCountry = b.DestCountry LIMIT 20`,
+ outputType: 'QUERY',
+ execution_time: '0.006 ms',
+ },
+ ],
+ input: {
+ inputText: `%sql
+SELECT a.FlightNum,a.OriginCountry,a.OriginCityName,a.DestCountry,a.DestCityName,a.DistanceMiles FROM opensearch_dashboards_sample_data_flights a JOIN opensearch_dashboards_sample_data_flights b on a.OriginCountry = b.DestCountry LIMIT 20`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result:
+ 'For aggregations, use the `GROUP BY` clause. The following query finds the countries with more than 500 flights departed.',
+ outputType: 'MARKDOWN',
+ execution_time: '0.006 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+For aggregations, use the \`GROUP BY\` clause. The following query finds the countries with more than 500 flights departed.`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `SELECT OriginCountry,COUNT(1) FROM opensearch_dashboards_sample_data_flights GROUP BY OriginCountry HAVING COUNT(1) > 500 LIMIT 20;`,
+ outputType: 'QUERY',
+ execution_time: '0.006 ms',
+ },
+ ],
+ input: {
+ inputText: `%sql
+SELECT OriginCountry,COUNT(1) FROM opensearch_dashboards_sample_data_flights GROUP BY OriginCountry HAVING COUNT(1) > 500 LIMIT 20;`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: 'OpenSearch SQL supports expressions.',
+ outputType: 'MARKDOWN',
+ execution_time: '0.006 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+OpenSearch SQL supports expressions.`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `SELECT abs(-1.234), abs(-1 * abs(-5)), dayofmonth(DATE '2021-07-07');`,
+ outputType: 'QUERY',
+ execution_time: '0.005 ms',
+ },
+ ],
+ input: {
+ inputText: `%sql
+SELECT abs(-1.234), abs(-1 * abs(-5)), dayofmonth(DATE '2021-07-07');`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ ],
+ };
+};
+
+const getPPLNotebook = (dateString: string) => {
+ return {
+ name: '[Logs] OpenSearch Piped Processing Language (PPL) Quick Start Guide',
+ dateCreated: dateString,
+ dateModified: dateString,
+ backend: 'Default',
+ paragraphs: [
+ {
+ output: [
+ {
+ result: `Query DSL is powerful and fast, but it has a steep learning curve because it doesn’t have a human-readable interface. It's also difficult to create ad hoc queries and explore your data. SQL lets you extract and analyze data in a declarative manner.
+
+OpenSearch makes its search and query engine robust by introducing Piped Processing Language (PPL).
+
+PPL enables developers, DevOps engineers, support engineers, site reliability engineers (SREs), and IT managers to effectively discover and explore log data stored in OpenSearch.
+
+With PPL, you can extract insights from your data with a sequence of commands delimited by pipes (|). PPL supports a comprehensive set of commands including search, where, fields, rename, dedup, sort, eval, head, top, and rare. PPL also supports functions, operators and expressions.
+
+Even if you're new to OpenSearch and are only familiar with the pipe (|) syntax, you can still be productive from day one.`,
+ outputType: 'MARKDOWN',
+ execution_time: '0.009 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+Query DSL is powerful and fast, but it has a steep learning curve because it doesn’t have a human-readable interface. It's also difficult to create ad hoc queries and explore your data. SQL lets you extract and analyze data in a declarative manner.
+
+OpenSearch makes its search and query engine robust by introducing Piped Processing Language (PPL).
+
+PPL enables developers, DevOps engineers, support engineers, site reliability engineers (SREs), and IT managers to effectively discover and explore log data stored in OpenSearch.
+
+With PPL, you can extract insights from your data with a sequence of commands delimited by pipes (|). PPL supports a comprehensive set of commands including search, where, fields, rename, dedup, sort, eval, head, top, and rare. PPL also supports functions, operators and expressions.
+
+Even if you're new to OpenSearch and are only familiar with the pipe (|) syntax, you can still be productive from day one.`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `Piped Processing Language (PPL) is a query language that lets you use pipe (|) syntax to explore, discover, and query data stored in OpenSearch.
+
+For more information, refer to the [documentation](https://opensearch.org/docs/search-plugins/ppl/index/).`,
+ outputType: 'MARKDOWN',
+ execution_time: '0.009 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+Piped Processing Language (PPL) is a query language that lets you use pipe (|) syntax to explore, discover, and query data stored in OpenSearch.
+
+For more information, refer to the [documentation](https://opensearch.org/docs/search-plugins/ppl/index/).`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result:
+ 'In this notebook, we will demonstrate some simple PPL queries with the [OpenSearch Dashboards sample web logs](/app/home#/tutorial_directory). ',
+ outputType: 'MARKDOWN',
+ execution_time: '0.006 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+In this notebook, we will demonstrate some simple PPL queries with the [OpenSearch Dashboards sample web logs](/app/home#/tutorial_directory). `,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result:
+ 'To use PPL, add a code paragraph, type `%ppl` on the first line, and add your PPL query on the next line. PPL uses `source` to specify indices and `head` to limit results.',
+ outputType: 'MARKDOWN',
+ execution_time: '0.006 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+To use PPL, add a code paragraph, type \`%ppl\` on the first line, and add your PPL query on the next line. PPL uses \`source\` to specify indices and \`head\` to limit results.`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `
+source=opensearch_dashboards_sample_data_logs | head 20`,
+ outputType: 'QUERY',
+ execution_time: '0.026 ms',
+ },
+ ],
+ input: {
+ inputText: `%ppl
+source=opensearch_dashboards_sample_data_logs | head 20`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result:
+ 'To specify fields to include and filter results, use the `field` and `where` commands. The next query returns hosts with failed responses.',
+ outputType: 'MARKDOWN',
+ execution_time: '0.007 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+To specify fields to include and filter results, use the \`field\` and \`where\` commands. The next query returns hosts with failed responses.`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `
+source=opensearch_dashboards_sample_data_logs | fields host, clientip, response, bytes | where response='503' or response='404'`,
+ outputType: 'QUERY',
+ execution_time: '0.006 ms',
+ },
+ ],
+ input: {
+ inputText: `%ppl
+source=opensearch_dashboards_sample_data_logs | fields host, clientip, response, bytes | where response='503' or response='404'`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: 'To see most common hosts from the previous result, use the `top` command.',
+ outputType: 'MARKDOWN',
+ execution_time: '0.006 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+To see most common hosts from the previous result, use the \`top\` command.`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `
+source=opensearch_dashboards_sample_data_logs | where response='503' or response='404' | top host`,
+ outputType: 'QUERY',
+ execution_time: '0.008 ms',
+ },
+ ],
+ input: {
+ inputText: `%ppl
+source=opensearch_dashboards_sample_data_logs | where response='503' or response='404' | top host`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: 'To perform aggregations on search results, use the `stats` command.',
+ outputType: 'MARKDOWN',
+ execution_time: '0.006 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+To perform aggregations on search results, use the \`stats\` command.`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `
+source=opensearch_dashboards_sample_data_logs | where response='503' or response='404' | stats count(1) by host`,
+ outputType: 'QUERY',
+ execution_time: '0.011 ms',
+ },
+ ],
+ input: {
+ inputText: `%ppl
+source=opensearch_dashboards_sample_data_logs | where response='503' or response='404' | stats count(1) by host`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ {
+ output: [
+ {
+ result: `For more information, refer to the [documentation](https://opensearch.org/docs/search-plugins/ppl/index/).
+
+To see how to perform sample root cause event analysis using PPL and visualizations, see the "\[Logs\] Sample Root Cause Event Analysis" notebook.`,
+ outputType: 'MARKDOWN',
+ execution_time: '0.009 ms',
+ },
+ ],
+ input: {
+ inputText: `%md
+For more information, refer to the [documentation](https://opensearch.org/docs/search-plugins/ppl/index/).
+
+To see how to perform sample root cause event analysis using PPL and visualizations, see the "\[Logs\] Sample Root Cause Event Analysis" notebook.`,
+ inputType: 'MARKDOWN',
+ },
+ dateCreated: dateString,
+ dateModified: dateString,
+ id: 'paragraph_' + uuid(),
+ },
+ ],
+ };
+};
+
+export const getSampleNotebooks = (visIds: string[]) => {
+ const dateString = new Date().toISOString();
+ return [
+ {
+ notebook: getDemoNotebook(dateString, visIds[2]),
+ dateModified: dateString,
+ dateCreated: dateString,
+ },
+ {
+ notebook: getSQLNotebook(dateString),
+ dateModified: dateString,
+ dateCreated: dateString,
+ },
+ {
+ notebook: getPPLNotebook(dateString),
+ dateModified: dateString,
+ dateCreated: dateString,
+ },
+ {
+ notebook: getRootCauseNotebook(dateString, visIds),
+ dateModified: dateString,
+ dateCreated: dateString,
+ },
+ ];
+};
diff --git a/server/common/helpers/notebooks/wreck_requests.ts b/server/common/helpers/notebooks/wreck_requests.ts
new file mode 100644
index 0000000000..54d39966b9
--- /dev/null
+++ b/server/common/helpers/notebooks/wreck_requests.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import Wreck from '@hapi/wreck';
+import { optionsType } from "../../../../common/types/notebooks";
+
+export const requestor = async function (
+ requestType: string,
+ url: string,
+ wreckOptions: optionsType
+) {
+ const promise = Wreck.request(requestType, url, wreckOptions);
+ const res = await promise;
+ const body = await Wreck.read(res, wreckOptions);
+ return body;
+};
diff --git a/server/common/types/index.ts b/server/common/types/index.ts
new file mode 100644
index 0000000000..3b332df93a
--- /dev/null
+++ b/server/common/types/index.ts
@@ -0,0 +1,23 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export interface ISchema {
+ name: string,
+ type: string
+}
+
+export interface IPPLVisualizationDataSource {
+ data: any;
+ metadata: any;
+ jsonData?: Array;
+ size: Number;
+ status: Number;
+}
+
+export interface IPPLEventsDataSource {
+ schema: Array;
+ datarows: Array;
+ jsonData?: Array;
+}
\ No newline at end of file
diff --git a/server/index.ts b/server/index.ts
new file mode 100644
index 0000000000..fb4e47bd3a
--- /dev/null
+++ b/server/index.ts
@@ -0,0 +1,13 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { PluginInitializerContext } from '../../../src/core/server';
+import { ObservabilityPlugin } from './plugin';
+
+export function plugin(initializerContext: PluginInitializerContext) {
+ return new ObservabilityPlugin(initializerContext);
+}
+
+export { ObservabilityPluginSetup, ObservabilityPluginStart } from './types';
diff --git a/server/plugin.ts b/server/plugin.ts
new file mode 100644
index 0000000000..69738f73e8
--- /dev/null
+++ b/server/plugin.ts
@@ -0,0 +1,60 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ CoreSetup,
+ CoreStart,
+ ILegacyClusterClient,
+ Logger,
+ Plugin,
+ PluginInitializerContext,
+} from '../../../src/core/server';
+import { OpenSearchObservabilityPlugin } from './adaptors/opensearch_observability_plugin';
+import { PPLPlugin } from './adaptors/ppl_plugin';
+import { setupRoutes } from './routes/index';
+import { ObservabilityPluginSetup, ObservabilityPluginStart } from './types';
+
+export class ObservabilityPlugin
+ implements Plugin {
+ private readonly logger: Logger;
+
+ constructor(initializerContext: PluginInitializerContext) {
+ this.logger = initializerContext.logger.get();
+ }
+
+ public setup(core: CoreSetup) {
+ this.logger.debug('Observability: Setup');
+ const router = core.http.createRouter();
+ const openSearchObservabilityClient: ILegacyClusterClient = core.opensearch.legacy.createClient(
+ 'opensearch_observability',
+ {
+ plugins: [
+ PPLPlugin,
+ OpenSearchObservabilityPlugin,
+ ],
+ }
+ );
+
+ // @ts-ignore
+ core.http.registerRouteHandlerContext('observability_plugin', (context, request) => {
+ return {
+ logger: this.logger,
+ observabilityClient: openSearchObservabilityClient,
+ };
+ });
+
+ // Register server side APIs
+ setupRoutes({ router, client: openSearchObservabilityClient });
+
+ return {};
+ }
+
+ public start(core: CoreStart) {
+ this.logger.debug('Observability: Started');
+ return {};
+ }
+
+ public stop() {}
+}
diff --git a/server/routes/application_analytics/app_analytics_router.ts b/server/routes/application_analytics/app_analytics_router.ts
new file mode 100644
index 0000000000..930e0d5f1c
--- /dev/null
+++ b/server/routes/application_analytics/app_analytics_router.ts
@@ -0,0 +1,255 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* eslint-disable no-console */
+
+import { schema } from '@osd/config-schema';
+import {
+ IRouter,
+ IOpenSearchDashboardsResponse,
+ ResponseError,
+ ILegacyScopedClusterClient,
+} from '../../../../../src/core/server';
+import { APP_ANALYTICS_API_PREFIX as API_PREFIX } from '../../../common/constants/application_analytics';
+import { ApplicationType } from '../../../common/types/application_analytics';
+import { AppAnalyticsAdaptor } from '../../../server/adaptors/application_analytics/app_analytics_adaptor';
+
+export function registerAppAnalyticsRouter(router: IRouter) {
+ const appAnalyticsBackend = new AppAnalyticsAdaptor();
+
+ // Fetches all existing applications
+ router.get(
+ {
+ path: `${API_PREFIX}/`,
+ validate: {},
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise> => {
+ const opensearchClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+ request
+ );
+ let applicationsData: ApplicationType[] = [];
+ try {
+ applicationsData = await appAnalyticsBackend.fetchApps(opensearchClient);
+ return response.ok({
+ body: {
+ data: applicationsData,
+ },
+ });
+ } catch (err: any) {
+ console.error('Error occurred while fetching applications', err);
+ return response.custom({
+ statusCode: err.statusCode || 500,
+ body: err.message,
+ });
+ }
+ }
+ );
+
+ // Fetch application by id
+ router.get(
+ {
+ path: `${API_PREFIX}/{appId}`,
+ validate: {
+ params: schema.object({
+ appId: schema.string(),
+ }),
+ },
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise> => {
+ const opensearchClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+ request
+ );
+ try {
+ const appObject = await appAnalyticsBackend.fetchAppById(
+ opensearchClient,
+ request.params.appId
+ );
+ return response.ok({
+ body: appObject,
+ });
+ } catch (err: any) {
+ console.error('Error occurred while fetching application', err);
+ return response.custom({
+ statusCode: err.statusCode || 500,
+ body: err.message,
+ });
+ }
+ }
+ );
+
+ // Create a new application
+ router.post(
+ {
+ path: `${API_PREFIX}/`,
+ validate: {
+ body: schema.object({
+ name: schema.string(),
+ description: schema.maybe(schema.string()),
+ baseQuery: schema.string(),
+ servicesEntities: schema.arrayOf(schema.string()),
+ traceGroups: schema.arrayOf(schema.string()),
+ availabilityVisId: schema.maybe(schema.string()),
+ }),
+ },
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise> => {
+ const opensearchClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+ request
+ );
+
+ try {
+ const newAppId = await appAnalyticsBackend.createNewApp(opensearchClient, request.body);
+ return response.ok({
+ body: {
+ message: 'Application Created',
+ newAppId,
+ },
+ });
+ } catch (err: any) {
+ console.error('Error occurred while creating a new application', err);
+ return response.custom({
+ statusCode: err.statusCode || 500,
+ body: err.message,
+ });
+ }
+ }
+ );
+
+ // Renames an existing application
+ router.put(
+ {
+ path: `${API_PREFIX}/rename`,
+ validate: {
+ body: schema.object({
+ appId: schema.string(),
+ name: schema.string(),
+ }),
+ },
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise> => {
+ const opensearchClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+ request
+ );
+
+ try {
+ await appAnalyticsBackend.renameApp(
+ opensearchClient,
+ request.body.appId,
+ request.body.name
+ );
+ return response.ok({
+ body: {
+ message: 'Application Renamed',
+ },
+ });
+ } catch (err: any) {
+ console.error('Error occurred while renaming an existing application', err);
+ return response.custom({
+ statusCode: err.statusCode || 500,
+ body: err.message,
+ });
+ }
+ }
+ );
+
+ // Updates an existing application
+ router.put(
+ {
+ path: `${API_PREFIX}/`,
+ validate: {
+ body: schema.object({
+ appId: schema.string(),
+ updateBody: schema.object({
+ name: schema.maybe(schema.string()),
+ description: schema.maybe(schema.string()),
+ servicesEntities: schema.maybe(schema.arrayOf(schema.string())),
+ traceGroups: schema.maybe(schema.arrayOf(schema.string())),
+ panelId: schema.maybe(schema.string()),
+ availabilityVisId: schema.maybe(schema.string()),
+ }),
+ }),
+ },
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise> => {
+ const opensearchClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+ request
+ );
+
+ try {
+ const updatedAppId = await appAnalyticsBackend.updateApp(
+ opensearchClient,
+ request.body.appId,
+ request.body.updateBody
+ );
+ return response.ok({
+ body: {
+ message: 'Application Updated',
+ updatedAppId,
+ },
+ });
+ } catch (err: any) {
+ console.error('Error occurred while updating an existing application', err);
+ return response.custom({
+ statusCode: err.statusCode || 500,
+ body: err.message,
+ });
+ }
+ }
+ );
+
+ // Delete applications
+ router.delete(
+ {
+ path: `${API_PREFIX}/{appList}`,
+ validate: {
+ params: schema.object({
+ appList: schema.string(),
+ }),
+ },
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise> => {
+ const opensearchClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+ request
+ );
+ try {
+ const delResponse = await appAnalyticsBackend.deleteApp(
+ opensearchClient,
+ request.params.appList
+ );
+ return response.ok({
+ body: delResponse,
+ });
+ } catch (err: any) {
+ return response.custom({
+ statusCode: err.statusCode || 500,
+ body: err.message,
+ });
+ }
+ }
+ );
+}
diff --git a/server/routes/custom_panels/panels_router.ts b/server/routes/custom_panels/panels_router.ts
new file mode 100644
index 0000000000..27b452f756
--- /dev/null
+++ b/server/routes/custom_panels/panels_router.ts
@@ -0,0 +1,377 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { schema } from '@osd/config-schema';
+import { CustomPanelsAdaptor } from '../../adaptors/custom_panels/custom_panel_adaptor';
+import {
+ IRouter,
+ IOpenSearchDashboardsResponse,
+ ResponseError,
+ ILegacyScopedClusterClient,
+} from '../../../../../src/core/server';
+import { CUSTOM_PANELS_API_PREFIX as API_PREFIX } from '../../../common/constants/custom_panels';
+
+export function PanelsRouter(router: IRouter) {
+ const customPanelBackend = new CustomPanelsAdaptor();
+ // Fetch all the custom panels available
+ router.get(
+ {
+ path: `${API_PREFIX}/panels`,
+ validate: {},
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise> => {
+ const opensearchNotebooksClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+ request
+ );
+
+ try {
+ const panelsList = await customPanelBackend.viewPanelList(opensearchNotebooksClient);
+ return response.ok({
+ body: {
+ panels: panelsList,
+ },
+ });
+ } catch (error: any) {
+ console.error('Issue in fetching panel list:', error);
+ return response.custom({
+ statusCode: error.statusCode || 500,
+ body: error.message,
+ });
+ }
+ }
+ );
+
+ // Fetch the required panel by id
+ router.get(
+ {
+ path: `${API_PREFIX}/panels/{panelId}`,
+ validate: {
+ params: schema.object({
+ panelId: schema.string(),
+ }),
+ },
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise> => {
+ const opensearchNotebooksClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+ request
+ );
+
+ try {
+ const panelObject = await customPanelBackend.getPanel(
+ opensearchNotebooksClient,
+ request.params.panelId
+ );
+ return response.ok({
+ body: panelObject,
+ });
+ } catch (error: any) {
+ console.error('Issue in fetching panel:', error);
+ return response.custom({
+ statusCode: error.statusCode || 500,
+ body: error.message,
+ });
+ }
+ }
+ );
+
+ // Create a new panel
+ router.post(
+ {
+ path: `${API_PREFIX}/panels`,
+ validate: {
+ body: schema.object({
+ panelName: schema.string(),
+ applicationId: schema.maybe(schema.string()),
+ }),
+ },
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise> => {
+ const opensearchNotebooksClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+ request
+ );
+ try {
+ const newPanelId = await customPanelBackend.createNewPanel(
+ opensearchNotebooksClient,
+ request.body.panelName,
+ request.body.applicationId || ''
+ );
+ return response.ok({
+ body: {
+ message: 'Panel Created',
+ newPanelId,
+ },
+ });
+ } catch (error: any) {
+ console.error('Issue in creating new panel', error);
+ return response.custom({
+ statusCode: error.statusCode || 500,
+ body: error.message,
+ });
+ }
+ }
+ );
+
+ // rename an existing panel
+ router.post(
+ {
+ path: `${API_PREFIX}/panels/rename`,
+ validate: {
+ body: schema.object({
+ panelId: schema.string(),
+ panelName: schema.string(),
+ }),
+ },
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise> => {
+ const opensearchNotebooksClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+ request
+ );
+
+ try {
+ const responseBody = await customPanelBackend.renamePanel(
+ opensearchNotebooksClient,
+ request.body.panelId,
+ request.body.panelName
+ );
+ return response.ok({
+ body: {
+ message: 'Panel Renamed',
+ },
+ });
+ } catch (error: any) {
+ console.error('Issue in renaming panel', error);
+ return response.custom({
+ statusCode: error.statusCode || 500,
+ body: error.message,
+ });
+ }
+ }
+ );
+
+ // clones an existing panel
+ // returns new panel Id
+ router.post(
+ {
+ path: `${API_PREFIX}/panels/clone`,
+ validate: {
+ body: schema.object({
+ panelId: schema.string(),
+ panelName: schema.string(),
+ }),
+ },
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise> => {
+ const opensearchNotebooksClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+ request
+ );
+
+ try {
+ const cloneResponse = await customPanelBackend.clonePanel(
+ opensearchNotebooksClient,
+ request.body.panelId,
+ request.body.panelName
+ );
+ return response.ok({
+ body: {
+ message: 'Panel Cloned',
+ clonePanelId: cloneResponse.clonePanelId,
+ dateCreated: cloneResponse.dateCreated,
+ dateModified: cloneResponse.dateModified,
+ },
+ });
+ } catch (error: any) {
+ console.error('Issue in cloning panel', error);
+ return response.custom({
+ statusCode: error.statusCode || 500,
+ body: error.message,
+ });
+ }
+ }
+ );
+
+ // delete an existing panel
+ router.delete(
+ {
+ path: `${API_PREFIX}/panels/{panelId}`,
+ validate: {
+ params: schema.object({
+ panelId: schema.string(),
+ }),
+ },
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise> => {
+ const opensearchNotebooksClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+ request
+ );
+
+ try {
+ const deleteResponse = await customPanelBackend.deletePanel(
+ opensearchNotebooksClient,
+ request.params.panelId
+ );
+ return response.ok({
+ body: {
+ message: 'Panel Deleted',
+ },
+ });
+ } catch (error: any) {
+ console.error('Issue in deleting panel', error);
+ return response.custom({
+ statusCode: error.statusCode || 500,
+ body: error.message,
+ });
+ }
+ }
+ );
+
+ // delete an existing panel(s)
+ router.delete(
+ {
+ path: `${API_PREFIX}/panelList/{panelIdList}`,
+ validate: {
+ params: schema.object({
+ panelIdList: schema.string(),
+ }),
+ },
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise> => {
+ const opensearchNotebooksClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+ request
+ );
+
+ try {
+ const deleteResponse = await customPanelBackend.deletePanelList(
+ opensearchNotebooksClient,
+ request.params.panelIdList
+ );
+ return response.ok({
+ body: {
+ message: 'Panel Deleted',
+ },
+ });
+ } catch (error: any) {
+ console.error('Issue in deleting panel', error);
+ return response.custom({
+ statusCode: error.statusCode || 500,
+ body: error.message,
+ });
+ }
+ }
+ );
+
+ // replaces the ppl query filter in panel
+ router.post(
+ {
+ path: `${API_PREFIX}/panels/filter`,
+ validate: {
+ body: schema.object({
+ panelId: schema.string(),
+ query: schema.string(),
+ language: schema.string(),
+ to: schema.string(),
+ from: schema.string(),
+ }),
+ },
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise> => {
+ const opensearchNotebooksClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+ request
+ );
+
+ try {
+ const panelFilterResponse = await customPanelBackend.addPanelFilter(
+ opensearchNotebooksClient,
+ request.body.panelId,
+ request.body.query,
+ request.body.language,
+ request.body.to,
+ request.body.from
+ );
+ return response.ok({
+ body: {
+ message: 'Panel PPL Filter Changed',
+ },
+ });
+ } catch (error: any) {
+ console.error('Issue in adding query filter', error);
+ return response.custom({
+ statusCode: error.statusCode || 500,
+ body: error.message,
+ });
+ }
+ }
+ );
+
+ // Add Sample Panels
+ router.post(
+ {
+ path: `${API_PREFIX}/panels/addSamplePanels`,
+ validate: {
+ body: schema.object({
+ savedVisualizationIds: schema.arrayOf(schema.string()),
+ }),
+ },
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise> => {
+ const opensearchNotebooksClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+ request
+ );
+
+ try {
+ const panelsData = await customPanelBackend.addSamplePanels(
+ opensearchNotebooksClient,
+ request.body.savedVisualizationIds
+ );
+ return response.ok({
+ body: {
+ demoPanelsData: panelsData,
+ },
+ });
+ } catch (error: any) {
+ console.error('Issue in fetching panel list:', error);
+ return response.custom({
+ statusCode: error.statusCode || 500,
+ body: error.message,
+ });
+ }
+ }
+ );
+}
diff --git a/server/routes/custom_panels/visualizations_router.ts b/server/routes/custom_panels/visualizations_router.ts
new file mode 100644
index 0000000000..3848b55c33
--- /dev/null
+++ b/server/routes/custom_panels/visualizations_router.ts
@@ -0,0 +1,225 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { schema } from '@osd/config-schema';
+import { CustomPanelsAdaptor } from '../../adaptors/custom_panels/custom_panel_adaptor';
+import {
+ IRouter,
+ IOpenSearchDashboardsResponse,
+ ResponseError,
+ ILegacyScopedClusterClient,
+} from '../../../../../src/core/server';
+import { CUSTOM_PANELS_API_PREFIX as API_PREFIX } from '../../../common/constants/custom_panels';
+
+export function VisualizationsRouter(router: IRouter) {
+ // Fetch all the savedVisualzations
+ const customPanelBackend = new CustomPanelsAdaptor();
+ router.get(
+ {
+ path: `${API_PREFIX}/visualizations`,
+ validate: {},
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise> => {
+ const opensearchNotebooksClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+ request
+ );
+ try {
+ const visualizationList = await customPanelBackend.getAllSavedVisualizations(
+ opensearchNotebooksClient
+ );
+ return response.ok({
+ body: {
+ visualizations: visualizationList,
+ },
+ });
+ } catch (error) {
+ console.error('Issue in fetching saved visualizations:', error);
+ return response.custom({
+ statusCode: error.statusCode || 500,
+ body: error.message,
+ });
+ }
+ }
+ );
+
+ // get all saved visualizations by Id
+ router.get(
+ {
+ path: `${API_PREFIX}/visualizations/{savedVisualizationId}`,
+ validate: {
+ params: schema.object({
+ savedVisualizationId: schema.string(),
+ }),
+ },
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise> => {
+ const opensearchNotebooksClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+ request
+ );
+ try {
+ const savedVisualization = await customPanelBackend.getSavedVisualizationById(
+ opensearchNotebooksClient,
+ request.params.savedVisualizationId
+ );
+ return response.ok({
+ body: {
+ visualization: savedVisualization,
+ },
+ });
+ } catch (error) {
+ console.error('Issue in fetching saved visualizations by ids:', error);
+ return response.custom({
+ statusCode: error.statusCode || 500,
+ body: error.message,
+ });
+ }
+ }
+ );
+
+ // Add a new visualization to the panel
+ router.post(
+ {
+ path: `${API_PREFIX}/visualizations`,
+ validate: {
+ body: schema.object({
+ panelId: schema.string(),
+ savedVisualizationId: schema.string(),
+ }),
+ },
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise> => {
+ const opensearchNotebooksClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+ request
+ );
+
+ try {
+ const newVisualizations = await customPanelBackend.addVisualization(
+ opensearchNotebooksClient,
+ request.body.panelId,
+ request.body.savedVisualizationId
+ );
+ return response.ok({
+ body: {
+ message: 'Visualization Added',
+ visualizations: newVisualizations,
+ },
+ });
+ } catch (error) {
+ console.error('Issue in adding visualization:', error);
+ return response.custom({
+ statusCode: error.statusCode || 500,
+ body: error.message,
+ });
+ }
+ }
+ );
+
+ // Replace an existing visualization
+ router.post(
+ {
+ path: `${API_PREFIX}/visualizations/replace`,
+ validate: {
+ body: schema.object({
+ panelId: schema.string(),
+ savedVisualizationId: schema.string(),
+ oldVisualizationId: schema.string(),
+ }),
+ },
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise> => {
+ const opensearchNotebooksClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+ request
+ );
+
+ try {
+ const newVisualizations = await customPanelBackend.addVisualization(
+ opensearchNotebooksClient,
+ request.body.panelId,
+ request.body.savedVisualizationId,
+ request.body.oldVisualizationId
+ );
+ return response.ok({
+ body: {
+ message: 'Visualization Replaced',
+ visualizations: newVisualizations,
+ },
+ });
+ } catch (error) {
+ console.error('Issue in replacing visualization:', error);
+ return response.custom({
+ statusCode: error.statusCode || 500,
+ body: error.message,
+ });
+ }
+ }
+ );
+
+ // changes the position of the mentioned visualizations
+ // Also removes the visualizations not mentioned
+ router.put(
+ {
+ path: `${API_PREFIX}/visualizations/edit`,
+ validate: {
+ body: schema.object({
+ panelId: schema.string(),
+ visualizationParams: schema.arrayOf(
+ schema.object({
+ i: schema.string(),
+ x: schema.number(),
+ y: schema.number(),
+ w: schema.number(),
+ h: schema.number(),
+ })
+ ),
+ }),
+ },
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise> => {
+ const opensearchNotebooksClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+ request
+ );
+
+ try {
+ const newVisualizations = await customPanelBackend.editVisualization(
+ opensearchNotebooksClient,
+ request.body.panelId,
+ request.body.visualizationParams
+ );
+ return response.ok({
+ body: {
+ message: 'Visualizations Edited',
+ visualizations: newVisualizations,
+ },
+ });
+ } catch (error) {
+ console.error('Issue in Editing visualizations:', error);
+ return response.custom({
+ statusCode: error.statusCode || 500,
+ body: error.message,
+ });
+ }
+ }
+ );
+}
diff --git a/server/routes/dsl.ts b/server/routes/dsl.ts
new file mode 100644
index 0000000000..4caaca8763
--- /dev/null
+++ b/server/routes/dsl.ts
@@ -0,0 +1,100 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ IRouter,
+} from '../../../../src/core/server';
+import { schema } from '@osd/config-schema';
+import DSLFacet from '../services/facets/dsl_facet';
+import {
+ DSL_BASE,
+ DSL_SEARCH,
+ DSL_CAT,
+ DSL_MAPPING
+} from '../../common/constants/shared';
+import { RequestParams } from '@elastic/elasticsearch';
+
+export function registerDslRoute({
+ router,
+ facet,
+}: {
+ router: IRouter
+ facet: DSLFacet
+}) {
+ router.post({
+ path: `${DSL_BASE}${DSL_SEARCH}`,
+ validate: { body:schema.any() }
+ },
+ async (context, request, response) => {
+ const { index, size, ...rest } = request.body;
+ const params: RequestParams.Search = {
+ index: index,
+ size,
+ body: rest,
+ };
+ try {
+ const resp = await context.core.opensearch.legacy.client.callAsCurrentUser(
+ 'search',
+ params
+ );
+ return response.ok({
+ body: resp,
+ });
+ } catch (error) {
+ if (error.statusCode !== 404) console.error(error);
+ return response.custom({
+ statusCode: error.statusCode || 500,
+ body: error.message,
+ });
+ }
+ })
+
+ router.get({
+ path: `${DSL_BASE}${DSL_CAT}`,
+ validate: { query: schema.object({
+ format: schema.string()
+ }) }
+ },
+ async (context, request, response) => {
+ try {
+ const resp = await context.core.opensearch.legacy.client.callAsCurrentUser(
+ 'cat.indices',
+ request.query
+ );
+ return response.ok({
+ body: resp
+ });
+ } catch (error) {
+ if (error.statusCode !== 404) console.error(error);
+ return response.custom({
+ statusCode: error.statusCode || 500,
+ body: error.message
+ })
+ }
+ })
+
+ router.get({
+ path: `${DSL_BASE}${DSL_MAPPING}`,
+ validate: { query: schema.any() }
+ },
+ async (context, request, response) => {
+ try {
+ const resp = await context.core.opensearch.legacy.client.callAsCurrentUser(
+ 'indices.getMapping',
+ { index: request.query.index }
+ );
+ return response.ok({
+ body: resp
+ });
+ } catch (error) {
+ if (error.statusCode !== 404) console.error(error);
+ return response.custom({
+ statusCode: error.statusCode || 500,
+ body: error.message,
+ })
+ }
+ }
+ )
+}
\ No newline at end of file
diff --git a/server/routes/event_analytics/event_analytics_router.ts b/server/routes/event_analytics/event_analytics_router.ts
new file mode 100644
index 0000000000..211aa2a60e
--- /dev/null
+++ b/server/routes/event_analytics/event_analytics_router.ts
@@ -0,0 +1,327 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { schema } from '@osd/config-schema';
+import {
+ IRouter,
+ IOpenSearchDashboardsResponse,
+ ResponseError,
+} from '../../../../../src/core/server';
+import {
+ OBSERVABILITY_BASE,
+ EVENT_ANALYTICS,
+ SAVED_OBJECTS,
+ SAVED_QUERY,
+ SAVED_VISUALIZATION,
+} from '../../../common/constants/shared';
+import SavedObjectFacet from '../../services/facets/saved_objects';
+
+export const registerEventAnalyticsRouter = ({
+ router,
+ savedObjectFacet,
+}: {
+ router: IRouter;
+ savedObjectFacet: SavedObjectFacet;
+}) => {
+ router.get(
+ {
+ path: `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}`,
+ validate: false,
+ },
+ async (context, req, res): Promise> => {
+ const savedRes = await savedObjectFacet.getSavedQuery(req);
+ const result: any = {
+ body: {
+ ...savedRes.data,
+ },
+ };
+
+ if (savedRes.success || savedRes?.data?.statusCode === 404) return res.ok(result);
+
+ result.statusCode = savedRes?.data?.statusCode || 500;
+ result.message = savedRes?.data || '';
+ return res.custom(result);
+ }
+ );
+
+ router.post(
+ {
+ path: `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}${SAVED_QUERY}`,
+ validate: {
+ body: schema.object({
+ object: schema.object({
+ query: schema.string(),
+ selected_date_range: schema.object({
+ start: schema.string(),
+ end: schema.string(),
+ text: schema.string(),
+ }),
+ selected_timestamp: schema.object({
+ name: schema.string(),
+ type: schema.string(),
+ }),
+ selected_fields: schema.object({
+ tokens: schema.arrayOf(schema.object({}, { unknowns: 'allow' })),
+ text: schema.string(),
+ }),
+ name: schema.string(),
+ description: schema.string(),
+ }),
+ }),
+ },
+ },
+ async (context, req, res): Promise> => {
+ const savedRes = await savedObjectFacet.createSavedQuery(req);
+ const result: any = {
+ body: {
+ ...savedRes.data,
+ },
+ };
+
+ if (savedRes.success) return res.ok(result);
+
+ result.statusCode = savedRes?.data?.statusCode || 500;
+ result.message = savedRes?.data || '';
+ return res.custom(result);
+ }
+ );
+
+ router.post(
+ {
+ path: `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}${SAVED_VISUALIZATION}`,
+ validate: {
+ body: schema.object({
+ object: schema.object({
+ query: schema.string(),
+ selected_date_range: schema.object({
+ start: schema.string(),
+ end: schema.string(),
+ text: schema.string(),
+ }),
+ selected_timestamp: schema.object({
+ name: schema.string(),
+ type: schema.string(),
+ }),
+ selected_fields: schema.object({
+ tokens: schema.arrayOf(schema.object({}, { unknowns: 'allow' })),
+ text: schema.string(),
+ }),
+ type: schema.string(),
+ name: schema.string(),
+ description: schema.string(),
+ application_id: schema.maybe(schema.string()),
+ user_configs: schema.string(),
+ }),
+ }),
+ },
+ },
+ async (context, req, res): Promise> => {
+ const savedRes = await savedObjectFacet.createSavedVisualization(req);
+ const result: any = {
+ body: {
+ ...savedRes.data,
+ },
+ };
+
+ if (savedRes.success) return res.ok(result);
+
+ result.statusCode = savedRes?.data?.statusCode || 500;
+ result.message = savedRes?.data || '';
+ return res.custom(result);
+ }
+ );
+
+ router.put(
+ {
+ path: `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}${SAVED_QUERY}`,
+ validate: {
+ body: schema.object({
+ object_id: schema.string(),
+ object: schema.object({
+ query: schema.string(),
+ selected_date_range: schema.object({
+ start: schema.string(),
+ end: schema.string(),
+ text: schema.string(),
+ }),
+ selected_timestamp: schema.object({
+ name: schema.string(),
+ type: schema.string(),
+ }),
+ selected_fields: schema.object({
+ tokens: schema.arrayOf(schema.object({}, { unknowns: 'allow' })),
+ text: schema.string(),
+ }),
+ name: schema.string(),
+ description: schema.string(),
+ }),
+ }),
+ },
+ },
+ async (context, req, res): Promise> => {
+ const savedRes = await savedObjectFacet.updateSavedQuery(req);
+ const result: any = {
+ body: {
+ ...savedRes.data,
+ },
+ };
+ if (savedRes.success) return res.ok(result);
+ result.statusCode = savedRes?.data?.statusCode || 500;
+ result.message = savedRes?.data || '';
+ return res.custom(result);
+ }
+ );
+
+ router.put(
+ {
+ path: `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}${SAVED_VISUALIZATION}`,
+ validate: {
+ body: schema.object({
+ object_id: schema.string(),
+ object: schema.object({
+ query: schema.string(),
+ selected_date_range: schema.object({
+ start: schema.string(),
+ end: schema.string(),
+ text: schema.string(),
+ }),
+ selected_timestamp: schema.object({
+ name: schema.string(),
+ type: schema.string(),
+ }),
+ selected_fields: schema.object({
+ tokens: schema.arrayOf(schema.object({}, { unknowns: 'allow' })),
+ text: schema.string(),
+ }),
+ type: schema.string(),
+ name: schema.string(),
+ description: schema.string(),
+ application_id: schema.maybe(schema.string()),
+ user_configs: schema.string(),
+ }),
+ }),
+ },
+ },
+ async (context, req, res): Promise> => {
+ const updateRes = await savedObjectFacet.updateSavedVisualization(req);
+ const result: any = {
+ body: {
+ ...updateRes.data,
+ },
+ };
+ if (updateRes.success) return res.ok(result);
+ result.statusCode = updateRes?.data?.statusCode || 500;
+ result.message = updateRes?.data || '';
+ return res.custom(result);
+ }
+ );
+
+ router.post(
+ {
+ path: `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}/timestamp`,
+ validate: {
+ body: schema.object({
+ name: schema.string(),
+ index: schema.string(),
+ type: schema.string(),
+ dsl_type: schema.string(),
+ }),
+ },
+ },
+ async (context, req, res): Promise> => {
+ const savedRes = await savedObjectFacet.createSavedTimestamp(req);
+ const result: any = {
+ body: {
+ ...savedRes.data,
+ },
+ };
+
+ if (savedRes.success) return res.ok(result);
+
+ result.statusCode = savedRes?.data?.statusCode || 500;
+ result.message = savedRes?.data || '';
+ return res.custom(result);
+ }
+ );
+
+ router.put(
+ {
+ path: `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}/timestamp`,
+ validate: {
+ body: schema.object({
+ objectId: schema.string(),
+ timestamp: schema.object({
+ name: schema.string(),
+ index: schema.string(),
+ type: schema.string(),
+ dsl_type: schema.string(),
+ }),
+ }),
+ },
+ },
+ async (context, req, res): Promise> => {
+ const savedRes = await savedObjectFacet.updateSavedTimestamp(req);
+ const result: any = {
+ body: {
+ ...savedRes.data,
+ },
+ };
+
+ if (savedRes.success) return res.ok(result);
+
+ result.statusCode = savedRes?.data?.statusCode || 500;
+ result.message = savedRes?.data || '';
+ return res.custom(result);
+ }
+ );
+
+ router.delete(
+ {
+ path: `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}/{objectIdList}`,
+ validate: {
+ params: schema.object({
+ objectIdList: schema.string(),
+ }),
+ },
+ },
+ async (context, req, res): Promise> => {
+ const deleteResponse = await savedObjectFacet.deleteSavedObject(req);
+ const result: any = {
+ body: {
+ ...deleteResponse.data,
+ },
+ };
+ if (deleteResponse.success) return res.ok(result);
+ result.statusCode = deleteResponse?.data?.statusCode || 500;
+ result.message = deleteResponse?.data || '';
+ return res.custom(result);
+ }
+ );
+
+ router.get(
+ {
+ path: `${OBSERVABILITY_BASE}${EVENT_ANALYTICS}${SAVED_OBJECTS}/addSampleSavedObjects/{sampleRequestor}`,
+ validate: {
+ params: schema.object({
+ sampleRequestor: schema.string(),
+ }),
+ },
+ },
+ async (context, req, res): Promise> => {
+ const savedRes = await savedObjectFacet.createSampleSavedObjects(req);
+ const result: any = {
+ body: {
+ ...savedRes.data,
+ },
+ };
+
+ if (savedRes.success) return res.ok(result);
+
+ result.statusCode = savedRes?.data?.statusCode || 500;
+ result.message = savedRes?.data || '';
+ return res.custom(result);
+ }
+ );
+};
diff --git a/server/routes/index.ts b/server/routes/index.ts
new file mode 100644
index 0000000000..80c07692b9
--- /dev/null
+++ b/server/routes/index.ts
@@ -0,0 +1,41 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { IRouter, ILegacyClusterClient } from '../../../../src/core/server';
+import { registerPplRoute } from './ppl';
+import PPLFacet from '../services/facets/ppl_facet';
+import { registerDslRoute } from './dsl';
+import DSLFacet from '../services/facets/dsl_facet';
+import SavedObjectFacet from '../services/facets/saved_objects';
+import { PanelsRouter } from './custom_panels/panels_router';
+import { VisualizationsRouter } from './custom_panels/visualizations_router';
+import { registerTraceAnalyticsDslRouter } from './trace_analytics_dsl_router';
+import { registerParaRoute } from './notebooks/paraRouter';
+import { registerNoteRoute } from './notebooks/noteRouter';
+import { registerVizRoute } from './notebooks/vizRouter';
+import QueryService from '../services/queryService';
+import { registerSqlRoute } from './notebooks/sqlRouter';
+import { registerEventAnalyticsRouter } from './event_analytics/event_analytics_router';
+import { registerAppAnalyticsRouter } from './application_analytics/app_analytics_router';
+
+
+export function setupRoutes({ router, client }: { router: IRouter; client: ILegacyClusterClient }) {
+ PanelsRouter(router);
+ VisualizationsRouter(router);
+ registerPplRoute({ router, facet: new PPLFacet(client) });
+ registerDslRoute({ router, facet: new DSLFacet(client)});
+ registerEventAnalyticsRouter({ router, savedObjectFacet: new SavedObjectFacet(client) });
+ registerAppAnalyticsRouter(router);
+
+ // TODO remove trace analytics route when DSL route for autocomplete is added
+ registerTraceAnalyticsDslRouter(router);
+
+ // notebooks routes
+ registerParaRoute(router);
+ registerNoteRoute(router);
+ registerVizRoute(router);
+ const queryService = new QueryService(client);
+ registerSqlRoute(router, queryService);
+};
diff --git a/server/routes/notebooks/noteRouter.ts b/server/routes/notebooks/noteRouter.ts
new file mode 100644
index 0000000000..27e7682bb9
--- /dev/null
+++ b/server/routes/notebooks/noteRouter.ts
@@ -0,0 +1,266 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { schema } from '@osd/config-schema';
+import {
+ ILegacyScopedClusterClient,
+ IOpenSearchDashboardsResponse,
+ IRouter,
+ ResponseError,
+} from '../../../../../src/core/server';
+import { NOTEBOOKS_API_PREFIX, wreckOptions } from '../../../common/constants/notebooks';
+import BACKEND from '../../adaptors/notebooks';
+
+export function registerNoteRoute(router: IRouter) {
+ // Fetch all the notebooks available
+ router.get(
+ {
+ path: `${NOTEBOOKS_API_PREFIX}/`,
+ validate: {},
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise> => {
+ const opensearchNotebooksClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+ request
+ );
+ let notebooksData = [];
+ try {
+ notebooksData = await BACKEND.viewNotes(opensearchNotebooksClient, wreckOptions);
+ return response.ok({
+ body: {
+ data: notebooksData,
+ },
+ });
+ } catch (error) {
+ console.log('Notebook:', error);
+ return response.custom({
+ statusCode: error.statusCode || 500,
+ body: error.message,
+ });
+ }
+ }
+ );
+
+ // Get all paragraphs of notebooks
+ router.get(
+ {
+ path: `${NOTEBOOKS_API_PREFIX}/note/{noteId}`,
+ validate: {
+ params: schema.object({
+ noteId: schema.string(),
+ }),
+ },
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise> => {
+ const opensearchNotebooksClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+ request
+ );
+ try {
+ const notebookinfo = await BACKEND.fetchNote(
+ opensearchNotebooksClient,
+ request.params.noteId,
+ wreckOptions
+ );
+ return response.ok({
+ body: notebookinfo,
+ });
+ } catch (error) {
+ return response.custom({
+ statusCode: error.statusCode || 500,
+ body: error.message,
+ });
+ }
+ }
+ );
+
+ // Add a Notebook
+ router.post(
+ {
+ path: `${NOTEBOOKS_API_PREFIX}/note`,
+ validate: {
+ body: schema.object({
+ name: schema.string(),
+ }),
+ },
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise> => {
+ const opensearchNotebooksClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+ request
+ );
+ try {
+ const addResponse = await BACKEND.addNote(
+ opensearchNotebooksClient,
+ request.body,
+ wreckOptions
+ );
+ return response.ok({
+ body: addResponse.message.objectId,
+ });
+ } catch (error) {
+ return response.custom({
+ statusCode: error.statusCode || 500,
+ body: error.message,
+ });
+ }
+ }
+ );
+
+ // Rename a notebook
+ router.put(
+ {
+ path: `${NOTEBOOKS_API_PREFIX}/note/rename`,
+ validate: {
+ body: schema.object({
+ name: schema.string(),
+ noteId: schema.string(),
+ }),
+ },
+ },
+ async (
+ context,
+ request,
+ response
+ ): Promise