jaegertracing / jaeger-ui

Web UI for Jaeger
http://jaegertracing.io/
Apache License 2.0
1.11k stars 475 forks source link

Make jaeger-ui installable by npm #248

Closed aljesusg closed 5 years ago

aljesusg commented 5 years ago

Requirement - what kind of business use case are you trying to solve?

I am from Jaeger team and Kiali in RH. Kiali is the UI for Istio, we are currently integrating the jaeger with some external links.

We want to collect the information provided by jaeger and the information of Kiali and show the relation to improve the tracing and observability of the service mesh so for example if we can show the component of the traceresults with our information, will be useful for the user.

Actually we have an external link to the full UI jaeger in tabs, our idea is contribute/improve the component to import them to our project from the jaeger UI for example the last 10 traces in our view using the component TraceTimelineViewer.

Problem - what in Jaeger blocks you from solving the requirement?

We can't integrate components of Jaeger UI So we are using external links to the Jaeger-UI in a new tabs.

Proposal - what do you suggest to solve the problem or improve the existing situation?

  1. Change the package.json to publish the releases
  2. Compile al build the components to export them
  3. Improve/contribute in the component

cc @jpkrohling @objectiser

yurishkuro commented 5 years ago

@tiffon thoughts?

mtho11 commented 5 years ago

It would be great to see these components published to npm so that others could use the jaeger-ui components directly in applications.

saminzadeh commented 5 years ago

It would be great to see these components published to npm so that others could use the jaeger-ui components directly in applications.

+1. This would be nice as a component library.

A few initial ideas on how to approach this:

import { TraceViewTimeline, TraceDAG } from '@jaegertracing/ui-kit';
import trace from './samples/my-jaeger-trace.json'

<TraceViewTimeline trace={trace} />
<TraceDAG trace={trace} customOverrides={...} />
import { 
  TraceViewTimeline, 
  JaegerClient, 
  JaegerProvider, 
  JaegerRenderer 
} from '@jaegertracing/ui-kit';

// Init Jaeger client
const jaegerClient = new JaegerClient("http://my.jaeger.host.com")

const App = ()=> (
  <JaegerProvider jaegerClient={jaegerClient}>
    <Layout>
      <h2>My Trace</h2>

      // Predefined component
      <TraceViewTimeline traceId="e29208c2-bc23-11e8-a355-529269fb1459" />

      // Custom components via Render Props
      <JaegerRenderer traceId="e29208c2-bc23-11e8-a355-529269fb1459">
        {({ trace, loading }) => {
          if(loading) {
            return "Loading trace..."
          }

          return (
            //... do custom logic with trace here
          )
        }}
      </ JaegerRenderer>
    </Layout>
  </JaegerProvider>
)

ReactDOM.render(<App/>, document.getElementById('root'))
tiffon commented 5 years ago

@aljesusg – Thanks for creating this ticket! This topic is actually something that is coming up for us, internally, as well.

The two main avenues for integration we've been exploring are either publishing React components or using iframes to create an embedded experience.

One drawback for wholesale publishing the React components, in their current form, is that when all of the components become public, their combined API becomes the API contract. That's a massive contract. So much so it would essentially become impossible to maintain backwards compatibility while making any significant changes to the UI.

So, if we go down the path of publishing React components, I think the approach outlined by @saminzadeh would make the API contract more manageable.

But, it'd be nice to get a sense of the current use-cases and to see what, concretely, needs to be supported.

Can you elaborate a bit on the types of integrations you have in mind?

saminzadeh commented 5 years ago

One drawback for wholesale publishing the React components, in their current form, is that when all of the components become public, their combined API becomes the API contract. That's a massive contract.

@tiffon I agree with you here. The components in their current form were not built with a public API in mind and it could be a maintenance burden if we published them today.

yurishkuro commented 5 years ago

Perhaps I'm missing something, but why do we need to publish ALL components instead of just the ones on the highest level?

aljesusg commented 5 years ago

But, it'd be nice to get a sense of the current use-cases and to see what, concretely, needs to be supported.

Can you elaborate a bit on the types of integrations you have in mind?

@tiffon we want to integrate the trace search UI and allow navigation to the trace instance view, allowing the integrating app to supplied some initial search criteria. I think these components are SearchResults of a service. Thanks

yurishkuro commented 5 years ago

@aljesusg I see you're creating PRs, but we have not agreed to what approach we want to take. I completely agree with @tiffon that we do not want to explore the public API surface of React components. If we still want to publish some embeddable components, I would prefer to design them from scratch, ie define a narrow interface and implement it with the existing components treating the latter as internal/private. It will allow us to change them freely without affecting the public facade.

Can we start with defining the API? Or even better, listing your specific requirements for embedding. Maybe they can be satisfied with embedding an iframe.

aljesusg commented 5 years ago

Yes @yurishkuro, sorry I saw later that you used nbw to create the plexus package, so I learned about and I redo the package, my idea was help you in this. About your comment I agree with you so I'll wait until your decision, It will be cleaner if it is done separately in another repo.

tiffon commented 5 years ago

@aljesusg, if we take a step back and evaluate the intent of this ticket, it implies a paradigm shift for Jaeger.

At the heart of this ticket is establishing a new objective for Jaeger: empowering other product experiences through integrations with Jaeger UI.

Empowering other product experiences through integrations can either be in addition to providing an end-user experience (e.g. the current Jaeger UI), or it can supplant the current UI and integrations can become the sole focus of Jaeger UI.

Mapbox is an eample of focusing almost exclusively on integrations with other products.

Searchkit (searchkit.co, GitHub), which @saminzadeh mentioned, is an interesting second example. Searchkit is a set of UI components intended solely to empower other product experiences.

The approaches exemplified by Mapbox and Searchkit is not quite right for Jaeger UI – I don't think it's practical to focus only on integrations; Jaeger needs an end-user experience in order to meet the basic needs of a distributed tracing solution – people need to be able to consume traces.

Google Maps is an example of providing both an end-user experience and empowering other product experiences through integrations.

Google Maps has a highly effective end-user experience (IMO) and integrations with Google Maps are all over the place (over 1,000,000 websites as of 2013). And, we can safely say integrations are also a first-class aspect of the product as the Google Maps API dates to four months after the product's launch in 2005.

One of the fundamental considerations for integrations is the API contract. The downside of publishing the current UI components, wholesale, is that it would create an API contract that is impossible to maintain. This is because the underlying implementation and the API contract are one and the same.

Using Google Maps as an exemplar, we can take a look at their approach for decoupling their API contract from the underlying implementation of the product.

Google Maps has a massive API, but it's very abstracted from the underlying implementation. They provide a JavaScript SDK (among others) which avails JS classes to create and manage map views. The JS classes generate and interface with an iframe, but the developer is not concerned with the iframe; they work only with the JS classes provided by the SDK.

So far, I'd say this approach would be a good fit for Jaeger UI.

A brief look at two Google Maps APIs

Maps has a number of APIs (overview), three are relevant to JS:

Embed API

The embed API is an iframe based approach using query parameters to customize the view. The ability to customize is pretty limited:

Code to embed driving directions:

<iframe
    width="600" height="450" frameborder="0" style="border:0"
    src="https://www.google.com/maps/embed/v1/directions?origin=1400%20Broadway%2C%20New%20York%2C%20NY&destination=636%20West%2028th%20Street%2C%20New%20York%2C%20NY&key=YOUR_API_KEY"
    allowfullscreen
></iframe>

The crux of the embed approach is "create it and forget about it" – You pass in query parameters and you're done.

JavaScript SDK

The JS SDK is very extensive (looks like 109 symbols) with a wide variety of customization options. Users can add markers, clusters of markers, generate a heatmap, use something called Fusion Tables, draw on the map, etc. The API reference.

The SDK is a JavaScript file, hosted on Google servers, which is included in the page via a <script> tag. It takes a few query parameters which are used by the file to hook into the page, e.g. &callback=initMap where initMap is a JS function in the global scope. The file also populates JS classes into the global scope, name-spaced on window.google.maps.*. These classes can then be used to customize the creation and management of the map view.

The JS SDK generates and interfaces with an iframe. This is nice because the consumer can create the map and then later modify and manipulate it, through the SDK API.

A code snippet using this API:

  <body>
    <div id="map"></div>
    <script>
      var map;
      function initMap() {
        map = new google.maps.Map(document.getElementById('map'), {
          zoom: 2,
          center: {lat: -33.865427, lng: 151.196123},
          mapTypeId: 'terrain'
        });

        // Create a <script> tag and set the USGS URL as the source.
        var script = document.createElement('script');

        // This example uses a local copy of the GeoJSON stored at
        // http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_week.geojsonp
        script.src = 'https://developers.google.com/maps/documentation/javascript/examples/json/earthquake_GeoJSONP.js';
        document.getElementsByTagName('head')[0].appendChild(script);

      }

      function eqfeed_callback(results) {
        var heatmapData = [];
        for (var i = 0; i < results.features.length; i++) {
          var coords = results.features[i].geometry.coordinates;
          var latLng = new google.maps.LatLng(coords[1], coords[0]);
          heatmapData.push(latLng);
        }
        var heatmap = new google.maps.visualization.HeatmapLayer({
          data: heatmapData,
          dissipating: false,
          map: map
        });
      }
    </script>
    <script async defer
    src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap">
    </script>
  </body>
jpkrohling commented 5 years ago

I think GitLab is also planning on doing something with Jaeger's UI, they may want to get aware of this issue :)

/cc @SuperQ

lambertjosh commented 5 years ago

Thanks @jpkrohling for the heads up on this. We've been looking for ways to best integrate the Jaeger UI, similar to Kiali, and this would be a great help.

I'd vote for the API route, as it would be more broadly adoptable than a React component. For example at GitLab we use Vue.

aljesusg commented 5 years ago

I think that we can close this in favor #279