Log organization_id in integration workers and services

What does this MR do and why?

Adds gl_organization_id to the integration logs, so cross-organization problems are easier to trace.

  • Integrations::ExecuteWorker: the done-log line now includes the organization.
  • Integrations::UpdateService: logs one line per update (success or failure).
  • Integrations::PropagateService: logs a start and a finish line per run.
  • Integrations::Loggable#build_message: now includes the organization, so every log_info, log_error and log_exception call on an integration gets it too.

Only instance-level integrations store organization_id. Group and project integrations get it from their parent, through a new Integrations::Loggable#organization_id_for_logging helper.

The field uses Labkit::Fields::GL_ORGANIZATION_ID. The plain organization_id name is deprecated in Labkit. The new service logs use build_structured_payload_labkit.

No attribute values are logged, since they can hold secrets.

Validation steps

  1. In a terminal, watch the log: tail -f log/integrations_json.log
  2. Then in rails c:
require 'sidekiq/testing'
Sidekiq::Testing.fake!   # stops propagation jobs actually running

# Pick existing records instead of creating new ones (or create new ones if needed)

p_int = Integration.where.not(project_id: nil).first
g_int = Integration.where.not(group_id: nil).first   # may be nil on a fresh GDK

# build_message / log_info: expect "gl_organization_id" in the log tail

p_int.log_info('console check')
p_int.organization_id_for_logging   # equals p_int.project.organization_id

# UpdateService: expect "Integration updated" in the log tail

Integrations::UpdateService.new(
  current_user: User.first, integration: p_int, attributes: { active: p_int.active }
).execute

# PropagateService: expect "started" and "finished" lines with integration_level "group"

Integrations::PropagateService.new(g_int).execute if g_int

# ExecuteWorker: this logs to the Sidekiq done-line, not integrations_json.log,
# so inspect the extra metadata directly

w = Integrations::ExecuteWorker.new
w.perform(p_int.id, {})
w.logging_extras

=> {"extra.integrations_execute_worker.integration_class"=>
  "Integrations::MockMonitoring",
 "extra.integrations_execute_worker.gl_organization_id"=>1}

Log output

{"severity":"INFO","time":"2026-10-05T11:01:01.252Z","integration_class":"Integrations::MockMonitoring","integration_id":1,"project_id":4,"project_path":"gnuwget/Wget2","gl_organization_id":1,"message":"console check"}


{"severity":"INFO","time":"2026-10-05T11:01:27.624Z","class_name":"Integrations::UpdateService","message":"Integration updated","integration_id":1,"integration_class":"Integrations::MockMonitoring","gl_organization_id":1}

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Related to #631292 (closed)

Merge request reports

Loading
Loading