Skip to content

Commit 295799d

Browse files
committed
update documentation
1 parent c88d84b commit 295799d

6 files changed

Lines changed: 321 additions & 129 deletions

File tree

README.md

Lines changed: 26 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,24 @@
22

33
[![Hex.pm](https://img.shields.io/hexpm/v/msgpack_elixir.svg)](https://hex.pm/packages/msgpack_elixir)
44

5-
A [MessagePack](https://msgpack.org/) serialization library for Elixir.
5+
An implementation of the [MessagePack](https://msgpack.org/) serialization
6+
format for Elixir.
7+
8+
It provides functions for encoding and decoding Elixir terms and supports the
9+
full MessagePack specification, including the Timestamp and custom Extension
10+
types.
611

712
## Features
813

9-
- **Full Specification Compliance:** Adheres to the MessagePack specification to
10-
ensure compatibility with other MessagePack implementations
11-
- Includes support for types such as `Booleans`, `Integers`, `Floats`, `Tuples`,
12-
`Lists`, `Maps`, `Strings`, `Binaries`, `Extensions`, and `Timestamps`
13-
- Encodes and decodes Elixir's `DateTime` and `NaiveDateTime` structs using
14-
the MessagePack `Timestamp` extension
15-
- **Performant Encoding:** Implements efficient encoding for collections and
16-
provides a `:string_validation` option to bypass UTF-8 validation in
17-
performance-sensitive applications
18-
- **Exception-raising Variants:** Includes bang (`!`) variants like `encode!/2`
19-
and `decode!/2` for contexts where raising an exception is preferred over
20-
error tuples
21-
- **Telemetry Integration:** Emits standard `:telemetry` events for all encode
22-
and decode operations, allowing for easy integration into monitoring and
23-
observability tools
14+
- **Specification Compliance:** Implements the complete MessagePack type system.
15+
- **Elixir Struct Support:** Encodes and decodes `DateTime` and `NaiveDateTime`
16+
structs via the Timestamp extension type.
17+
- **Configurable Validation:** Provides an option to bypass UTF-8 validation on
18+
strings for performance-critical paths.
19+
- **Resource Limiting:** Includes configurable `:max_depth` and `:max_byte_size`
20+
limits to mitigate resource exhaustion from malformed or malicious payloads.
21+
- **Telemetry Integration:** Emits standard `:telemetry` events for integration
22+
with monitoring tools.
2423

2524
## Installation
2625

@@ -34,98 +33,28 @@ end
3433

3534
Then, run `mix deps.get`.
3635

37-
## Usage
38-
39-
### Basic Operations
40-
41-
The library returns `{:ok, value}` tuples for successful operations and
42-
`{:error, reason}` tuples for failures.
36+
## Quick Start
4337

4438
```elixir
45-
# Encode a map
46-
iex> data = %{"id" => 1, "name" => "Elixir"}
39+
# Encode a map. Atom keys are converted to strings by default.
40+
iex> data = %{id: 1, name: "Elixir"}
4741
iex> {:ok, encoded} = Msgpack.encode(data)
4842
<<130, 162, 105, 100, 1, 164, 110, 97, 109, 101, 166, 69, 108, 105, 120, 105, 114>>
4943

50-
# Decode a binary
44+
# Decode a binary.
5145
iex> Msgpack.decode(encoded)
5246
{:ok, %{"id" => 1, "name" => "Elixir"}}
53-
```
54-
55-
### Exception-raising Operations
5647

57-
If you prefer an exception to be raised on failure, use the bang (`!`) variants.
58-
59-
```elixir
60-
iex> encoded = Msgpack.encode!(%{id: 1})
61-
<<129, 162, 105, 100, 1>>
62-
63-
iex> Msgpack.decode!(<<192, 42>>)
64-
** (Msgpack.DecodeError) Failed to decode MessagePack binary. Reason = {:trailing_bytes, <<42>>}
48+
# Use the exception-raising variants for exceptional failure cases.
49+
iex> Msgpack.decode!(<<0xC1>>)
50+
** (Msgpack.DecodeError) Unknown type prefix: 193. The byte `0xC1` is not a valid MessagePack type marker.
6551
```
6652

67-
## Options
68-
69-
The following options can be passed as a second argument to the `encode` and
70-
`decode` functions.
71-
72-
### For `encode/2`
53+
## Full Documentation
7354

74-
- `:atoms`
75-
- Controls how atoms are encoded.
76-
- `:string` (default) - Encodes atoms as MessagePack strings
77-
- `:error` - Returns an `{:error, {:unsupported_atom, atom}}` tuple if an atom
78-
is encountered
79-
- `:string_validation`
80-
- Controls whether to perform UTF-8 validation on binaries
81-
- `true` (default) - Validates binaries; encodes as `str` type if valid UTF-8,
82-
`bin` type otherwise
83-
- `false` - Skips validation and encodes all binaries as the `str` type.
84-
Improves performance but should only be used if you are certain your data is
85-
valid
86-
87-
### For `decode/2`
88-
89-
- `:max_depth`
90-
- Sets a limit on the nesting level of arrays and maps to prevent stack
91-
exhaustion attacks
92-
- Defaults to `100`
93-
- `:max_byte_size`
94-
- Sets a limit on the declared byte size of any single string, binary, array,
95-
or map to prevent memory exhaustion attacks
96-
- Defaults to `10_000_000` (10MB)
97-
98-
## Telemetry
99-
100-
The library emits `:telemetry` events which can be used for monitoring or
101-
logging.
102-
103-
- `[:msgpack, :encode]` - Dispatched when `Msgpack.encode/2` is called
104-
- `[:msgpack, :decode]` - Dispatched when `Msgpack.decode/2` is called
105-
106-
Example of attaching a logger:
107-
108-
```elixir
109-
defmodule MyTelemetryHandler do
110-
require Logger
111-
112-
def attach do
113-
:telemetry.attach(
114-
"msgpack-logger",
115-
[:msgpack, :encode],
116-
&__MODULE__.handle_event/4,
117-
nil
118-
)
119-
end
120-
121-
def handle_event(event_name, measurements, metadata, _config) do
122-
Logger.info("Telemetry Event: #{inspect(event_name)}",
123-
measurements: measurements,
124-
metadata: metadata
125-
)
126-
end
127-
end
128-
```
55+
For detailed information on all features, options, and functions, see the [full
56+
documentation on HexDocs](https://hexdocs.pm/msgpack_elixir/Msgpack.html), which
57+
contains a complete API reference for all public modules and functions.
12958

13059
## Development
13160

guides/telemetry.md

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# Telemetry
2+
3+
This library emits `:telemetry` events for all `encode/2` and `decode/2`
4+
operations. This allows you to integrate `Msgpack` into your application's
5+
monitoring and observability stack.
6+
7+
This guide will show you how to attach a simple logger to these events.
8+
9+
## 1. Define a Telemetry Handler
10+
11+
First, define a module that will receive and handle the events. This handler can
12+
log the event, increment a metric, or record a trace span.
13+
14+
```elixir
15+
defmodule MyTelemetryHandler do
16+
require Logger
17+
18+
def attach do
19+
:telemetry.attach_many(
20+
"msgpack-logger",
21+
[
22+
[:msgpack, :encode, :start],
23+
[:msgpack, :encode, :stop],
24+
[:msgpack, :encode, :exception],
25+
[:msgpack, :decode, :start],
26+
[:msgpack, :decode, :stop],
27+
[:msgpack, :decode, :exception]
28+
],
29+
&__MODULE__.handle_event/4,
30+
nil
31+
)
32+
end
33+
34+
def handle_event(event_name, measurements, metadata, _config) do
35+
Logger.info("Telemetry Event: #{inspect(event_name)}",
36+
measurements: measurements,
37+
metadata: metadata
38+
)
39+
end
40+
end
41+
```
42+
43+
## 2. Attach the Handler
44+
45+
Attach the handler when your application starts, for example, in your
46+
`Application.start/2` callback.
47+
48+
```elixir
49+
# In your application.ex
50+
def start(_type, _args) do
51+
# ... other startup code
52+
MyTelemetryHandler.attach()
53+
# ...
54+
end
55+
```
56+
57+
## Understanding Events
58+
59+
The library emits standard `:start`, `:stop`, and `:exception` events for each operation.
60+
61+
### Encoding Events
62+
63+
#### `[:msgpack, :encode, :start]`
64+
65+
- **Dispatched Before:** The encoding process begins.
66+
- **`measurements`:** `%{system_time: ...}`
67+
- **`metadata`:** `%{opts: keyword(), term: term()}`
68+
69+
#### `[:msgpack, :encode, :stop]`
70+
71+
- **Dispatched After:** The encoding process finishes (either successfully or with a logical error).
72+
- **`measurements`:** `%{duration: native_time}`
73+
- **`metadata`:**
74+
- **On success:** `%{outcome: :ok, byte_size: non_neg_integer()}`
75+
- **On logical failure:** `%{outcome: :error}`
76+
77+
#### `[:msgpack, :encode, :exception]`
78+
79+
- **Dispatched If:** An error occurs during encoding.
80+
- **`measurements`:** `%{duration: native_time}`
81+
- **`metadata`:** `%{kind: :error | :throw | :exit, reason: term(), stacktrace: list()}`
82+
83+
### Decoding Events
84+
85+
#### `[:msgpack, :decode, :start]`
86+
87+
- **Dispatched Before:** The decoding process begins.
88+
- **`measurements`:** `%{system_time: ...}`
89+
- **`metadata`:** `%{opts: keyword(), byte_size: non_neg_integer()}`
90+
91+
#### `[:msgpack, :decode, :stop]`
92+
93+
- **Dispatched After:** The decoding process finishes (either successfully or with a logical error).
94+
- **`measurements`:** `%{duration: native_time}`
95+
- **`metadata`:**
96+
- **On success:** `%{outcome: :ok}`
97+
- **On logical failure:** `%{outcome: :error}`
98+
99+
#### `[:msgpack, :decode, :exception]`
100+
101+
- **Dispatched If:** An error occurs during decoding.
102+
- **`measurements`:** `%{duration: native_time}`
103+
- **`metadata`:** `%{kind: :error | :throw | :exit, reason: term(), stacktrace: list()}`

0 commit comments

Comments
 (0)