Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/index/priv/web/static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ <h2>Apps</h2>
<li><a href="http://localhost:8093">Chat</a></li>
<li><a href="http://localhost:8094">REST API</a></li>
<li><a href="http://localhost:8095">TODO</a></li>
<li><a href="http://localhost:8096">REST with Telemetry</a></li>
</ul>
</p>

Expand Down
12 changes: 12 additions & 0 deletions examples/rest_with_telemetry/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Kraft REST API with Telemetry Example

This example is about how to build a REST API using the Kraft web framework,
while integrating telemetry monitoring through
[Cowboy Telemetry](https://github.com/beam-telemetry/cowboy_telemetry).

> [!TIP]
> [Cowboy Telemetry](https://github.com/beam-telemetry/cowboy_telemetry) is a
> prerequisite for using
> [opentelemetry_cowboy](https://hexdocs.pm/opentelemetry_cowboy/readme.html),
> a Telemetry handler that translates Cowboy events into OpenTelemetry spans,
> enabling HTTP request/response instrumentation.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
htmx.defineExtension('client-side-templates', {
transformResponse : function(text, xhr, elt) {

var mustacheTemplate = htmx.closest(elt, "[mustache-template]");
if (mustacheTemplate) {
var data = JSON.parse(text);
var templateId = mustacheTemplate.getAttribute('mustache-template');
var template = htmx.find("#" + templateId);
if (template) {
return Mustache.render(template.innerHTML, data);
} else {
throw "Unknown mustache template: " + templateId;
}
}

var handlebarsTemplate = htmx.closest(elt, "[handlebars-template]");
if (handlebarsTemplate) {
var data = JSON.parse(text);
var templateName = handlebarsTemplate.getAttribute('handlebars-template');
return Handlebars.partials[templateName](data);
}

var nunjucksTemplate = htmx.closest(elt, "[nunjucks-template]");
if (nunjucksTemplate) {
var data = JSON.parse(text);
var templateName = nunjucksTemplate.getAttribute('nunjucks-template');
var template = htmx.find('#' + templateName);
if (template) {
return nunjucks.renderString(template.innerHTML, data);
} else {
return nunjucks.render(templateName, data);
}
}

return text;
}
});

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

57 changes: 57 additions & 0 deletions examples/rest_with_telemetry/priv/web/static/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<!doctype html>
<html>
<head>
<title>Kraft REST API with Telemetry</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="/assets/scripts/htmx@1.4.1.min.js"></script>
<script src="/assets/scripts/htmx@1.4.1/ext/client-side-templates.js"></script>
<script src="/assets/scripts/mustache@4.2.0.min.js"></script>

</head>
<body style="margin: 0; padding: 0;">


<h1>Kraft REST API with Telemetry</h1>

<div style="text-align: left; margin-bottom: 30px;">
<a href="/telemetry.html" style="background-color: #007bff; color: white; margin: 10px; padding: 10px 20px;">
Telemetry Dashboard
</a>
</div>

<div style="text-align: center; " hx-ext="client-side-templates">
<h2>API Testing</h2>

<button hx-get="/api/v1/example/endpoint" hx-target="#content" mustache-template="content-template" >
Click Me (Get request)
</button>

<button hx-get="/api/v1/error">
Click Me (Generate an error for telemetry)
</button>

<div id="content"></div>

<template id="content-template">
<div style="text-align: left; margin-left: 20px;">
<h3>Response</h3>
<dl>
<dt>User</dt>
<dd>{{user}}</dd>

<dt>ID</dt>
<dd>{{id}}</dd>

<dt>Role</dt>
<dd>{{role}}</dd>

<dt>Last Accessed</dt>
<dd>{{access}}</dd>
</dl>
</div>
</template>
</div>

</body>
</html>
80 changes: 80 additions & 0 deletions examples/rest_with_telemetry/priv/web/static/telemetry.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Telemetry</title>
<script src="/assets/scripts/htmx@1.4.1.min.js"></script>
<script src="/assets/scripts/htmx@1.4.1/ext/client-side-templates.js"></script>
<script src="/assets/scripts/mustache@4.2.0.min.js"></script>
</head>
<body>
<h1>Kraft REST API with Telemetry</h1>

<a href="/"> &lt; Back to main page</a>

<div hx-ext="client-side-templates" style="padding: 10px 10px 10px 0;">
<button id="clear-btn"
hx-delete="/api/v1/telemetry/events"
hx-swap="none"
hx-confirm="Are you sure you want to clear all events?">
Clear All Events
</button>

<script>
document.body.addEventListener('htmx:afterRequest', function(evt) {
if (evt.detail.elt.id === 'clear-btn') {
document.getElementById('refresh-btn').click();
}
});
</script>

<button id="refresh-btn"
hx-get="/api/v1/telemetry/events"
hx-target="#events"
mustache-template="events-template">
Refresh Events
</button>

<div id="events"></div>

<template id="events-template">
<h2>Events ({{count}})</h2>
<p>Last updated: {{timestamp}}</p>

{{#events}}
<div style="border: 1px solid #ccc; margin: 10px 0; padding: 10px;">
<p><strong>Request ID (Connection PID + Stream ID):</strong> {{request_id}}</p>
<p><strong>Type:</strong> {{event_type}}</p>
<p><strong>Path:</strong> {{method}} {{path}}</p>

{{#measurements}}
<div style="margin-top: 10px; padding: 5px; background-color: #f5f5f5;">
<strong>Measurements:</strong>
{{#duration}}
<p>&bull; <strong>Duration:</strong> {{duration}}&micro;s</p>
{{/duration}}
{{#resp_body_length}}
<p>&bull; <strong>Response Size:</strong> {{resp_body_length}} bytes</p>
{{/resp_body_length}}
</div>
{{/measurements}}

{{#meta}}
<div style="margin-top: 10px; padding: 5px; background-color: #f0f8ff; border-left: 3px solid #007acc;">
<strong>Meta (Raw Telemetry Data):</strong>
<pre style="white-space: pre-wrap; word-wrap: break-word; font-size: 12px; background-color: #f9f9f9; padding: 5px; margin: 5px 0;">
{{meta}}
</pre>
</div>
{{/meta}}

</div>
{{/events}}

{{^events}}
<p>No events captured yet.</p>
<p>Go to <a href="/">main page</a> and click "Click Me" to generate events.</p>
{{/events}}
</template>
</div>
</body>
</html>
7 changes: 7 additions & 0 deletions examples/rest_with_telemetry/rebar.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{erl_opts, [debug_info]}.

{deps, [
kraft,
cowboy_telemetry,
telemetry
]}.
18 changes: 18 additions & 0 deletions examples/rest_with_telemetry/src/rest_with_telemetry.app.src
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{application, rest_with_telemetry, [
{description, "A REST API example in Kraft"},
{vsn, "0.1.0"},
{registered, []},
{mod, {rest_with_telemetry, []}},
{applications, [
kernel,
stdlib,
telemetry,
cowboy_telemetry,
kraft
]},
{env, []},
{modules, []},

{licenses, ["Apache 2.0"]},
{links, []}
]}.
Loading