Current section

Files

Jump to
posthog lib posthog.ex
Raw

lib/posthog.ex

defmodule PostHog do
@moduledoc """
Main API for working with PostHog
"""
@typedoc "Name under which an instance of PostHog supervision tree is registered."
@type supervisor_name() :: atom()
@typedoc ~S(Event name, such as `"user_signed_up"` or `"$create_alias"`)
@type event() :: String.t()
@typedoc "String representing a PostHog distinct ID."
@type distinct_id() :: String.t()
@typedoc """
Map representing event properties.
Note that it __must__ be JSON-serializable.
"""
@type properties() :: %{optional(String.t()) => any(), optional(atom()) => any()}
@doc """
Returns the configuration map for a named `PostHog` supervisor.
## Examples
Retrieve the default `PostHog` instance config:
%{supervisor_name: PostHog} = PostHog.config()
Retrieve named instance config:
%{supervisor_name: MyPostHog} = PostHog.config(MyPostHog)
"""
@spec config(supervisor_name()) :: PostHog.Config.config()
def config(name \\ __MODULE__), do: PostHog.Registry.config(name)
@doc false
def bare_capture(event, distinct_id, %{} = properties),
do: bare_capture(__MODULE__, event, distinct_id, properties)
@doc """
Captures a single event without retrieving properties from context.
Capture is a relatively lightweight operation. The event is prepared
synchronously and then sent to PostHog workers to be batched together with
other events and sent over the wire.
## Examples
Capture a simple event:
PostHog.bare_capture("event_captured", "user123")
Capture an event with properties:
PostHog.bare_capture("event_captured", "user123", %{backend: "Phoenix"})
Capture through a named PostHog instance:
PostHog.bare_capture(MyPostHog, "event_captured", "user123")
"""
@spec bare_capture(supervisor_name(), event(), distinct_id(), properties()) :: :ok
def bare_capture(name \\ __MODULE__, event, distinct_id, properties \\ %{}) do
config = PostHog.Registry.config(name)
properties =
properties
|> Map.merge(config.global_properties)
|> LoggerJSON.Formatter.RedactorEncoder.encode([])
event = %{
event: event,
distinct_id: distinct_id,
uuid: UUIDv7.generate(),
timestamp: DateTime.utc_now() |> DateTime.to_iso8601(),
properties: properties
}
PostHog.Sender.send(event, name)
end
@doc false
def capture(event, %{} = properties),
do: capture(__MODULE__, event, properties)
@doc """
Captures a single event.
Any context previously set will be included in the event properties. Note that
`distinct_id` is still required.
## Examples
Set context and capture an event:
PostHog.set_context(%{distinct_id: "user123", "$feature/my-feature-flag": true})
PostHog.capture("job_started", %{job_name: "JobName"})
Set context and capture an event through a named PostHog instance:
PostHog.set_context(MyPostHog, %{distinct_id: "user123", "$feature/my-feature-flag": true})
PostHog.capture(MyPostHog, "job_started", %{job_name: "JobName"})
"""
@spec capture(supervisor_name(), event(), properties()) :: :ok | {:error, :missing_distinct_id}
def capture(name \\ __MODULE__, event, properties \\ %{}) do
context =
name
|> get_event_context(event)
|> Map.merge(properties)
case Map.pop(context, :distinct_id) do
{nil, _} -> {:error, :missing_distinct_id}
{distinct_id, properties} -> bare_capture(name, event, distinct_id, properties)
end
end
@doc """
Sets context for the current process.
## Examples
Set and retrieve context for the current process:
> PostHog.set_context(%{foo: "bar"})
> PostHog.get_context()
%{foo: "bar"}
Set and retrieve context for a named PostHog instance:
> PostHog.set_context(MyPostHog, %{foo: "bar"})
> PostHog.get_context(MyPostHog)
%{foo: "bar"}
"""
@spec set_context(supervisor_name(), properties()) :: :ok
defdelegate set_context(name \\ __MODULE__, context), to: PostHog.Context, as: :set
@doc """
Sets context for the current process scoped to a specific event.
## Examples
Set and retrieve context scoped to an event:
> PostHog.set_event_context("$exception", %{foo: "bar"})
> PostHog.get_event_context("$exception")
%{foo: "bar"}
Set and retrieve context for a specific event through a named PostHog instance:
> PostHog.set_event_context(MyPostHog, "$exception", %{foo: "bar"})
> PostHog.get_event_context(MyPostHog, "$exception")
%{foo: "bar"}
"""
@spec set_event_context(supervisor_name(), event(), properties()) :: :ok
def set_event_context(name \\ __MODULE__, event, context),
do: PostHog.Context.set(name, event, context)
@doc """
Retrieves context for the current process.
## Examples
Set and retrieve context for current process:
> PostHog.set_context(%{foo: "bar"})
> PostHog.get_context()
%{foo: "bar"}
Set and retrieve context for a named PostHog instance:
> PostHog.set_context(MyPostHog, %{foo: "bar"})
> PostHog.get_context(MyPostHog)
%{foo: "bar"}
"""
@spec get_context(supervisor_name()) :: properties()
defdelegate get_context(name \\ __MODULE__), to: PostHog.Context, as: :get
@doc """
Retrieves context for the current process scoped to a specific event.
## Examples
Set and retrieve context scoped to an event:
> PostHog.set_event_context("$exception", %{foo: "bar"})
> PostHog.get_event_context("$exception")
%{foo: "bar"}
Set and retrieve context for a specific event through a named PostHog instance:
> PostHog.set_event_context(MyPostHog, "$exception", %{foo: "bar"})
> PostHog.get_event_context(MyPostHog, "$exception")
%{foo: "bar"}
"""
@spec get_event_context(event()) :: properties()
@spec get_event_context(supervisor_name(), event()) :: properties()
def get_event_context(name \\ __MODULE__, event), do: PostHog.Context.get(name, event)
end