A Cased client for Elixir applications in your organization to publish audit trail events to Datadog Logs.
The package can be installed by adding cased
to your list of dependencies in mix.exs
:
def deps do
[
{:cased, "~> 1.0.0"}
]
end
cased-elixir
follows Elixir's Library Guidelines, avoiding the use of a global :cased
application configuration in favor of more flexible, ad hoc configuration at runtime (using your own application configuration, environment variables, etc).
Add a worker specification for Cased.Publisher.Datadog
to your application's supervisor.
The publisher accepts the following options:
:key
— Your Datadog API key (required).:silence
— Whether audit trail events will be discarded, rather than sent; useful for non-production usage (optional; defaults tofalse
).:timeout
— The request timeout, in milliseconds (optional; defaults to15_000
)
You can source your configuration values from your application configuration, runtime environment variables, or hard-code them directly; the following is just an example:
children = [
# Other workers...
{
Cased.Publisher.Datadog,
key: System.get_env("DD_API_KEY") || Application.fetch_env!(:your_app, :datadog_api_key),
silence: System.get_env("CASED_SILENCE") || Application.fetch_env!(:your_app, :cased_silence, false),
}
]
# Other config...
Supervisor.start_link(children, opts)
In the event you provide an invalid configuration, a Cased.ConfigurationError
will be raised with details.
Provided you've configured the Cased publisher, use Cased.publish/1
:
iex> %{
...> action: "credit_card.charge",
...> amount: 2000,
...> currency: "usd",
...> source: "tok_amex",
...> description: "My First Test Charge (created for API docs)",
...> credit_card_id: "card_1dQpXqQwXxsQs9sohN9HrzRAV6y"
...> }
...> |> Cased.publish()
:ok
ℹ️ See the documentation for Cased.publish/2
for more options.
If you are handling sensitive information on behalf of your users, you should consider masking or filtering any sensitive information.
You can do this manually by using Cased.Sensitive.String.new/2
:
iex> %{
...> action: "credit_card.charge",
...> user: Cased.Sensitive.String.new("john@example.com", label: :email)
...> }
...> |> Cased.publish()
:ok
You can also use handlers to find sensitive values for you automatically. Here's an example checking for usernames:
iex> username_handler = {Cased.Sensitive.RegexHandler, :username, ~r<@\w+>}
iex> %{
...> action: "comment.create",
...> body: "@username, I'm not sure."
...> }
...> |> Cased.publish(handlers: [username_handler])
:ok
If you're regularly using the same handlers, consider storing them in your application config and defining your own function to use them in your application:
defmodule MyApp do
@doc """
Publish an audit event to Cased.
"""
@spec publish_to_cased(audit_event :: map()) :: :ok | {:error, any()}
def publish_to_cased(audit_event) do
handlers = Application.get_env(:my_app, :cased_handlers, [])
audit_event
|> Cased.publish(handlers: handlers)
end
end
For more information, see the Cased.Sensitive.Handler
module.
One of the most easiest ways to publish detailed events to Cased is to push contextual information into the Cased context.
Note that the Cased context is tied to the current process (it's actually stored in the process dictionary). Different process, different context.
iex> Cased.Context.merge(location: "hostname.local")
:ok
iex> %{
...> action: "console.start",
...> user: "john"
...> }
...> |> Cased.publish()
:ok
Any information stored using Cased.Context
will be included any time an event is published.
{
"cased_id": "5f8559cd-4cd9-48c3-b1d0-6eedc4019ec1",
"action": "user.login",
"user": "john",
"location": "hostname.local",
"timestamp": "2020-06-22T21:43:06.157336"
}
You can provide Cased.Context.merge/2
a function and the context will only be present for the duration of the function execution:
iex> Cased.Context.merge(location: "hostname.local") do
...> # Will include { "location": "hostname.local" }
...> %{
...> action: "console.start",
...> user: "john"
...> }
...> |> Cased.publish()
...> end
:ok
iex> # Will not include {"location": "hostname.local"}
iex> %{
...> action: "console.end",
...> user: "john"
...> }
...> |> Cased.publish()
:ok
(You can also use Cased.Context.put/2
and Cased.Context.put/3
for single-value additions to the context.)
To reset the context, use Cased.Context.reset/0
:
iex> Cased.Context.reset()
:ok # or `nil` if no data was stored in the context
See the Cased.Context
module for more information.
See Cased.TestHelper
.
- Fork it ( https://github.com/cased/cased-elixir/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request