defmodule OrgGarden.Telemetry do @moduledoc """ Telemetry event definitions and logging handler. ## Events The following telemetry events are emitted: * `[:org_garden, :export, :start]` — Export of a single file started - Metadata: `%{file: path}` * `[:org_garden, :export, :stop]` — Export of a single file completed - Measurements: `%{duration: native_time}` - Metadata: `%{file: path}` * `[:org_garden, :export, :exception]` — Export failed - Measurements: `%{duration: native_time}` - Metadata: `%{file: path, kind: kind, reason: reason}` * `[:org_garden, :watcher, :file_processed]` — File change processed - Metadata: `%{path: path, event: :created | :modified | :deleted}` * `[:org_garden, :server, :start]` — Server started - Metadata: `%{port: port}` * `[:org_garden, :server, :stop]` — Server stopped - Metadata: `%{reason: reason}` ## Usage Attach a handler to log events: OrgGarden.Telemetry.attach_logger() Or use `:telemetry.attach/4` for custom handling. """ require Logger @doc """ Attach a simple logging handler for telemetry events. """ def attach_logger do events = [ [:org_garden, :export, :stop], [:org_garden, :export, :exception], [:org_garden, :watcher, :file_processed], [:org_garden, :server, :start], [:org_garden, :server, :stop] ] :telemetry.attach_many( "org-garden-logger", events, &handle_event/4, nil ) end @doc """ Detach the logging handler. """ def detach_logger do :telemetry.detach("org-garden-logger") end # ------------------------------------------------------------------- # Event handlers # ------------------------------------------------------------------- defp handle_event([:org_garden, :export, :stop], measurements, metadata, _config) do duration_ms = System.convert_time_unit(measurements.duration, :native, :millisecond) Logger.debug("Export completed: #{metadata.file} (#{duration_ms}ms)") end defp handle_event([:org_garden, :export, :exception], _measurements, metadata, _config) do Logger.error("Export failed: #{metadata.file}") end defp handle_event([:org_garden, :watcher, :file_processed], _measurements, metadata, _config) do Logger.debug("Watcher processed: #{metadata.event} #{metadata.path}") end defp handle_event([:org_garden, :server, :start], _measurements, metadata, _config) do Logger.info("Server started on port #{metadata.port}") end defp handle_event([:org_garden, :server, :stop], _measurements, metadata, _config) do Logger.info("Server stopped: #{inspect(metadata.reason)}") end # ------------------------------------------------------------------- # Convenience functions for emitting events # ------------------------------------------------------------------- @doc """ Wrap a function with export telemetry events. """ def span_export(file, fun) when is_function(fun, 0) do :telemetry.span( [:org_garden, :export], %{file: file}, fn -> result = fun.() {result, %{file: file}} end ) end end