Packages
new_relic_agent
1.35.0
1.40.3
1.40.2
1.40.1
1.40.0
1.39.0
1.38.0
1.37.0
1.36.0
1.35.0
1.34.0
1.33.0
1.32.0
1.31.1
1.31.0
1.30.0
1.29.0
1.28.0
1.27.8
1.27.7
1.27.6
1.27.5
1.27.4
1.27.3
1.27.2
1.27.1
1.27.0
1.26.0
1.25.3
1.25.2
1.25.1
1.25.0
1.24.5
1.24.4
1.24.3
1.24.2
1.24.1
1.24.0
1.24.0-rc.10
1.24.0-rc.9
1.24.0-rc.8
1.24.0-rc.7
1.23.6
1.23.5
1.23.4
1.23.3
1.23.2
1.23.1
1.23.0
1.23.0-rc.6
1.23.0-rc.5
1.23.0-rc.4
1.23.0-rc.3
1.23.0-rc.2
1.23.0-rc.1
1.22.6
1.22.5
1.22.4
1.22.3
1.22.2
1.22.1
1.22.0
1.21.2
1.21.1
1.21.0
1.21.0-rc.3
1.21.0-rc.1
1.20.0
1.20.0-rc.1
1.19.7
1.19.6
1.19.5
1.19.4
1.19.3
1.19.2
1.19.1
1.19.0
1.18.5
1.18.4
1.18.3
1.18.2
1.18.1
1.18.0
1.18.0-rc.5
1.18.0-rc.4
1.18.0-rc.2
1.18.0-rc.1
1.17.1
1.17.0
1.17.0-rc.4
1.17.0-rc.3
1.17.0-rc.2
1.17.0-rc.1
1.17.0-rc.0
1.16.7
1.16.6
1.16.5
1.16.4
1.16.3
1.16.2
1.16.1
1.16.0
1.16.0-rc.2
1.16.0-rc.1
1.16.0-rc.0
1.15.0
1.15.0-rc.3
1.15.0-rc.2
1.15.0-rc.1
1.14.0
1.13.1
1.13.0
1.12.0
1.11.0
1.10.2
1.10.1
1.10.0
1.9.12
1.9.11
1.9.10
1.9.9
1.9.8
1.9.7
1.9.6
1.9.5
1.9.4
1.9.3
1.9.2
1.9.1
1.9.0
1.8.0
1.7.0
1.6.2
1.6.1
1.6.0
1.5.0
1.4.0
1.3.2
1.3.1
1.3.0
1.2.1
1.2.0
1.1.0
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
New Relic's Open-Source Elixir Agent
Current section
Files
Jump to
Current section
Files
lib/new_relic/logs_in_context.ex
defmodule NewRelic.LogsInContext do
@moduledoc false
alias NewRelic.Harvest.Collector.AgentRun
alias NewRelic.Harvest.TelemetrySdk
def configure(:direct) do
:logger.add_primary_filter(:nr_logs_in_context, {&primary_filter/2, %{mode: :direct}})
end
def configure(:forwarder) do
:logger.add_primary_filter(:nr_logs_in_context, {&primary_filter/2, %{mode: :forwarder}})
Logger.configure_backend(:console, format: {NewRelic.LogsInContext, :format})
end
def configure(:disabled) do
:skip
end
def configure(unknown) do
NewRelic.log(:error, "Unknown :logs_in_context mode: #{inspect(unknown)}")
:skip
end
defp primary_filter(%{msg: {:string, msg}} = log, %{mode: :direct}) do
[message: IO.iodata_to_binary(msg)]
|> prepare_log(log)
|> TelemetrySdk.Logs.Harvester.report_log()
:ignore
end
defp primary_filter(%{msg: {:report, report}, meta: %{domain: [:elixir]}} = log, %{mode: :direct}) do
report
|> prepare_log(log)
|> TelemetrySdk.Logs.Harvester.report_log()
:ignore
end
defp primary_filter(%{msg: {:string, msg}} = log, %{mode: :forwarder}) do
message =
[message: IO.iodata_to_binary(msg)]
|> prepare_log(log)
|> Map.merge(linking_metadata())
|> NewRelic.JSON.encode!()
%{log | msg: {:string, message}}
end
defp primary_filter(%{msg: {:report, report}, meta: %{domain: [:elixir]}} = log, %{mode: :forwarder}) do
message =
report
|> prepare_log(log)
|> Map.merge(linking_metadata())
|> NewRelic.JSON.encode!()
%{log | msg: {:string, message}}
end
defp primary_filter(_log, _config) do
:ignore
end
defp prepare_log(metadata, log) do
Map.new(metadata)
|> Map.merge(log_metadata(log))
|> Map.merge(custom_metadata(log))
|> Map.merge(tracing_metadata())
end
def format(_level, message, _timestamp, _metadata) when is_binary(message) do
message <> "\n"
end
# Fallback to default formatter for future compatibility with Elixir structured logging
def format(level, message, timestamp, metadata) do
config = Logger.Formatter.compile(nil)
Logger.Formatter.format(config, level, message, timestamp, metadata)
end
defp log_metadata(log) do
{module, function, arity} = log.meta.mfa
%{
timestamp: System.convert_time_unit(log.meta.time, :microsecond, :millisecond),
"log.level": log.level,
"line.number": log.meta.line,
"file.name": log.meta.file |> to_string,
"module.name": inspect(module),
"function.name": "#{function}/#{arity}",
"process.pid": inspect(log.meta.pid)
}
end
@ignored [:domain, :file, :gl, :line, :mfa, :pid, :time]
defp custom_metadata(log) do
[metadata: Map.drop(log.meta, @ignored)]
|> NewRelic.Util.deep_flatten()
|> NewRelic.Util.coerce_attributes()
|> Map.new()
|> Map.delete("metadata.size")
end
def linking_metadata() do
AgentRun.entity_metadata()
end
defp tracing_metadata() do
context = NewRelic.DistributedTrace.get_tracing_context() || %{}
%{
"trace.id": Map.get(context, :trace_id),
"span.id": Map.get(context, :guid)
}
end
end