Skip to content

Adding OpenTelemetry and provide traces - #4598

Draft
FredPraca wants to merge 8 commits into
LycheeOrg:masterfrom
FredPraca:feat/telemetry
Draft

Adding OpenTelemetry and provide traces#4598
FredPraca wants to merge 8 commits into
LycheeOrg:masterfrom
FredPraca:feat/telemetry

Conversation

@FredPraca

Copy link
Copy Markdown
Contributor

This PR provides OpenTelemetry functionalities to Lychee.
It allows to send logs, metrics and traces to any OpenTelemetry collector.

It has been tested with Loki, Tempo and Mimir for logs, traces and metrics respectively.

The best way to test it is to use Grafana Alloy as a collector and then dispatch to other tools such as the ones mentioned before.

It requires to install the opentelemetry extension as described here.

The following environment variables may be set:

OTEL_PHP_AUTOLOAD_ENABLED=true
OTEL_TRACES_EXPORTER=otlp
OTEL_METRICS_EXPORTER=none
OTEL_LOGS_EXPORTER=console
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318/
OTEL_SERVICE_NAME=lychee
OTEL_PHP_DISABLED_INSTRUMENTATIONS=pdo

Please note that exporters may be set to console or otlp. When using otlp, you may provide the OTEL_EXPORTER_OTLP_ENDPOINT variable to point to an OTLP collector. Here http://localhost:4318/ corresponds to a local setup for Tempo.

Moreover, OTEL_PHP_DISABLED_INSTRUMENTATIONS allows to disable some instrumentation. Here, I disabled pdo to avoid having all SQL operations in my traces. Currently, only laravel, guzzle and pdo are configured.

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 16a236de-2ad6-4c5c-948e-47d5cb319cff

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@socket-security

socket-security Bot commented Aug 8, 2026

Copy link
Copy Markdown

@ildyria

ildyria commented Aug 11, 2026

Copy link
Copy Markdown
Member

@FredPraca I am not able to push changes to enable the CICD missing extension. Would you mind ticking the box or modify the php-test and php-dist yaml files :)

@FredPraca

FredPraca commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

@FredPraca I am not able to push changes to enable the CICD missing extension. Would you mind ticking the box or modify the php-test and php-dist yaml files :)

The Allow edits by maintainers is checked so I don't know why you're unable to change it.
I didn't have time to dig into the tests and dist things. I'll take a look at it.

The main problem is that opentelemetry extensions is not a standard one. The process is described here but I don't know if I can do something like this Github actions.
Moreover, I don't know how to test without committing and pushing to GH.

@FredPraca

Copy link
Copy Markdown
Contributor Author

I'm also trying to include a package providing metrics about PHP runtime, especially RAM but I face a problem with initialization order.

}
$trace = app(TraceService::class);

return $trace->traceMethod('photo.load_file_metadata', function () use ($state, $next) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think here it might be cleaner to rename
handle(InitDTO $state, \Closure $next): InitDTO
into
_handle(InitDTO $state, \Closure $next): InitDTO

and then have

public function handle(InitDTO $state, \Closure $next): InitDTO
{
		$trace = app(TraceService::class);
		return $trace->traceMethod('photo.load_file_metadata',
			fn () => $this->_handle($state, $next)); 
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

or indeed, rename into execute() instead of _handle :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

In fact, I started with it for telemetry tests and switched to Standalone pipes which were more promising in terms of trace and memory investigations.
If the part on Standalone pipes was considered well done by the main maintainer of Lychee, I was considering using the same pattern as for standalone pipes :)

We could also generalize this "pattern" to other types of pipes.
The drawback is that it will generate a lot of traces 😄

Comment on lines +27 to +29
return $trace->traceMethod($this->getSpanName(), function () use ($state, $next) {
return $this->execute($state, $next);
});

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
return $trace->traceMethod($this->getSpanName(), function () use ($state, $next) {
return $this->execute($state, $next);
});
return $trace->traceMethod($this->getSpanName(), fn () => $this->execute($state, $next));

You can use the arrow functions instead to avoid the use (...)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ahaha, I am not really a PHP dev as you may have seen :)

// Skip if the caller explicitly provided a title at upload time (FR-041-06).
// User-supplied titles take precedence and must not be overwritten by renamer rules.
if ($state->title !== null) {
Log::info('Photo has a title, we don\'t rename it, skipping');

Copy link
Copy Markdown
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 necessary :)

@FredPraca FredPraca Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Maybe at debug level or even trace ?

@FredPraca FredPraca Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ahaha, there is no trace :)
Notice maybe ?


// Skip if not enabled.
if (!$state->shall_rename_photo_title) {
Log::info('renaming not necessary, skipping');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

idem :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Same as before

public function handle(StandaloneDTO $state, \Closure $next): StandaloneDTO
protected function execute(StandaloneDTO $state, \Closure $next): StandaloneDTO
{
Log::info('Computing original checksum');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Instead of info maybe we want to keep those at debug level?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

As it is standard flow, yes, debug is enough

{
$meta = $request->meta();
$file = new UploadedFile($request->uploaded_file_chunk());
// Reset max memory usage before measuring

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should this be in a middleware instead?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

See here some ideas I had:
#4577

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'll read it as I'm not aware of all Laravel possibilities and especially with the middleware and so on stuff.

Besides this, I was not super happy with this way of tracing memory usage.
So we might maybe leave the trace without performing these memory features and keep tracing telemetry for what it is, following calls durations.

Your way of profiling might be a better way that we may merge with telemetry afterwards.

What do you think ?

$final->delete();
$processable_file->close();
// End of work-around
return $this->trace->traceMethod('photo.process', function () use ($verify,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It is important to note that here you are measuring either of two cases:
if the processing is done sync, you will have the full processing memory, but if it is dispatch to a queue you won't see the computation anymore.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, I figured it out and maybe we will use traces to provide time consumption instead of memory consumption.
That's the reason why I would like to import the php metrics module and experiment around it.

@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.65672% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.00%. Comparing base (0d856a2) to head (282c473).
⚠️ Report is 3 commits behind head on master.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants