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

Add tracing to jaeger-ui package #1627

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

psk001
Copy link

@psk001 psk001 commented Aug 1, 2023

Which problem is this PR solving?

Resolves issue 2307

Short description of the changes

Adds tracing module, which handles trace management and connection to jaeger all-in-one

Signed-off-by: puspak <puspak9208@gmail.com>
Copy link
Member

@yurishkuro yurishkuro left a comment

Choose a reason for hiding this comment

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

please provide description of the testing (commands to run, screenshots)

packages/jaeger-ui/src/tracing.jsx Outdated Show resolved Hide resolved
packages/jaeger-ui/src/tracing.jsx Outdated Show resolved Hide resolved
packages/jaeger-ui/src/tracing.jsx Outdated Show resolved Hide resolved
const consoleExporter = new ConsoleSpanExporter();

const collectorExporter = new OTLPTraceExporter({
url: `${process.env.OTEL_HOST}:4318/v1/traces`,
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this is how we want to do that. The binary that runs Jaeger UI (all-in-one or jaeger-query) has an internal connectivity to Jaeger backend and knows where to send the traces (since it's using OTEL SDK internally it can be configured in a standard way). Establishing a direct connection from the browser requires additional configuration, CORS settings, etc. I don't know what OTEL JS recommends here, but if I were designing it I would create an endpoint in the query API (which the UI already talks to) and submit the spans there. Then the endpoint could act as a proxy and forward the spans to the collector location.

Copy link
Author

Choose a reason for hiding this comment

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

Opentelemetry tells to add tracing imports to index.html like

<script type="module" src="tracing.ts"></script>

Establishing a direct connection from the browser requires additional configuration, CORS settings, etc.

Otel asks to add this in collector config

receivers:
  otlp:
    protocols:
      http:
        cors:
          allowed_origins: ["*"] #required urls
          allowed_headers: ["*"] #required headers

Going through Otel docs and also the API way as suggested.

@yurishkuro
Copy link
Member

@psk001 are you planning to address the comments, or should I close this PR?

@psk001
Copy link
Author

psk001 commented Aug 25, 2023

I have been working on the API route as you suggested

in jaeger query, I added another API endpoint
as

aH.handleFunc(router, aH.sendToCollector, "/collector").Methods(http.MethodPost)
func (aH *APIHandler) sendToCollector(w http.ResponseWriter, r *http.Request) {

	aH.logger.Debug("Into collect trace controller")

	// aH.logger.Debug("trace received", zap.Stringer("traceId", traceID))

	// Read the request body
	bodyBytes, err := io.ReadAll(r.Body)
	if err != nil {
		aH.logger.Error("error reading request body", zap.Error(err))
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}

	// Create a new request to the collector
	collectorURL := "<collector-url>"
	collectorReq, err := http.NewRequest("POST", collectorURL, bytes.NewReader(bodyBytes))
	if err != nil {
		aH.logger.Error("error creating collector request", zap.Error(err))
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}

	// Set headers if needed
	// collectorReq.Header.Set("Authorization", "Bearer YOUR_ACCESS_TOKEN")

	// Make the request to the collector
	client := http.DefaultClient
	collectorResp, err := client.Do(collectorReq)
	if err != nil {
		aH.logger.Error("error sending trace to collector", zap.Error(err))
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}
	defer collectorResp.Body.Close()

	// Check the collector response and handle as needed
	if collectorResp.StatusCode != http.StatusOK {
		aH.logger.Error("collector returned non-OK status", zap.Int("status", collectorResp.StatusCode))
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}

	// Optionally read and log the collector response body
	// collectorRespBytes, _ := io.ReadAll(collectorResp.Body)
	// aH.logger.Debug("collector response", zap.String("body", string(collectorRespBytes)))

	aH.logger.Debug("returning from trace controller")
	aH.writeJSON(w, r, r.Body)
}

then in jaeger-ui , added tracing file with config as

import {
  BatchSpanProcessor,
  WebTracerProvider,
} from '@opentelemetry/sdk-trace-web';
import { getWebAutoInstrumentations } from '@opentelemetry/auto-instrumentations-web'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { DocumentLoadInstrumentation } from '@opentelemetry/instrumentation-document-load';
import { Resource } from '@opentelemetry/resources'
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'

import prefixUrl from './utils/prefix-url';
export const DEFAULT_API_ROOT = prefixUrl('/api/');

const collectorOptions = {
  url: `${DEFAULT_API_ROOT}collector`,
  headers: {}, // an optional object containing custom headers to be sent with each request
  concurrencyLimit: 10, // an optional limit on pending requests
};

const provider = new WebTracerProvider({
  resource: new Resource({
    [SemanticResourceAttributes.SERVICE_NAME]: 'Jaeger UI' || process.env.REACT_APP_NAME
  })
});
const exporter = new OTLPTraceExporter(collectorOptions);
provider.addSpanProcessor(new BatchSpanProcessor(exporter));

registerInstrumentations({
  instrumentations: [
    getWebAutoInstrumentations({
      '@opentelemetry/instrumentation-xml-http-request': {
        clearTimingResources: true,
      },
    }),
    new DocumentLoadInstrumentation()
  ],
});

provider.register();

next, used it in the index.html

<body>
    <div id="jaeger-ui-root"></div>
    <!--
      This file is the main entry point for the Jaeger UI application.
      See https://vitejs.dev/guide/#index-html-and-project-root for more information
      on how asset references are managed by the build system.
    -->
    <script type="module" src="/src/index.jsx"></script>
</body>

With the above changes, Im getting the traces in the at the query backend , but the Im unable to generate a different collector so as to display those traces in ui.

@psk001
Copy link
Author

psk001 commented Aug 25, 2023

I tried building Otel collector locally but was unable to reach the UI , any leads on how to create a collector or UI would be really helpful

@yurishkuro
Copy link
Member

I think there are two options for exporting spans from the UI

  1. sending them to a real collector that is different from query/api
  2. sending them to query/api where we can probably mount the standard OTLP receiver

@psk001
Copy link
Author

psk001 commented Aug 25, 2023

The first choice is an easy one, we can replace the url in collector options in tracing config by the collector url and it will be done.

The second one requires changes in query api as well involving the jaeger backend.

Should I go ahead and implement the first option?

@yurishkuro
Copy link
Member

Should I go ahead and implement the first option?

yes

Signed-off-by: puspak <puspak9208@gmail.com>
@psk001
Copy link
Author

psk001 commented Aug 26, 2023

Using elastic APM for trace viewing

Use following configuration

docker compose configuration

version: "2"
services:
  collector:
    image: otel/opentelemetry-collector:latest
    command: ["--config=/otel-collector-config.yaml"]
    volumes:
      - './otel-collector-config.yaml:/otel-collector-config.yaml'
    ports:
      - "4318:4318"
    depends_on:
      - jaeger-all-in-one
   # Jaeger
  jaeger-all-in-one:
    hostname: jaeger-all-in-one
    image: jaegertracing/all-in-one:latest
    ports:
      - "16685"
      - "16686:16686"
      - "14268:14268"
      - "14250:14250"

openTelemetry collector configuration

receivers:
  otlp:
    protocols:
      http:
        cors:
          allowed_origins: ["*"]
          allowed_headers: ["*"]
exporters:
  logging:
    verbosity: Detailed
  otlp/elastic:
    endpoint: "<url>.apm.us-central1.gcp.cloud.es.io:443"
    compression: none
    headers:
      Authorization: "Bearer <token>"
  jaeger:
    endpoint: jaeger-all-in-one:14250
    tls:
      insecure: true
processors:
  batch:
service:
  telemetry:
    logs:
      level: "debug"
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [logging, jaeger, otlp/elastic]
      processors: [batch]

run docker-compose up and then start the Jaeger-UI . Perform actions like button click, search etc,

As viewed in elastic APM
image

@yurishkuro
Copy link
Member

Using elastic APM for trace viewing

why, instead of Jaeger?

@psk001
Copy link
Author

psk001 commented Aug 26, 2023

It shows in jaeger as well as

image

with general otel collector config

receivers:
  otlp:
    protocols:
      http:
        cors:
          allowed_origins: ["*"]
          allowed_headers: ["*"]
exporters:
  logging:
    verbosity: Detailed
  jaeger:
    endpoint: jaeger-all-in-one:14250
    tls:
      insecure: true
processors:
  batch:
service:
  telemetry:
    logs:
      level: "debug"
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [logging, jaeger]
      processors: [batch]

Copy link
Contributor

Choose a reason for hiding this comment

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

Why this addition ?
Is Jaeger-ui not using yarn.lock instead ?

Copy link
Member

Choose a reason for hiding this comment

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

agreed, please remove this file

Copy link
Member

Choose a reason for hiding this comment

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

also, not sure if all changes to yarn.lock are required. Please revert, merge main, and add dependencies using yarn add ...

Copy link
Author

Choose a reason for hiding this comment

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

Got it

Copy link
Contributor

Choose a reason for hiding this comment

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

Why is it a .js and not .ts instead ?

@@ -46,6 +46,14 @@
},
"dependencies": {
"@jaegertracing/plexus": "0.2.0",
"@opentelemetry/api": "^1.4.1",
"@opentelemetry/auto-instrumentations-web": "^0.33.0",
"@opentelemetry/context-zone": "^1.15.1",
Copy link
Member

Choose a reason for hiding this comment

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

don't see this being used

"@opentelemetry/api": "^1.4.1",
"@opentelemetry/auto-instrumentations-web": "^0.33.0",
"@opentelemetry/context-zone": "^1.15.1",
"@opentelemetry/exporter-collector": "^0.25.0",
Copy link
Member

Choose a reason for hiding this comment

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

nor this

Copy link
Author

Choose a reason for hiding this comment

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

These are to be added for better tracing, working on it

],
});

provider.register();
Copy link
Member

Choose a reason for hiding this comment

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

can this be grouped with other provider statements?

Copy link
Author

Choose a reason for hiding this comment

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

Checking if it could be done

[SemanticResourceAttributes.SERVICE_NAME]: 'Jaeger UI' || process.env.REACT_APP_NAME
})
});
const exporter = new OTLPTraceExporter(collectorOptions);
Copy link
Member

Choose a reason for hiding this comment

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

this meant that:
a. the exporter ALWAYS going send data to 127.0.0.1, which doesn't make sense in production environments
b. there is no way to disable the tracing

I think what we need is an option in the UI configuration that would contain exporter configuration. If that option is empty, do not enable tracing at all.

Copy link
Author

Choose a reason for hiding this comment

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

a. Url from env can be added to address it
b. The script import in index.html can be dynamically added depending on the configuration, which will enable or disable the tracing, working on its implementation

Copy link
Member

Choose a reason for hiding this comment

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

agreed, please remove this file

Comment on lines +12 to +13
import prefixUrl from './utils/prefix-url';
export const DEFAULT_API_ROOT = prefixUrl('/api/');
Copy link
Member

Choose a reason for hiding this comment

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

what are these for? Don't see the being used

Copy link
Member

Choose a reason for hiding this comment

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

also, not sure if all changes to yarn.lock are required. Please revert, merge main, and add dependencies using yarn add ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Fun task]: Add React tracing
3 participants