View Source LoggerJSON.Formatters.Elastic (logger_json v6.2.1)
Custom Erlang's :logger
formatter which
writes logs in a JSON-structured format that conforms to the Elastic Common Schema (ECS), so it can be consumed by
ElasticSearch, LogStash, FileBeat and Kibana.
Formatter Configuration
For list of options see "Shared options" in LoggerJSON
.
Metadata
For list of other well-known metadata keys see "Metadata" in LoggerJSON
.
Any custom metadata that you set with Logger.metadata/1
will be included top-level in the log entry.
Examples
Example of an info log (Logger.info("Hello")
without any metadata):
%{
"@timestamp" => "2024-05-17T16:20:00.000Z",
"ecs.version" => "8.11.0",
"log.level" => "info",
"log.logger" => "Elixir.LoggerJSON.Formatters.ElasticTest",
"log.origin" => %{
"file.name" => "/app/logger_json/test/formatters/elastic_test.exs",
"file.line" => 18,
"function" => "test logs an LogEntry of every level/1"
},
"message" => "Hello"
}
Example of logging by keywords or by map (Logger.info(%{message: "Hello", foo: :bar, fiz: %{buz: "buz"}})). The keywords or map items are added to the top-level of the log entry:
%{
"@timestamp" => "2024-05-17T16:20:00.000Z",
"ecs.version" => "8.11.0",
"fiz" => %{"buz" => "buz"},
"foo" => "bar",
"log.level" => "debug",
"log.logger" => "Elixir.LoggerJSON.Formatters.ElasticTest",
"log.origin" => %{
"file.line" => 68,
"file.name" => "/app/logger_json/test/formatters/elastic_test.exs",
"function" => "test logs an LogEntry with a map payload containing message/1"
},
"message" => "Hello"
}
Example of logging due to raising an exception (raise RuntimeError
):
%{
"@timestamp" => "2024-05-17T16:20:00.000Z",
"ecs.version" => "8.11.0",
"error.message" => "runtime error",
"error.stack_trace" => "** (RuntimeError) runtime error
test/logger_json/formatters/elastic_test.exs:191: anonymous fn/0 in LoggerJSON.Formatters.ElasticTest."test logs exceptions"/1
",
"error.type" => "Elixir.RuntimeError",
"log.level" => "error",
"message" => "Process #PID<0.322.0> raised an exception
** (RuntimeError) runtime error
test/logger_json/formatters/elastic_test.exs:191: anonymous fn/0 in LoggerJSON.Formatters.ElasticTest."test logs exceptions"/1"
}
Note that if you raise an exception that contains an id
or a code
property, they will be included in the log entry as error.id
and error.code
respectively.
Example:
defmodule TestException do
defexception [:message, :id, :code]
end
...
raise TestException, id: :oops_id, code: 42, message: "oops!"
results in:
%{
"@timestamp" => "2024-05-17T16:20:00.000Z",
"ecs.version" => "8.11.0",
"error.code" => 42,
"error.id" => "oops_id",
"error.message" => "oops!",
"error.stack_trace" => "** (LoggerJSON.Formatters.ElasticTest.TestException) oops!
test/logger_json/formatters/elastic_test.exs:223: anonymous fn/0 in LoggerJSON.Formatters.ElasticTest."test logs exceptions with id and code"/1
",
"error.type" => "Elixir.LoggerJSON.Formatters.ElasticTest.TestException",
"log.level" => "error",
"message" => "Process #PID<0.325.0> raised an exception
** (LoggerJSON.Formatters.ElasticTest.TestException) oops!
test/logger_json/formatters/elastic_test.exs:223: anonymous fn/0 in LoggerJSON.Formatters.ElasticTest."test logs exceptions with id and code"/1"
}
You can also choose to log caught exceptions with a custom message.
For example, after catching an exception with try
/rescue
:
try do
raise "oops"
rescue
e in RuntimeError -> Logger.error("Something went wrong", crash_reason: {e, __STACKTRACE__})
end
then you'll get a message like:
%{
"@timestamp" => "2024-05-17T16:20:00.000Z",
"ecs.version" => "8.11.0",
"error.message" => "oops",
"error.stack_trace" => "** (RuntimeError) oops
test/logger_json/formatters/elastic_test.exs:421: anonymous fn/0 in LoggerJSON.Formatters.ElasticTest."test logs caught errors"/1
(logger_json 6.0.2) test/support/logger_case.ex:16: anonymous fn/1 in LoggerJSON.Case.capture_log/2
(ex_unit 1.16.3) lib/ex_unit/capture_io.ex:258: ExUnit.CaptureIO.do_with_io/3
(ex_unit 1.16.3) lib/ex_unit/capture_io.ex:134: ExUnit.CaptureIO.capture_io/2
(logger_json 6.0.2) test/support/logger_case.ex:15: LoggerJSON.Case.capture_log/2
test/logger_json/formatters/elastic_test.exs:419: LoggerJSON.Formatters.ElasticTest."test logs caught errors"/1
(ex_unit 1.16.3) lib/ex_unit/runner.ex:472: ExUnit.Runner.exec_test/2
(stdlib 5.2.3) timer.erl:270: :timer.tc/2
(ex_unit 1.16.3) lib/ex_unit/runner.ex:394: anonymous fn/6 in ExUnit.Runner.spawn_test_monitor/4
",
"error.type" => "Elixir.RuntimeError",
"log.level" => "error",
"log.logger" => "Elixir.LoggerJSON.Formatters.ElasticTest",
"log.origin" => %{
"file.line" => 423,
"file.name" => "/app/logger_json/test/logger_json/formatters/elastic_test.exs",
"function" => "test logs caught errors/1"
},
"message" => "Something went wrong"
}