Packages
sentry
10.6.0
13.3.0
13.2.0
13.1.0
13.0.1
13.0.0
12.0.3
12.0.2
12.0.1
12.0.0
11.0.4
11.0.3
11.0.2
11.0.1
11.0.0
10.10.0
10.9.0
10.8.1
10.8.0
10.7.1
10.7.0
10.6.2
10.6.1
10.6.0
10.5.0
10.4.0
10.3.0
10.2.1
10.2.0
10.2.0-rc.2
10.2.0-rc.1
10.1.0
10.0.3
10.0.2
10.0.1
10.0.0
9.1.0
9.0.0
8.1.0
8.0.6
8.0.5
8.0.4
8.0.3
8.0.2
8.0.1
8.0.0
8.0.0-rc.2
8.0.0-rc.1
8.0.0-rc.0
retired
7.2.5
7.2.4
7.2.3
7.2.2
7.2.1
7.2.0
7.1.0
7.0.6
7.0.5
7.0.4
7.0.3
7.0.2
7.0.1
7.0.0
6.4.2
6.4.1
6.4.0
6.3.0
6.2.1
6.2.0
6.1.0
6.0.5
6.0.4
6.0.3
6.0.2
6.0.1
6.0.0
5.0.1
5.0.0
4.0.3
4.0.2
4.0.1
4.0.0
3.0.0
2.2.0
2.1.0
2.0.2
2.0.1
2.0.0
1.1.2
1.1.1
1.1.0
1.0.0
0.3.2
0.3.1
0.3.0
0.2.0
0.1.3
0.1.2
0.1.1
0.1.0
The Official Elixir client for Sentry
Current section
Files
Jump to
Current section
Files
lib/sentry/integrations/quantum/cron.ex
defmodule Sentry.Integrations.Quantum.Cron do
@moduledoc false
require Logger
@events [
[:quantum, :job, :start],
[:quantum, :job, :stop],
[:quantum, :job, :exception]
]
@spec attach_telemetry_handler() :: :ok
def attach_telemetry_handler do
_ = :telemetry.attach_many(__MODULE__, @events, &__MODULE__.handle_event/4, :no_config)
:ok
end
@spec handle_event([atom()], term(), term(), :no_config) :: :ok
def handle_event(event, measurements, metadata, _config)
def handle_event(
[:quantum, :job, event],
measurements,
%{job: %mod{schedule: schedule}} = metadata,
_config
)
when event in [:start, :stop, :exception] and mod == Quantum.Job and not is_nil(schedule) do
_ = handle_event(event, measurements, metadata)
:ok
end
def handle_event([:quantum, :job, event], _measurements, _metadata, _config)
when event in [:start, :stop, :exception] do
:ok
end
## Helpers
defp handle_event(:start, _measurements, metadata) do
if opts = check_in_opts(metadata) do
opts
|> Keyword.merge(status: :in_progress)
|> Sentry.capture_check_in()
end
end
defp handle_event(:stop, measurements, metadata) do
if opts = check_in_opts(metadata) do
opts
|> Keyword.merge(status: :ok, duration: duration_in_seconds(measurements))
|> Sentry.capture_check_in()
end
end
defp handle_event(:exception, measurements, metadata) do
if opts = check_in_opts(metadata) do
opts
|> Keyword.merge(status: :error, duration: duration_in_seconds(measurements))
|> Sentry.capture_check_in()
end
end
defp check_in_opts(%{job: job} = metadata) when is_struct(job, Quantum.Job) do
if schedule_opts = schedule_opts(job) do
id = metadata.telemetry_span_context |> :erlang.phash2() |> Integer.to_string()
[
check_in_id: "quantum-#{id}",
# This is already a binary.
monitor_slug: "quantum-#{slugify(job.name)}",
monitor_config: [schedule: schedule_opts]
]
else
nil
end
end
defp schedule_opts(job) when is_struct(job, Quantum.Job) do
case apply(Crontab.CronExpression.Composer, :compose, [job.schedule]) do
"@hourly" -> [type: :interval, value: 1, unit: :hour]
"@daily" -> [type: :interval, value: 1, unit: :day]
"@weekly" -> [type: :interval, value: 1, unit: :week]
"@monthly" -> [type: :interval, value: 1, unit: :month]
"@yearly" -> [type: :interval, value: 1, unit: :year]
"@annually" -> [type: :interval, value: 1, unit: :year]
"@reboot" -> nil
cron_expr when is_binary(cron_expr) -> [type: :crontab, value: cron_expr]
_other -> nil
end
end
defp duration_in_seconds(%{duration: duration} = _measurements) do
duration
|> System.convert_time_unit(:native, :millisecond)
|> Kernel./(1000)
end
defp slugify(job_name) when is_reference(job_name) do
Logger.error(
"""
Sentry cannot report Quantum cron jobs correctly if they don't have a :name set up, and \
will just report them as "quantum-generic-job".\
""",
event_source: :logger
)
"generic-job"
end
defp slugify(job_name) when is_atom(job_name) do
case Atom.to_string(job_name) do
"Elixir." <> module -> module |> Macro.underscore() |> slugify()
other -> slugify(other)
end
end
defp slugify(job_name) when is_binary(job_name) do
job_name
|> String.downcase()
|> String.replace(["_", "#", "<", ">", ".", " ", "/"], "-")
|> String.slice(0, 50)
end
end