-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathindex.html
More file actions
494 lines (434 loc) · 23.3 KB
/
Copy pathindex.html
File metadata and controls
494 lines (434 loc) · 23.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>mtlog - Message Template Logging for Go</title>
<meta name="description" content="Serilog-inspired structured logging for Go with message templates, rich formatting, and native Seq support.">
<!-- Go import -->
<meta name="go-import" content="mtlog.dev git https://github.com/willibrandon/mtlog">
<!-- Open Graph -->
<meta property="og:title" content="mtlog - Message Template Logging for Go">
<meta property="og:description" content="Zero-allocation structured logging with message templates. 17.3ns per operation. Serilog-inspired design for Go.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://mtlog.dev">
<!-- Prevent theme flash -->
<script>
(() => {
try {
const stored = localStorage.getItem('theme');
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
const theme = stored || (prefersDark ? 'dark' : 'light');
if (theme === 'light') {
document.documentElement.classList.add('light');
document.body?.classList.add('light', 'bg-white', 'text-gray-900');
document.body?.classList.remove('bg-gray-900', 'text-gray-100');
}
} catch {}
})();
</script>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Prism.js for syntax highlighting -->
<link id="prism-theme-dark" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css" rel="stylesheet" />
<link id="prism-theme-light" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism.min.css" rel="stylesheet" disabled />
<style>
/* Custom gradient text */
.gradient-text {
background: linear-gradient(135deg, #7c3aed 0%, #2563eb 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
/* Performance bar animation */
@keyframes slideIn {
from { width: 0; }
to { width: var(--width); }
}
.perf-bar {
animation: slideIn 1s ease-out forwards;
}
/* Code block styling */
pre[class*="language-"] {
border-radius: 0.5rem;
margin: 0;
overflow-x: auto;
white-space: pre;
}
/* Prevent horizontal scroll on feature grid */
.feature-grid pre {
font-size: 0.875rem;
}
@media (max-width: 768px) {
.feature-grid pre {
font-size: 0.75rem;
}
}
/* Smooth scroll */
html {
scroll-behavior: smooth;
}
/* Theme transition */
* {
transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease;
}
/* Light theme adjustments */
body.light pre[class*="language-"] {
background-color: #f5f5f5;
border: 1px solid #e5e5e5;
}
/* Navigation link colors for light mode */
body.light nav a {
color: #6b7280; /* gray-500 */
}
body.light nav a:hover {
color: #111827; /* gray-900 */
}
/* Fix contrast for performance stats in light mode */
body.light .bg-gray-100 span.font-mono {
color: #374151; /* gray-700 */
}
/* Ensure proper contrast in dark mode for iOS/Safari */
.bg-gray-800 span.font-mono {
color: #f3f4f6; /* gray-100 */
}
body.light .bg-gray-100 span.font-mono {
color: #374151 !important; /* gray-700 with !important for iOS */
}
</style>
</head>
<body class="bg-gray-900 text-gray-100">
<!-- Header -->
<header class="border-b border-gray-800">
<div class="container mx-auto px-4 py-4 flex justify-between items-center">
<h1 class="text-2xl font-bold gradient-text">mtlog</h1>
<div class="flex items-center gap-6">
<nav class="flex gap-6">
<a href="https://pkg.go.dev/github.com/willibrandon/mtlog" class="text-gray-400 hover:text-gray-100 transition">Docs</a>
<a href="https://github.com/willibrandon/mtlog" class="text-gray-400 hover:text-gray-100 transition">GitHub</a>
<a href="/quick-reference" class="text-gray-400 hover:text-gray-100 transition">Reference</a>
</nav>
<!-- Theme Switcher -->
<button id="theme-toggle" class="p-2 rounded-lg bg-gray-800 hover:bg-gray-700 transition" aria-label="Toggle theme">
<svg class="w-5 h-5 hidden dark-icon" fill="currentColor" viewBox="0 0 20 20">
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"></path>
</svg>
<svg class="w-5 h-5 light-icon" fill="currentColor" viewBox="0 0 20 20">
<path d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z"></path>
</svg>
</button>
</div>
</div>
</header>
<!-- Hero Section -->
<section class="py-20 px-4">
<div class="container mx-auto text-center max-w-4xl">
<h2 class="text-5xl md:text-6xl font-bold mb-6">
Message Template Logging for Go
</h2>
<p class="text-xl text-gray-400 mb-8">
Serilog-inspired structured logging with message templates,<br>
rich formatting, and native Seq support.
</p>
<!-- Stats -->
<div class="grid grid-cols-3 gap-4 sm:gap-8 max-w-2xl mx-auto mb-12">
<div class="text-center">
<div class="text-3xl sm:text-4xl font-bold text-blue-400">17.3ns</div>
<div class="text-sm text-gray-600 dark:text-gray-500 mt-1">per operation</div>
</div>
<div class="text-center">
<div class="text-3xl sm:text-4xl font-bold text-green-400">0</div>
<div class="text-sm text-gray-600 dark:text-gray-500 mt-1">allocations</div>
</div>
<div class="text-center">
<div class="text-2xl sm:text-4xl font-bold text-purple-400">Pipeline</div>
<div class="text-sm text-gray-600 dark:text-gray-500 mt-1">architecture</div>
</div>
</div>
<!-- CTA -->
<div class="flex gap-4 justify-center">
<a href="#quick-start" class="bg-blue-600 hover:bg-blue-700 px-6 py-3 rounded-lg font-semibold transition">
Get Started
</a>
<a href="https://github.com/willibrandon/mtlog" class="border border-gray-700 hover:border-gray-600 px-6 py-3 rounded-lg font-semibold transition">
View on GitHub
</a>
</div>
</div>
</section>
<!-- Features -->
<section class="py-16 px-4 border-t border-gray-800">
<div class="container mx-auto max-w-6xl">
<h3 class="text-3xl font-bold text-center mb-12">Why mtlog?</h3>
<div class="grid md:grid-cols-2 gap-8 feature-grid">
<!-- Message Templates -->
<div class="bg-gray-800 rounded-lg p-6">
<h4 class="text-xl font-semibold mb-4 text-blue-400">Message Templates</h4>
<pre class="mb-4"><code class="language-go">log.Info("User {UserId} logged in from {IP}", userId, ip)
log.Info("Order {@Order} created", order)
log.Info("Processing time: {Duration:F2}ms", 123.456)</code></pre>
<p class="text-gray-400 text-sm">
Properties are extracted from templates and preserved throughout the pipeline.
Templates serve as both human-readable messages and event types.
</p>
</div>
<!-- Type-Safe Logging -->
<div class="bg-gray-800 rounded-lg p-6">
<h4 class="text-xl font-semibold mb-4 text-green-400">Type-Safe ForType</h4>
<pre class="mb-4"><code class="language-go">userLogger := mtlog.ForType[User](logger)
userLogger.Info("User created")
// SourceContext: "User"
orderLogger := mtlog.ForType[OrderService](logger)
// Automatic categorization by type</code></pre>
<p class="text-gray-400 text-sm">
Automatic source context from Go types. No more string constants.
Perfect for service-oriented architectures.
</p>
</div>
<!-- Zero Allocations -->
<div class="bg-gray-800 rounded-lg p-6">
<h4 class="text-xl font-semibold mb-4 text-purple-400">Zero Allocations</h4>
<pre class="mb-4"><code class="language-go">// Simple logging: 0 allocations
log.Info("Application started")
// Below minimum level: 0 allocations
log.Debug("This won't allocate")</code></pre>
<p class="text-gray-400 text-sm">
Carefully optimized for the common path. Simple messages and filtered
events allocate zero bytes.
</p>
</div>
<!-- Rich Ecosystem -->
<div class="bg-gray-800 rounded-lg p-6">
<h4 class="text-xl font-semibold mb-4 text-yellow-400">Ecosystem Compatible</h4>
<pre class="mb-4"><code class="language-go">// Works with slog
slogger := mtlog.NewSlogLogger(...)
slog.SetDefault(slogger)
// Works with logr (Kubernetes)
import mtlogr "github.com/willibrandon/mtlog/adapters/logr"
logrLogger := mtlogr.NewLogger(...)</code></pre>
<p class="text-gray-400 text-sm">
Drop-in adapters for Go's standard slog and Kubernetes logr.
Use mtlog's power with existing code.
</p>
</div>
</div>
</div>
</section>
<!-- Performance -->
<section class="py-16 px-4 border-t border-gray-800">
<div class="container mx-auto max-w-4xl">
<h3 class="text-3xl font-bold text-center mb-12">Performance Characteristics</h3>
<div class="grid md:grid-cols-2 gap-8 mb-8">
<div class="bg-gray-800 rounded-lg p-6">
<h4 class="text-xl font-semibold mb-4 text-blue-400">Zero-Allocation Path</h4>
<ul class="space-y-2 text-gray-400">
<li>• Simple string messages: <span class="text-gray-700 dark:text-gray-100 font-mono">0 allocs</span></li>
<li>• Below minimum level: <span class="text-gray-700 dark:text-gray-100 font-mono">0 allocs</span></li>
<li>• Dynamic level checks: <span class="text-gray-700 dark:text-gray-100 font-mono">0 allocs</span></li>
<li>• Filtered events: <span class="text-gray-700 dark:text-gray-100 font-mono">0 allocs</span></li>
</ul>
</div>
<div class="bg-gray-800 rounded-lg p-6">
<h4 class="text-xl font-semibold mb-4 text-green-400">Operation Timing</h4>
<ul class="space-y-2 text-gray-400">
<li>• Simple logging: <span class="text-gray-700 dark:text-gray-100 font-mono">17.3 ns/op</span></li>
<li>• Level filtering: <span class="text-gray-700 dark:text-gray-100 font-mono">1.5 ns/op</span></li>
<li>• With properties: <span class="text-gray-700 dark:text-gray-100 font-mono">~200 ns/op</span></li>
<li>• ForType (cached): <span class="text-gray-700 dark:text-gray-100 font-mono">~148 ns/op</span></li>
</ul>
</div>
</div>
<div class="text-center">
<p class="text-gray-400 mb-4">
Carefully optimized for the common path with zero allocations for simple operations.
</p>
<p class="text-gray-500 text-sm mb-4">
Benchmarked with <code class="text-gray-400">go test -bench . -benchmem</code> on AMD Ryzen 9 9950X, Go 1.23
</p>
<a href="https://github.com/willibrandon/mtlog#performance" class="text-blue-400 hover:underline">
View detailed benchmarks →
</a>
</div>
</div>
</section>
<!-- Quick Start -->
<section id="quick-start" class="py-16 px-4 border-t border-gray-800">
<div class="container mx-auto max-w-4xl">
<h3 class="text-3xl font-bold text-center mb-12">Quick Start</h3>
<div class="bg-gray-800 rounded-lg p-4 mb-6">
<pre><code class="language-bash">go get github.com/willibrandon/mtlog</code></pre>
</div>
<div class="bg-gray-800 rounded-lg p-4">
<pre><code class="language-go">package main
import (
"github.com/willibrandon/mtlog"
"github.com/willibrandon/mtlog/core"
)
type User struct{}
func main() {
// Create a logger with console output
log := mtlog.New(
mtlog.WithConsole(),
mtlog.WithMinimumLevel(core.InformationLevel),
)
// Simple logging
log.Info("Application started")
// Message templates with properties
userId := 123
log.Info("User {UserId} logged in", userId)
// Type-based logging
userLogger := mtlog.ForType[User](log)
userLogger.Info("User operation completed")
}</code></pre>
</div>
<div class="text-center mt-8">
<a href="https://github.com/willibrandon/mtlog#quick-start" class="text-blue-400 hover:underline">
See more examples →
</a>
</div>
</div>
</section>
<!-- IDE Extensions -->
<section id="ide-extensions" class="py-16 px-4 border-t border-gray-800">
<div class="container mx-auto max-w-4xl">
<h3 class="text-3xl font-bold text-center mb-8">IDE Extensions</h3>
<p class="text-gray-400 text-center mb-12">
Real-time validation for mtlog message templates with the mtlog-analyzer
</p>
<div class="grid md:grid-cols-3 gap-8">
<!-- VS Code Extension -->
<div class="bg-gray-800 rounded-lg p-8 text-center">
<h4 class="text-xl font-semibold mb-4">Visual Studio Code</h4>
<p class="text-gray-400 mb-6">
Get instant feedback on template/argument mismatches, property naming, and more.
</p>
<a href="https://marketplace.visualstudio.com/items?itemName=mtlog.mtlog-analyzer"
class="inline-block">
<img src="https://img.shields.io/visual-studio-marketplace/v/mtlog.mtlog-analyzer?style=for-the-badge&logo=visual-studio-code&label=VS%20Code%20Marketplace&color=007ACC"
alt="VS Code Marketplace">
</a>
<div class="mt-4">
<code class="text-sm bg-gray-200 dark:bg-gray-900 text-gray-900 dark:text-gray-100 px-3 py-1 rounded">code --install-extension mtlog.mtlog-analyzer</code>
</div>
</div>
<!-- GoLand/IntelliJ Extension -->
<div class="bg-gray-800 rounded-lg p-8 text-center">
<h4 class="text-xl font-semibold mb-4">GoLand / IntelliJ IDEA</h4>
<p class="text-gray-400 mb-6">
Real-time annotations with quick fixes for common issues.
</p>
<a href="https://plugins.jetbrains.com/plugin/28090-mtlog-analyzer"
class="inline-block">
<img src="https://img.shields.io/jetbrains/plugin/v/28090?style=for-the-badge&logo=jetbrains&label=JetBrains%20Marketplace&color=000000"
alt="JetBrains Marketplace">
</a>
<div class="mt-4">
<code class="text-sm bg-gray-200 dark:bg-gray-900 text-gray-900 dark:text-gray-100 px-3 py-1 rounded">Plugin ID: 28090</code>
</div>
</div>
<!-- Neovim Plugin -->
<div class="bg-gray-800 rounded-lg p-8 text-center">
<h4 class="text-xl font-semibold mb-4">Neovim</h4>
<p class="text-gray-400 mb-6">
LSP integration with code actions, quick fixes, and advanced diagnostics.
</p>
<a href="https://github.com/willibrandon/mtlog/tree/main/neovim-plugin"
class="inline-block">
<img src="https://img.shields.io/badge/Neovim-v0.8.0%2B-57A143?style=for-the-badge&logo=neovim&logoColor=white"
alt="Neovim Plugin">
</a>
<div class="mt-4">
<code class="text-sm bg-gray-200 dark:bg-gray-900 text-gray-900 dark:text-gray-100 px-3 py-1 rounded">rtp = 'neovim-plugin'</code>
</div>
</div>
</div>
<div class="mt-12 text-center">
<p class="text-gray-400 mb-4">First install the analyzer:</p>
<div class="bg-gray-200 dark:bg-gray-800 rounded-lg p-4 inline-block">
<code class="text-gray-900 dark:text-gray-100">go install github.com/willibrandon/mtlog/cmd/mtlog-analyzer@latest</code>
</div>
</div>
</div>
</section>
<!-- Footer -->
<footer class="border-t border-gray-800 py-8 px-4">
<div class="container mx-auto text-center text-gray-500 text-sm">
<p class="mt-2">
<a href="https://github.com/willibrandon/mtlog" class="hover:text-gray-400">GitHub</a> •
<a href="https://pkg.go.dev/github.com/willibrandon/mtlog" class="hover:text-gray-400 ml-4">Go Docs</a> •
<a href="/quick-reference" class="hover:text-gray-400 ml-4">Quick Reference</a> •
<a href="/blog" class="hover:text-gray-400 ml-4">Blog</a> •
<a href="https://github.com/willibrandon/mtlog/blob/main/LICENSE" class="hover:text-gray-400 ml-4">MIT</a>
</p>
</div>
</footer>
<!-- Prism.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-go.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-bash.min.js"></script>
<!-- Theme Switcher -->
<script>
// Theme management
const themeToggle = document.getElementById('theme-toggle');
const body = document.body;
const darkIcon = themeToggle.querySelector('.dark-icon');
const lightIcon = themeToggle.querySelector('.light-icon');
const prismDark = document.getElementById('prism-theme-dark');
const prismLight = document.getElementById('prism-theme-light');
// Load saved theme or default to dark
const savedTheme = localStorage.getItem('theme') || 'dark';
setTheme(savedTheme);
function setTheme(theme) {
if (theme === 'light') {
body.classList.remove('bg-gray-900', 'text-gray-100');
body.classList.add('bg-white', 'text-gray-900', 'light');
darkIcon.classList.add('hidden');
lightIcon.classList.remove('hidden');
prismDark.disabled = true;
prismLight.disabled = false;
// Update header
const header = document.querySelector('header');
header.classList.remove('bg-gray-900', 'border-gray-800');
header.classList.add('bg-white', 'border-gray-200');
// Update code blocks
document.querySelectorAll('.bg-gray-800').forEach(el => {
el.classList.remove('bg-gray-800');
el.classList.add('bg-gray-100');
});
// Update footer
const footer = document.querySelector('footer');
footer.classList.remove('border-gray-800');
footer.classList.add('border-gray-200');
} else {
body.classList.remove('bg-white', 'text-gray-900', 'light');
body.classList.add('bg-gray-900', 'text-gray-100');
darkIcon.classList.remove('hidden');
lightIcon.classList.add('hidden');
prismDark.disabled = false;
prismLight.disabled = true;
// Update header
const header = document.querySelector('header');
header.classList.remove('bg-white', 'border-gray-200');
header.classList.add('bg-gray-900', 'border-gray-800');
// Update code blocks
document.querySelectorAll('.bg-gray-100').forEach(el => {
el.classList.remove('bg-gray-100');
el.classList.add('bg-gray-800');
});
// Update footer
const footer = document.querySelector('footer');
footer.classList.remove('border-gray-200');
footer.classList.add('border-gray-800');
}
// Re-highlight code
Prism.highlightAll();
}
themeToggle.addEventListener('click', () => {
const currentTheme = body.classList.contains('light') ? 'light' : 'dark';
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
setTheme(newTheme);
localStorage.setItem('theme', newTheme);
});
</script>
</body>
</html>