Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Logs UI] Shared <LogStream /> component #76262

Merged
merged 19 commits into from
Sep 7, 2020

Conversation

afgomez
Copy link
Contributor

@afgomez afgomez commented Aug 31, 2020

Summary

Closes #75650

This PR implements an embeddable <LogStream /> component that other plugins can use.
Screenshot 2020-09-01 at 17 07 39

For the @elastic/apm-ui folks, the code I added to your area is a proof of concept and it's not intended to be merged in this PR. Feel free to play with it though :)

To Do

  • Fix layout issues.

Non-goals for this PR

  • Implement pagination

Checklist

Delete any items that are not applicable to this PR.

  • Documentation was added for features that require explanation or tutorials

@afgomez afgomez changed the title [Logs UI] Shared <LogStream /> component log stream shared [Logs UI] Shared <LogStream /> component Sep 1, 2020
The `<LogStream />` component misbehaves when its parent component
doesn't have a fixed width. This is caused by an `AutoSizer` trying to
determine the necessary width, and the `ScrollableLogTextStreamView`
trying to hide the scrollbar by making the scrollable view 20 pixels
wider than its container.

To fix this we control the hiding behaviour through a prop, and disable
it in our component.
@afgomez afgomez added Feature:Logs UI Logs UI feature Team:Infra Monitoring UI - DEPRECATED DEPRECATED - Label for the Infra Monitoring UI team. Use Team:obs-ux-infra_services labels Sep 1, 2020
@afgomez afgomez added this to the Logs UI 7.10 milestone Sep 1, 2020
@afgomez afgomez added release_note:skip Skip the PR/issue when compiling release notes v7.10.0 v8.0.0 labels Sep 1, 2020
@jasonrhodes
Copy link
Member

I was playing with useKibana error handling and I have two thoughts:

  1. We should throw a specific error when services.http doesn't exist. services should always at the very least be an empty object—we should make our type specify http as optional and then throw that error if (!services.http)
  2. What do you think about adding an EuiErrorBoundary around the outside of our component so it doesn't crash other apps? Is that our responsibility or should the calling app wrap our component if they want to do that? I'm not sure what the "right" way is...

@afgomez afgomez marked this pull request as ready for review September 1, 2020 19:01
@afgomez afgomez requested review from a team as code owners September 1, 2020 19:01
@elasticmachine
Copy link
Contributor

Pinging @elastic/logs-metrics-ui (Team:logs-metrics-ui)

@botelastic botelastic bot added the Team:APM All issues that need APM UI Team support label Sep 1, 2020
@elasticmachine
Copy link
Contributor

Pinging @elastic/apm-ui (Team:apm)

@sorenlouv
Copy link
Member

Wow, this is awesome @afgomez !

startTimestamp={Date.now() - 86400000}
endTimestamp={Date.now()}
query={`trace.id: "${urlParams.traceId}" OR "${urlParams.traceId}"`}
/>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This interface lgtm 👍 Thanks for doing this

@afgomez
Copy link
Contributor Author

afgomez commented Sep 2, 2020

1. We should throw a specific error when `services.http` doesn't exist. `services` should always at the very least be an empty object—we should make our type specify `http` as optional and then throw that error `if (!services.http)`

This has been fixed.

2. What do you think about adding an `EuiErrorBoundary` around the outside of our component so it doesn't crash other apps? Is that our responsibility or should the calling app wrap our component if they want to do that? I'm not sure what the "right" way is...

We discussed this somewhere else but I'll add my opinion here for completion.

I consider this shared component library code (vs application code). I think when something exceptional happens the component should throw an exception and let the consuming application code decide what to do. Maybe they want to recover from it, maybe they want to crash and burn the app because there's nothing to do if this component didn't load, but I don't think library code should make that decision.

@jasonrhodes
Copy link
Member

I think when something exceptional happens the component should throw an exception and let the consuming application code decide what to do.

Makes sense. It's hard to imagine a case where this component would be on its own somewhere else, but you're right that we should probably let the caller make the decision. Can we add a casual recommendation to consider wrapping the LogStream component in an EuiErrorBoundary in the docs for this component?

Copy link
Member

@weltenwort weltenwort left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a comprehensive code review, but it looks really good! I left two questions below, though. 😉


To use the component, there are several things you need to ensure in your plugin:

- In your `kibana.json` plugin, you need to either add `"requiredBundles": ["infra"]` or `"requiredPlugins": ["infra"]`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would requiredBundles be enough given that this component uses the infra HTTP API to fetch the data?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmm, good point. I haven't tried what would happen if the infra plugin is disabled.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can provide a "is the logs api available?" wrapper alongside that renders an informative message instead of the children? (In a separate PR, though.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked what happens with xpack.infra.enabled: false. The component renders, but it says there's no log data. I will remove the requiredBundles bit from the docs because it's a lie :D.

Copy link
Contributor Author

@afgomez afgomez Sep 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I want to give freedom to plugin developers here. They can either choose to make it a hard requirement (requiredPlugins), or a soft one (optionalPlugins). In the second case, we can advise to wrap our component in a check that tests if the infra plugin is loaded or not, alongside other changes that they want to do in their UI.

function SomeComponent() {
	const { services } = useKibana();
	const hasInfraPlugin = 'infra' in services; // This seems to work

	const tabs = ['Timeline', 'Metadata'];
	if (hasInfraPlugin) {
		tabs.push('Logs');
	}
	// ...
}

We can give examples in the docs. Do you think this is enough, or do you think it's the responsibility of our component to check for this? We can of course also check on our side and raise an exception.


Edit: It's not possible. It needs to be in requiredPlugins if the component is imported

Screenshot 2020-09-04 at 17 15 08

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if it's in optional plugins, then they need to add it to requiredBundles as I understand it.

x-pack/plugins/infra/public/index.ts Outdated Show resolved Hide resolved
@alex-fedotyev
Copy link

This is awesome!
I love the idea to accept query as input, this would allow to be flexible to leverage this for multiple use cases in APM:

  • Logs for distributed trace across multiple services (trace.Id: NNN)
  • Logs for the service across all instances (service.Name: bla)
  • Logs for the service on specific instance(s) (service.Name: bla AND container...)

Copy link
Member

@jasonrhodes jasonrhodes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I finally got this working locally and it looks good. I wonder a couple things as we iterate on this shared component:

  • This separated from the context of the Logs UI, I'm not sure if the chosen columns for the source configuration are a great idea. Maybe this should just be timestamp and message by default?
  • It also feels a bit strange that I can't interact with the message to learn more about it at all. I think clicking on the log line should take you to the Logs UI but at the very least some kind of link to the Logs UI somewhere may be good, either clicking the log line, using the actions popover menu, or we let APM and other users of this shared plugin handle this on their own, e.g. one single "view in Logs UI" link at the top of the tab content here

But as a first step this looks great and we should get it merged so others can weigh in with feedback.

@kibanamachine
Copy link
Contributor

💛 Build succeeded, but was flaky


Test Failures

Accessibility Tests.test/accessibility/apps/discover·ts.Discover Load a new search from the panel

Link to Jenkins

Standard Out

Failed Tests Reporter:
  - Test has failed 5 times on tracked branches: https://github.com/elastic/kibana/issues/59975

[00:00:00]       │
[00:00:00]         └-: Discover
[00:00:00]           └-> "before all" hook
[00:00:00]           └-> "before all" hook
[00:00:00]             │ info [discover] Loading "mappings.json"
[00:00:00]             │ info [discover] Loading "data.json.gz"
[00:00:00]             │ info [o.e.c.m.MetadataDeleteIndexService] [kibana-ci-immutable-debian-tests-xxl-1599481284762790432] [.kibana_1/gtXMZwMGRGmM01Yzx9VIGA] deleting index
[00:00:00]             │ info [discover] Deleted existing index [".kibana_1"]
[00:00:00]             │ info [o.e.c.m.MetadataCreateIndexService] [kibana-ci-immutable-debian-tests-xxl-1599481284762790432] [.kibana] creating index, cause [api], templates [], shards [1]/[1]
[00:00:00]             │ info [discover] Created index ".kibana"
[00:00:00]             │ debg [discover] ".kibana" settings {"index":{"number_of_replicas":"1","number_of_shards":"1"}}
[00:00:00]             │ info [discover] Indexed 2 docs into ".kibana"
[00:00:00]             │ info [o.e.c.m.MetadataMappingService] [kibana-ci-immutable-debian-tests-xxl-1599481284762790432] [.kibana/OL0FTSflTVWExYfE0CklVw] update_mapping [_doc]
[00:00:00]             │ debg Migrating saved objects
[00:00:00]             │ proc [kibana]   log   [12:39:05.334] [info][savedobjects-service] Creating index .kibana_2.
[00:00:00]             │ info [o.e.c.m.MetadataCreateIndexService] [kibana-ci-immutable-debian-tests-xxl-1599481284762790432] [.kibana_2] creating index, cause [api], templates [], shards [1]/[1]
[00:00:00]             │ info [o.e.c.r.a.AllocationService] [kibana-ci-immutable-debian-tests-xxl-1599481284762790432] updating number_of_replicas to [0] for indices [.kibana_2]
[00:00:00]             │ proc [kibana]   log   [12:39:05.439] [info][savedobjects-service] Reindexing .kibana to .kibana_1
[00:00:00]             │ info [o.e.c.m.MetadataCreateIndexService] [kibana-ci-immutable-debian-tests-xxl-1599481284762790432] [.kibana_1] creating index, cause [api], templates [], shards [1]/[1]
[00:00:00]             │ info [o.e.c.r.a.AllocationService] [kibana-ci-immutable-debian-tests-xxl-1599481284762790432] updating number_of_replicas to [0] for indices [.kibana_1]
[00:00:00]             │ info [o.e.c.m.MetadataCreateIndexService] [kibana-ci-immutable-debian-tests-xxl-1599481284762790432] [.tasks] creating index, cause [auto(task api)], templates [], shards [1]/[1]
[00:00:00]             │ info [o.e.c.r.a.AllocationService] [kibana-ci-immutable-debian-tests-xxl-1599481284762790432] updating number_of_replicas to [0] for indices [.tasks]
[00:00:00]             │ info [o.e.t.LoggingTaskListener] [kibana-ci-immutable-debian-tests-xxl-1599481284762790432] 106 finished with response BulkByScrollResponse[took=101.5ms,timed_out=false,sliceId=null,updated=0,created=2,deleted=0,batches=1,versionConflicts=0,noops=0,retries=0,throttledUntil=0s,bulk_failures=[],search_failures=[]]
[00:00:00]             │ info [o.e.c.m.MetadataDeleteIndexService] [kibana-ci-immutable-debian-tests-xxl-1599481284762790432] [.kibana/OL0FTSflTVWExYfE0CklVw] deleting index
[00:00:01]             │ proc [kibana]   log   [12:39:05.887] [info][savedobjects-service] Migrating .kibana_1 saved objects to .kibana_2
[00:00:01]             │ info [o.e.c.m.MetadataMappingService] [kibana-ci-immutable-debian-tests-xxl-1599481284762790432] [.kibana_2/rWLFEPnDRTGGLM0wuEcmrg] update_mapping [_doc]
[00:00:01]             │ info [o.e.c.m.MetadataMappingService] [kibana-ci-immutable-debian-tests-xxl-1599481284762790432] [.kibana_2/rWLFEPnDRTGGLM0wuEcmrg] update_mapping [_doc]
[00:00:01]             │ proc [kibana]   log   [12:39:06.064] [info][savedobjects-service] Pointing alias .kibana to .kibana_2.
[00:00:01]             │ proc [kibana]   log   [12:39:06.123] [info][savedobjects-service] Finished in 793ms.
[00:00:01]             │ debg applying update to kibana config: {"accessibility:disableAnimations":true,"dateFormat:tz":"UTC"}
[00:00:01]             │ info [o.e.c.m.MetadataMappingService] [kibana-ci-immutable-debian-tests-xxl-1599481284762790432] [.kibana_2/rWLFEPnDRTGGLM0wuEcmrg] update_mapping [_doc]
[00:00:02]             │ info [logstash_functional] Loading "mappings.json"
[00:00:02]             │ info [logstash_functional] Loading "data.json.gz"
[00:00:02]             │ info [o.e.c.m.MetadataCreateIndexService] [kibana-ci-immutable-debian-tests-xxl-1599481284762790432] [logstash-2015.09.22] creating index, cause [api], templates [], shards [1]/[0]
[00:00:02]             │ info [o.e.c.r.a.AllocationService] [kibana-ci-immutable-debian-tests-xxl-1599481284762790432] current.health="GREEN" message="Cluster health status changed from [YELLOW] to [GREEN] (reason: [shards started [[logstash-2015.09.22][0]]])." previous.health="YELLOW" reason="shards started [[logstash-2015.09.22][0]]"
[00:00:02]             │ info [logstash_functional] Created index "logstash-2015.09.22"
[00:00:02]             │ debg [logstash_functional] "logstash-2015.09.22" settings {"index":{"analysis":{"analyzer":{"url":{"max_token_length":"1000","tokenizer":"uax_url_email","type":"standard"}}},"number_of_replicas":"0","number_of_shards":"1"}}
[00:00:02]             │ info [o.e.c.m.MetadataCreateIndexService] [kibana-ci-immutable-debian-tests-xxl-1599481284762790432] [logstash-2015.09.20] creating index, cause [api], templates [], shards [1]/[0]
[00:00:02]             │ info [o.e.c.r.a.AllocationService] [kibana-ci-immutable-debian-tests-xxl-1599481284762790432] current.health="GREEN" message="Cluster health status changed from [YELLOW] to [GREEN] (reason: [shards started [[logstash-2015.09.20][0]]])." previous.health="YELLOW" reason="shards started [[logstash-2015.09.20][0]]"
[00:00:02]             │ info [logstash_functional] Created index "logstash-2015.09.20"
[00:00:02]             │ debg [logstash_functional] "logstash-2015.09.20" settings {"index":{"analysis":{"analyzer":{"url":{"max_token_length":"1000","tokenizer":"uax_url_email","type":"standard"}}},"number_of_replicas":"0","number_of_shards":"1"}}
[00:00:02]             │ info [o.e.c.m.MetadataCreateIndexService] [kibana-ci-immutable-debian-tests-xxl-1599481284762790432] [logstash-2015.09.21] creating index, cause [api], templates [], shards [1]/[0]
[00:00:02]             │ info [o.e.c.r.a.AllocationService] [kibana-ci-immutable-debian-tests-xxl-1599481284762790432] current.health="GREEN" message="Cluster health status changed from [YELLOW] to [GREEN] (reason: [shards started [[logstash-2015.09.21][0]]])." previous.health="YELLOW" reason="shards started [[logstash-2015.09.21][0]]"
[00:00:02]             │ info [logstash_functional] Created index "logstash-2015.09.21"
[00:00:02]             │ debg [logstash_functional] "logstash-2015.09.21" settings {"index":{"analysis":{"analyzer":{"url":{"max_token_length":"1000","tokenizer":"uax_url_email","type":"standard"}}},"number_of_replicas":"0","number_of_shards":"1"}}
[00:00:12]             │ info progress: 6613
[00:00:21]             │ info [logstash_functional] Indexed 4633 docs into "logstash-2015.09.22"
[00:00:21]             │ info [logstash_functional] Indexed 4757 docs into "logstash-2015.09.20"
[00:00:21]             │ info [logstash_functional] Indexed 4614 docs into "logstash-2015.09.21"
[00:00:22]             │ debg applying update to kibana config: {"defaultIndex":"logstash-*"}
[00:00:22]             │ debg navigating to discover url: http://localhost:61141/app/discover#/
[00:00:22]             │ debg navigate to: http://localhost:61141/app/discover#/
[00:00:22]             │ debg browser[INFO] http://localhost:61141/app/discover?_t=1599482367486#/ 341 Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'unsafe-eval' 'self'". Either the 'unsafe-inline' keyword, a hash ('sha256-P5polb1UreUSOe5V/Pv7tc+yeZuJXiOi/3fqhGsU7BE='), or a nonce ('nonce-...') is required to enable inline execution.
[00:00:22]             │
[00:00:22]             │ debg browser[INFO] http://localhost:61141/bootstrap.js 42:19 "^ A single error about an inline script not firing due to content security policy is expected!"
[00:00:22]             │ debg ... sleep(700) start
[00:00:23]             │ debg ... sleep(700) end
[00:00:23]             │ debg returned from get, calling refresh
[00:00:27]             │ debg browser[INFO] http://localhost:61141/app/discover?_t=1599482367486#/ 341 Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'unsafe-eval' 'self'". Either the 'unsafe-inline' keyword, a hash ('sha256-P5polb1UreUSOe5V/Pv7tc+yeZuJXiOi/3fqhGsU7BE='), or a nonce ('nonce-...') is required to enable inline execution.
[00:00:27]             │
[00:00:27]             │ debg browser[INFO] http://localhost:61141/bootstrap.js 42:19 "^ A single error about an inline script not firing due to content security policy is expected!"
[00:00:27]             │ debg currentUrl = http://localhost:61141/app/discover#/
[00:00:27]             │          appUrl = http://localhost:61141/app/discover#/
[00:00:27]             │ debg TestSubjects.find(kibanaChrome)
[00:00:27]             │ debg Find.findByCssSelector('[data-test-subj="kibanaChrome"]') with timeout=60000
[00:00:32]             │ debg ... sleep(501) start
[00:00:32]             │ debg ... sleep(501) end
[00:00:32]             │ debg in navigateTo url = http://localhost:61141/app/discover#/
[00:00:32]             │ debg TestSubjects.exists(statusPageContainer)
[00:00:32]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj="statusPageContainer"]') with timeout=2500
[00:00:35]             │ debg --- retry.tryForTime error: [data-test-subj="statusPageContainer"] is not displayed
[00:00:36]             │ debg Setting absolute range to Sep 19, 2015 @ 06:31:44.000 to Sep 23, 2015 @ 18:31:44.000
[00:00:36]             │ debg TestSubjects.exists(superDatePickerToggleQuickMenuButton)
[00:00:36]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj="superDatePickerToggleQuickMenuButton"]') with timeout=20000
[00:00:36]             │ debg TestSubjects.exists(superDatePickerShowDatesButton)
[00:00:36]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj="superDatePickerShowDatesButton"]') with timeout=2500
[00:00:36]             │ debg TestSubjects.click(superDatePickerShowDatesButton)
[00:00:36]             │ debg Find.clickByCssSelector('[data-test-subj="superDatePickerShowDatesButton"]') with timeout=10000
[00:00:36]             │ debg Find.findByCssSelector('[data-test-subj="superDatePickerShowDatesButton"]') with timeout=10000
[00:00:36]             │ debg TestSubjects.exists(superDatePickerstartDatePopoverButton)
[00:00:36]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj="superDatePickerstartDatePopoverButton"]') with timeout=2500
[00:00:36]             │ debg TestSubjects.click(superDatePickerendDatePopoverButton)
[00:00:36]             │ debg Find.clickByCssSelector('[data-test-subj="superDatePickerendDatePopoverButton"]') with timeout=10000
[00:00:36]             │ debg Find.findByCssSelector('[data-test-subj="superDatePickerendDatePopoverButton"]') with timeout=10000
[00:00:36]             │ debg Find.findByCssSelector('div.euiPopover__panel-isOpen') with timeout=10000
[00:00:36]             │ debg TestSubjects.click(superDatePickerAbsoluteTab)
[00:00:36]             │ debg Find.clickByCssSelector('[data-test-subj="superDatePickerAbsoluteTab"]') with timeout=10000
[00:00:36]             │ debg Find.findByCssSelector('[data-test-subj="superDatePickerAbsoluteTab"]') with timeout=10000
[00:00:36]             │ debg TestSubjects.click(superDatePickerAbsoluteDateInput)
[00:00:36]             │ debg Find.clickByCssSelector('[data-test-subj="superDatePickerAbsoluteDateInput"]') with timeout=10000
[00:00:36]             │ debg Find.findByCssSelector('[data-test-subj="superDatePickerAbsoluteDateInput"]') with timeout=10000
[00:00:37]             │ debg TestSubjects.setValue(superDatePickerAbsoluteDateInput, Sep 23, 2015 @ 18:31:44.000)
[00:00:37]             │ debg TestSubjects.click(superDatePickerAbsoluteDateInput)
[00:00:37]             │ debg Find.clickByCssSelector('[data-test-subj="superDatePickerAbsoluteDateInput"]') with timeout=10000
[00:00:37]             │ debg Find.findByCssSelector('[data-test-subj="superDatePickerAbsoluteDateInput"]') with timeout=10000
[00:00:37]             │ debg ... sleep(500) start
[00:00:38]             │ debg ... sleep(500) end
[00:00:38]             │ debg TestSubjects.click(superDatePickerstartDatePopoverButton)
[00:00:38]             │ debg Find.clickByCssSelector('[data-test-subj="superDatePickerstartDatePopoverButton"]') with timeout=10000
[00:00:38]             │ debg Find.findByCssSelector('[data-test-subj="superDatePickerstartDatePopoverButton"]') with timeout=10000
[00:00:38]             │ debg Find.waitForElementStale with timeout=10000
[00:00:38]             │ debg Find.findByCssSelector('div.euiPopover__panel-isOpen') with timeout=10000
[00:00:38]             │ debg TestSubjects.click(superDatePickerAbsoluteTab)
[00:00:38]             │ debg Find.clickByCssSelector('[data-test-subj="superDatePickerAbsoluteTab"]') with timeout=10000
[00:00:38]             │ debg Find.findByCssSelector('[data-test-subj="superDatePickerAbsoluteTab"]') with timeout=10000
[00:00:39]             │ debg TestSubjects.click(superDatePickerAbsoluteDateInput)
[00:00:39]             │ debg Find.clickByCssSelector('[data-test-subj="superDatePickerAbsoluteDateInput"]') with timeout=10000
[00:00:39]             │ debg Find.findByCssSelector('[data-test-subj="superDatePickerAbsoluteDateInput"]') with timeout=10000
[00:00:39]             │ debg TestSubjects.setValue(superDatePickerAbsoluteDateInput, Sep 19, 2015 @ 06:31:44.000)
[00:00:39]             │ debg TestSubjects.click(superDatePickerAbsoluteDateInput)
[00:00:39]             │ debg Find.clickByCssSelector('[data-test-subj="superDatePickerAbsoluteDateInput"]') with timeout=10000
[00:00:39]             │ debg Find.findByCssSelector('[data-test-subj="superDatePickerAbsoluteDateInput"]') with timeout=10000
[00:00:39]             │ debg TestSubjects.exists(superDatePickerApplyTimeButton)
[00:00:39]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj="superDatePickerApplyTimeButton"]') with timeout=2500
[00:00:42]             │ debg --- retry.tryForTime error: [data-test-subj="superDatePickerApplyTimeButton"] is not displayed
[00:00:42]             │ debg TestSubjects.click(querySubmitButton)
[00:00:42]             │ debg Find.clickByCssSelector('[data-test-subj="querySubmitButton"]') with timeout=10000
[00:00:42]             │ debg Find.findByCssSelector('[data-test-subj="querySubmitButton"]') with timeout=10000
[00:00:43]             │ debg Find.waitForElementStale with timeout=10000
[00:00:43]             │ debg TestSubjects.exists(globalLoadingIndicator-hidden)
[00:00:43]             │ debg Find.existsByCssSelector('[data-test-subj="globalLoadingIndicator-hidden"]') with timeout=100000
[00:00:46]           └-> main view
[00:00:46]             └-> "before each" hook: global before each
[00:01:03]             └- ✓ pass  (17.3s) "Discover main view"
[00:01:03]           └-> Click save button
[00:01:03]             └-> "before each" hook: global before each
[00:01:03]             │ debg TestSubjects.click(discoverSaveButton)
[00:01:03]             │ debg Find.clickByCssSelector('[data-test-subj="discoverSaveButton"]') with timeout=10000
[00:01:03]             │ debg Find.findByCssSelector('[data-test-subj="discoverSaveButton"]') with timeout=10000
[00:01:07]             └- ✓ pass  (4.4s) "Discover Click save button"
[00:01:07]           └-> Save search panel
[00:01:07]             └-> "before each" hook: global before each
[00:01:07]             │ debg TestSubjects.setValue(savedObjectTitle, a11ySearch)
[00:01:07]             │ debg TestSubjects.click(savedObjectTitle)
[00:01:07]             │ debg Find.clickByCssSelector('[data-test-subj="savedObjectTitle"]') with timeout=10000
[00:01:07]             │ debg Find.findByCssSelector('[data-test-subj="savedObjectTitle"]') with timeout=10000
[00:01:10]             └- ✓ pass  (3.2s) "Discover Save search panel"
[00:01:10]           └-> Confirm saved search
[00:01:10]             └-> "before each" hook: global before each
[00:01:10]             │ debg TestSubjects.click(confirmSaveSavedObjectButton)
[00:01:10]             │ debg Find.clickByCssSelector('[data-test-subj="confirmSaveSavedObjectButton"]') with timeout=10000
[00:01:10]             │ debg Find.findByCssSelector('[data-test-subj="confirmSaveSavedObjectButton"]') with timeout=10000
[00:01:14]             └- ✓ pass  (4.1s) "Discover Confirm saved search"
[00:01:14]           └-> Click on new to clear the search
[00:01:14]             └-> "before each" hook: global before each
[00:01:15]             │ debg TestSubjects.click(discoverNewButton)
[00:01:15]             │ debg Find.clickByCssSelector('[data-test-subj="discoverNewButton"]') with timeout=10000
[00:01:15]             │ debg Find.findByCssSelector('[data-test-subj="discoverNewButton"]') with timeout=10000
[00:01:16]             │ debg isGlobalLoadingIndicatorVisible
[00:01:16]             │ debg TestSubjects.exists(globalLoadingIndicator)
[00:01:16]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj="globalLoadingIndicator"]') with timeout=1500
[00:01:17]             │ debg TestSubjects.exists(globalLoadingIndicator-hidden)
[00:01:17]             │ debg Find.existsByCssSelector('[data-test-subj="globalLoadingIndicator-hidden"]') with timeout=100000
[00:01:31]             └- ✓ pass  (17.0s) "Discover Click on new to clear the search"
[00:01:31]           └-> Open load saved search panel
[00:01:31]             └-> "before each" hook: global before each
[00:01:32]             │ debg TestSubjects.exists(loadSearchForm)
[00:01:32]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj="loadSearchForm"]') with timeout=2500
[00:01:34]             │ debg --- retry.tryForTime error: [data-test-subj="loadSearchForm"] is not displayed
[00:01:35]             │ debg Waiting up to 20000ms for saved search panel is opened...
[00:01:35]             │ debg TestSubjects.moveMouseTo(discoverOpenButton)
[00:01:35]             │ debg TestSubjects.find(discoverOpenButton)
[00:01:35]             │ debg Find.findByCssSelector('[data-test-subj="discoverOpenButton"]') with timeout=10000
[00:01:35]             │ debg TestSubjects.click(discoverOpenButton)
[00:01:35]             │ debg Find.clickByCssSelector('[data-test-subj="discoverOpenButton"]') with timeout=10000
[00:01:35]             │ debg Find.findByCssSelector('[data-test-subj="discoverOpenButton"]') with timeout=10000
[00:01:35]             │ debg isGlobalLoadingIndicatorVisible
[00:01:35]             │ debg TestSubjects.exists(globalLoadingIndicator)
[00:01:35]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj="globalLoadingIndicator"]') with timeout=1500
[00:01:36]             │ debg --- retry.tryForTime error: [data-test-subj="globalLoadingIndicator"] is not displayed
[00:01:38]             │ debg --- retry.tryForTime failed again with the same message...
[00:01:38]             │ debg TestSubjects.exists(globalLoadingIndicator-hidden)
[00:01:38]             │ debg Find.existsByCssSelector('[data-test-subj="globalLoadingIndicator-hidden"]') with timeout=100000
[00:01:38]             │ debg TestSubjects.exists(loadSearchForm)
[00:01:38]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj="loadSearchForm"]') with timeout=2500
[00:01:41]             │ debg TestSubjects.click(euiFlyoutCloseButton)
[00:01:41]             │ debg Find.clickByCssSelector('[data-test-subj="euiFlyoutCloseButton"]') with timeout=10000
[00:01:41]             │ debg Find.findByCssSelector('[data-test-subj="euiFlyoutCloseButton"]') with timeout=10000
[00:01:41]             └- ✓ pass  (9.6s) "Discover Open load saved search panel"
[00:01:41]           └-> Open inspector panel
[00:01:41]             └-> "before each" hook: global before each
[00:01:41]             │ debg Inspector.open
[00:01:41]             │ debg TestSubjects.exists(inspectorPanel)
[00:01:41]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj="inspectorPanel"]') with timeout=2500
[00:01:44]             │ debg --- retry.tryForTime error: [data-test-subj="inspectorPanel"] is not displayed
[00:01:44]             │ debg TestSubjects.click(openInspectorButton)
[00:01:44]             │ debg Find.clickByCssSelector('[data-test-subj="openInspectorButton"]') with timeout=10000
[00:01:44]             │ debg Find.findByCssSelector('[data-test-subj="openInspectorButton"]') with timeout=10000
[00:01:45]             │ debg TestSubjects.exists(inspectorPanel)
[00:01:45]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj="inspectorPanel"]') with timeout=2500
[00:01:47]             │ debg Close Inspector
[00:01:47]             │ debg TestSubjects.exists(inspectorPanel)
[00:01:47]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj="inspectorPanel"]') with timeout=2500
[00:01:47]             │ debg Closing flyout inspectorPanel
[00:01:47]             │ debg TestSubjects.find(inspectorPanel)
[00:01:47]             │ debg Find.findByCssSelector('[data-test-subj="inspectorPanel"]') with timeout=10000
[00:01:47]             │ debg Waiting up to 20000ms for flyout closed...
[00:01:47]             │ debg TestSubjects.exists(inspectorPanel)
[00:01:47]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj="inspectorPanel"]') with timeout=1000
[00:01:48]             │ debg --- retry.tryForTime error: [data-test-subj="inspectorPanel"] is not displayed
[00:01:49]             │ debg TestSubjects.exists(inspectorPanel)
[00:01:49]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj="inspectorPanel"]') with timeout=2500
[00:01:51]             │ debg --- retry.tryForTime error: [data-test-subj="inspectorPanel"] is not displayed
[00:01:52]             └- ✓ pass  (10.7s) "Discover Open inspector panel"
[00:01:52]           └-> Open add filter
[00:01:52]             └-> "before each" hook: global before each
[00:01:52]             │ debg TestSubjects.click(addFilter)
[00:01:52]             │ debg Find.clickByCssSelector('[data-test-subj="addFilter"]') with timeout=10000
[00:01:52]             │ debg Find.findByCssSelector('[data-test-subj="addFilter"]') with timeout=10000
[00:01:54]             └- ✓ pass  (1.9s) "Discover Open add filter"
[00:01:54]           └-> Select values for a filter
[00:01:54]             └-> "before each" hook: global before each
[00:01:54]             │ debg TestSubjects.click(addFilter)
[00:01:54]             │ debg Find.clickByCssSelector('[data-test-subj="addFilter"]') with timeout=10000
[00:01:54]             │ debg Find.findByCssSelector('[data-test-subj="addFilter"]') with timeout=10000
[00:01:54]             │ debg comboBox.set, comboBoxSelector: filterFieldSuggestionList
[00:01:54]             │ debg TestSubjects.find(filterFieldSuggestionList)
[00:01:54]             │ debg Find.findByCssSelector('[data-test-subj="filterFieldSuggestionList"]') with timeout=10000
[00:01:54]             │ debg comboBox.setElement, value: extension.raw
[00:01:54]             │ debg comboBox.isOptionSelected, value: extension.raw
[00:01:57]             │ debg TestSubjects.exists(~comboBoxOptionsList)
[00:01:57]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj~="comboBoxOptionsList"]') with timeout=2500
[00:01:57]             │ debg Find.allByCssSelector('.euiFilterSelectItem[title^="extension.raw"]') with timeout=2500
[00:01:57]             │ debg TestSubjects.exists(~comboBoxOptionsList)
[00:01:57]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj~="comboBoxOptionsList"]') with timeout=2500
[00:02:00]             │ debg --- retry.tryForTime error: [data-test-subj~="comboBoxOptionsList"] is not displayed
[00:02:00]             │ debg comboBox.set, comboBoxSelector: filterOperatorList
[00:02:00]             │ debg TestSubjects.find(filterOperatorList)
[00:02:00]             │ debg Find.findByCssSelector('[data-test-subj="filterOperatorList"]') with timeout=10000
[00:02:00]             │ debg comboBox.setElement, value: is one of
[00:02:00]             │ debg comboBox.isOptionSelected, value: is one of
[00:02:03]             │ debg TestSubjects.exists(~comboBoxOptionsList)
[00:02:03]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj~="comboBoxOptionsList"]') with timeout=2500
[00:02:03]             │ debg Find.allByCssSelector('.euiFilterSelectItem[title^="is one of"]') with timeout=2500
[00:02:03]             │ debg TestSubjects.exists(~comboBoxOptionsList)
[00:02:03]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj~="comboBoxOptionsList"]') with timeout=2500
[00:02:06]             │ debg --- retry.tryForTime error: [data-test-subj~="comboBoxOptionsList"] is not displayed
[00:02:06]             │ debg TestSubjects.find(filterParams)
[00:02:06]             │ debg Find.findByCssSelector('[data-test-subj="filterParams"]') with timeout=10000
[00:02:06]             │ debg comboBox.setElement, value: jpg
[00:02:06]             │ debg comboBox.isOptionSelected, value: jpg
[00:02:09]             │ debg TestSubjects.exists(~comboBoxOptionsList)
[00:02:09]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj~="comboBoxOptionsList"]') with timeout=2500
[00:02:09]             │ debg Find.allByCssSelector('.euiFilterSelectItem[title^="jpg"]') with timeout=2500
[00:02:09]             │ debg TestSubjects.exists(~comboBoxOptionsList)
[00:02:09]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj~="comboBoxOptionsList"]') with timeout=2500
[00:02:09]             │ debg TestSubjects.click(saveFilter)
[00:02:09]             │ debg Find.clickByCssSelector('[data-test-subj="saveFilter"]') with timeout=10000
[00:02:09]             │ debg Find.findByCssSelector('[data-test-subj="saveFilter"]') with timeout=10000
[00:02:09]             │ debg TestSubjects.exists(globalLoadingIndicator-hidden)
[00:02:09]             │ debg Find.existsByCssSelector('[data-test-subj="globalLoadingIndicator-hidden"]') with timeout=100000
[00:02:22]             └- ✓ pass  (28.4s) "Discover Select values for a filter"
[00:02:22]           └-> Load a new search from the panel
[00:02:22]             └-> "before each" hook: global before each
[00:02:22]             │ debg TestSubjects.click(discoverSaveButton)
[00:02:22]             │ debg Find.clickByCssSelector('[data-test-subj="discoverSaveButton"]') with timeout=10000
[00:02:22]             │ debg Find.findByCssSelector('[data-test-subj="discoverSaveButton"]') with timeout=10000
[00:02:23]             │ debg TestSubjects.setValue(savedObjectTitle, filterSearch)
[00:02:23]             │ debg TestSubjects.click(savedObjectTitle)
[00:02:23]             │ debg Find.clickByCssSelector('[data-test-subj="savedObjectTitle"]') with timeout=10000
[00:02:23]             │ debg Find.findByCssSelector('[data-test-subj="savedObjectTitle"]') with timeout=10000
[00:02:23]             │ debg TestSubjects.click(confirmSaveSavedObjectButton)
[00:02:23]             │ debg Find.clickByCssSelector('[data-test-subj="confirmSaveSavedObjectButton"]') with timeout=10000
[00:02:23]             │ debg Find.findByCssSelector('[data-test-subj="confirmSaveSavedObjectButton"]') with timeout=10000
[00:02:24]             │ debg TestSubjects.exists(loadSearchForm)
[00:02:24]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj="loadSearchForm"]') with timeout=2500
[00:02:26]             │ debg --- retry.tryForTime error: [data-test-subj="loadSearchForm"] is not displayed
[00:02:27]             │ debg Waiting up to 20000ms for saved search panel is opened...
[00:02:27]             │ debg TestSubjects.moveMouseTo(discoverOpenButton)
[00:02:27]             │ debg TestSubjects.find(discoverOpenButton)
[00:02:27]             │ debg Find.findByCssSelector('[data-test-subj="discoverOpenButton"]') with timeout=10000
[00:02:27]             │ debg TestSubjects.click(discoverOpenButton)
[00:02:27]             │ debg Find.clickByCssSelector('[data-test-subj="discoverOpenButton"]') with timeout=10000
[00:02:27]             │ debg Find.findByCssSelector('[data-test-subj="discoverOpenButton"]') with timeout=10000
[00:02:27]             │ debg isGlobalLoadingIndicatorVisible
[00:02:27]             │ debg TestSubjects.exists(globalLoadingIndicator)
[00:02:27]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj="globalLoadingIndicator"]') with timeout=1500
[00:02:29]             │ debg --- retry.tryForTime error: [data-test-subj="globalLoadingIndicator"] is not displayed
[00:02:29]             │ debg TestSubjects.exists(globalLoadingIndicator-hidden)
[00:02:29]             │ debg Find.existsByCssSelector('[data-test-subj="globalLoadingIndicator-hidden"]') with timeout=100000
[00:02:29]             │ debg TestSubjects.exists(loadSearchForm)
[00:02:29]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj="loadSearchForm"]') with timeout=2500
[00:02:29]             │ debg TestSubjects.exists(loadSearchForm)
[00:02:29]             │ debg Find.existsByDisplayedByCssSelector('[data-test-subj="loadSearchForm"]') with timeout=2500
[00:02:29]             │ debg Find.byButtonText('filterSearch') with timeout=10000
[00:02:39]             │ debg --- retry.tryForTime error: stale element reference: element is not attached to the page document
[00:02:39]             │        (Session info: headless chrome=84.0.4147.135)
[00:02:40]             │ info Taking screenshot "/dev/shm/workspace/parallel/14/kibana/test/functional/screenshots/failure/Discover Load a new search from the panel.png"
[00:02:40]             │ info Current URL is: http://localhost:61141/app/discover#/view/734d43d0-f107-11ea-a4ee-9b826948e6d3?_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:%272015-09-19T06:31:44.000Z%27,to:%272015-09-23T18:31:44.000Z%27))&_a=(columns:!(_source),filters:!((%27$state%27:(store:appState),meta:(alias:!n,disabled:!f,index:%27logstash-*%27,key:extension.raw,negate:!f,params:!(jpg),type:phrases,value:jpg),query:(bool:(minimum_should_match:1,should:!((match_phrase:(extension.raw:jpg))))))),index:%27logstash-*%27,interval:auto,query:(language:kuery,query:%27%27),sort:!())
[00:02:40]             │ info Saving page source to: /dev/shm/workspace/parallel/14/kibana/test/functional/failure_debug/html/Discover Load a new search from the panel.html
[00:02:40]             └- ✖ fail: Discover Load a new search from the panel
[00:02:40]             │      Error: retry.tryForTime timeout: StaleElementReferenceError: stale element reference: element is not attached to the page document
[00:02:40]             │   (Session info: headless chrome=84.0.4147.135)
[00:02:40]             │     at Object.throwDecodedError (/dev/shm/workspace/kibana/node_modules/selenium-webdriver/lib/error.js:550:15)
[00:02:40]             │     at parseHttpResponse (/dev/shm/workspace/kibana/node_modules/selenium-webdriver/lib/http.js:565:13)
[00:02:40]             │     at Executor.execute (/dev/shm/workspace/kibana/node_modules/selenium-webdriver/lib/http.js:491:26)
[00:02:40]             │     at process._tickCallback (internal/process/next_tick.js:68:7)
[00:02:40]             │       at onFailure (test/common/services/retry/retry_for_success.ts:28:9)
[00:02:40]             │       at retryForSuccess (test/common/services/retry/retry_for_success.ts:68:13)
[00:02:40]             │ 
[00:02:40]             │ 

Stack Trace

Error: retry.tryForTime timeout: StaleElementReferenceError: stale element reference: element is not attached to the page document
  (Session info: headless chrome=84.0.4147.135)
    at Object.throwDecodedError (/dev/shm/workspace/kibana/node_modules/selenium-webdriver/lib/error.js:550:15)
    at parseHttpResponse (/dev/shm/workspace/kibana/node_modules/selenium-webdriver/lib/http.js:565:13)
    at Executor.execute (/dev/shm/workspace/kibana/node_modules/selenium-webdriver/lib/http.js:491:26)
    at process._tickCallback (internal/process/next_tick.js:68:7)
    at onFailure (test/common/services/retry/retry_for_success.ts:28:9)
    at retryForSuccess (test/common/services/retry/retry_for_success.ts:68:13)

Build metrics

@kbn/optimizer bundle module count

id value diff baseline
infra 1096 +3 1093

async chunks size

id value diff baseline
infra 3.8MB ⚠️ +212.3KB 3.6MB

page load bundle size

id value diff baseline
infra 277.3KB +760.0B 276.6KB

distributable file count

id value diff baseline
default 45418 +9 45409

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

@afgomez afgomez merged commit 203f256 into elastic:master Sep 7, 2020
@afgomez afgomez deleted the 75650-log-stream-shared branch September 7, 2020 14:08
@afgomez
Copy link
Contributor Author

afgomez commented Sep 7, 2020

Thanks for the review @jasonrhodes! I'll answer to your feedback here

This separated from the context of the Logs UI, I'm not sure if the chosen columns for the source configuration are a great idea. Maybe this should just be timestamp and message by default?

I think for consistency the default should be the same as in the logs UI. I do think that there's value in letting users specify what columns they want, but is not that easy so we decided to postpone it for now.

It also feels a bit strange that I can't interact with the message to learn more about it at all. I think clicking on the log line should take you to the Logs UI but at the very least some kind of link to the Logs UI somewhere may be good, either clicking the log line, using the actions popover menu, or we let APM and other users of this shared plugin handle this on their own, e.g. one single "view in Logs UI" link at the top of the tab content here

I think it makes sense to allow consumers to specify actions, but I'm not sure how I feel about adding default actions.

For the link to the logs UI, I would prefer to have it separate. That way consumers can decide where in their UI makes sense to link to the logs UI and how (maybe with a extended time range, different filters, etc).

We can export a helper to generate the URLs or a "View in logs" component to streamline the process.

jloleysens added a commit to jloleysens/kibana that referenced this pull request Sep 8, 2020
…' of github.com:jloleysens/kibana into ilm/fix/pre-existing-policy-with-no-existing-repository

* 'ilm/fix/pre-existing-policy-with-no-existing-repository' of github.com:jloleysens/kibana:
  fix empty string in selected indices (elastic#76855)
  [Security Solution] Refactor OverviewHost and OverviewNetwork to use Search Strategy (elastic#76409)
  Use Search API in Timelion (sync) (elastic#75115)
  [telemetry] expose getIsOptedIn function in plugin start contract (elastic#75143)
  [ILM] Clean up remaining js files and any typings (elastic#76803)
  [Logs UI] Shared `<LogStream />` component (elastic#76262)
  [Security Solution] Add unit test for all hosts (elastic#76752)
  [Security Solution] Add unit test for authentications search strategy (elastic#76665)
  Do not apply search source data for tsvb (elastic#75137)
  [Security Solution] Refactor NetworkDns to use Search Strategy (elastic#76250)
  [SECURITY SOLUTION] Adds 'cypress:open-as-ci' command (elastic#76125)
  [Logs UI] Update alert executor tests (elastic#75764)
  [Functional] Unskip vega tests and fix flakiness (elastic#76600)
  [Data] Query String Input accepts classname prop (elastic#76848)
  [ML] Swim lane pagination for viewing by job id (elastic#76847)
  [Security Solution] Refactor MatrixHistogram to use Search Strategy (elastic#76603)
  [APM] Use the outcome field to calculate the transaction error rate chart (elastic#75528)
  [APM] Use observer.hostname instead of observer.name (elastic#76074)
  Legacy logging: fix remoteAddress being duplicated in userAgent field (elastic#76751)
jloleysens added a commit to jloleysens/kibana that referenced this pull request Sep 8, 2020
…s-for-710

* 'master' of github.com:elastic/kibana:
  [Search] Use async es client endpoints (elastic#76872)
  fix empty string in selected indices (elastic#76855)
  [Security Solution] Refactor OverviewHost and OverviewNetwork to use Search Strategy (elastic#76409)
  Use Search API in Timelion (sync) (elastic#75115)
  [telemetry] expose getIsOptedIn function in plugin start contract (elastic#75143)
  [ILM] Clean up remaining js files and any typings (elastic#76803)
  [Logs UI] Shared `<LogStream />` component (elastic#76262)
  [Security Solution] Add unit test for all hosts (elastic#76752)
  [Security Solution] Add unit test for authentications search strategy (elastic#76665)
  Do not apply search source data for tsvb (elastic#75137)
  [Security Solution] Refactor NetworkDns to use Search Strategy (elastic#76250)
  [SECURITY SOLUTION] Adds 'cypress:open-as-ci' command (elastic#76125)
  [Logs UI] Update alert executor tests (elastic#75764)
  [Functional] Unskip vega tests and fix flakiness (elastic#76600)
  [Data] Query String Input accepts classname prop (elastic#76848)
  [ML] Swim lane pagination for viewing by job id (elastic#76847)
  [Security Solution] Refactor MatrixHistogram to use Search Strategy (elastic#76603)
  [APM] Use the outcome field to calculate the transaction error rate chart (elastic#75528)
  [APM] Use observer.hostname instead of observer.name (elastic#76074)
  Legacy logging: fix remoteAddress being duplicated in userAgent field (elastic#76751)

# Conflicts:
#	x-pack/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.tsx
#	x-pack/plugins/index_lifecycle_management/common/types/index.ts
#	x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/node_allocation.tsx
#	x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.tsx
#	x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/phases/warm_phase.tsx
#	x-pack/plugins/index_lifecycle_management/public/application/services/api.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature:Logs UI Logs UI feature release_note:skip Skip the PR/issue when compiling release notes Team:APM All issues that need APM UI Team support Team:Infra Monitoring UI - DEPRECATED DEPRECATED - Label for the Infra Monitoring UI team. Use Team:obs-ux-infra_services v7.10.0 v8.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement embeddable <LogStream /> component
7 participants