feat(site): 导航收敛为特性/文档/定价,新增定价页与站点自包含截图,dist 产物入库
- homepage/index.html:菜单改为 特性/文档/定价,正文按钮指向 /docs/ 与 /pricing - homepage/pricing.html:新增许可与定价页(License & Pricing) - homepage/assets/screenshots/:6 张文档截图收进站点,构建不再依赖仓库 docs/ 目录 - scripts/build-homepage.py:取图优先 homepage/assets;模板内置 h5 移动端修复(重建不丢);dist/assets 不再重复复制截图 - homepage/dist/:23 个构建产物入库,nginx 直接托管(重建幂等)
No files matched your search
|
After Width: | Height: | Size: 275 KiB |
|
After Width: | Height: | Size: 187 KiB |
|
After Width: | Height: | Size: 115 KiB |
|
After Width: | Height: | Size: 291 KiB |
|
After Width: | Height: | Size: 168 KiB |
|
After Width: | Height: | Size: 184 KiB |
@@ -0,0 +1,58 @@
|
|||||||
|
:root {
|
||||||
|
--brand: #059669; --brand-dark: #047857; --ink: #0f172a; --muted: #64748b;
|
||||||
|
--bg: #f8fafc; --card: #ffffff; --line: #e2e8f0;
|
||||||
|
--code-bg: #0f172a; --code-ink: #e2e8f0;
|
||||||
|
}
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
html { scroll-behavior: smooth; }
|
||||||
|
body { font-family: -apple-system, "PingFang SC", "Microsoft YaHei", "Segoe UI", sans-serif; color: var(--ink); background: var(--bg); line-height: 1.7; }
|
||||||
|
a { color: var(--brand); text-decoration: none; }
|
||||||
|
.container { max-width: 1080px; margin: 0 auto; padding: 0 24px; }
|
||||||
|
|
||||||
|
.nav { position: sticky; top: 0; z-index: 10; background: rgba(255,255,255,.92); backdrop-filter: blur(8px); border-bottom: 1px solid var(--line); }
|
||||||
|
.nav-inner { max-width: 1080px; margin: 0 auto; padding: 14px 24px; display: flex; align-items: center; justify-content: space-between; }
|
||||||
|
.brand { display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 20px; color: var(--ink); }
|
||||||
|
.brand-logo { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; border-radius: 9px; background: linear-gradient(135deg, #10b981, #047857); color: #fff; font-weight: 800; }
|
||||||
|
.nav-links { display: flex; gap: 26px; font-size: 15px; }
|
||||||
|
.nav-links a { color: var(--muted); }
|
||||||
|
.nav-links a:hover { color: var(--ink); }
|
||||||
|
|
||||||
|
.hero { padding: 96px 0 84px; text-align: center; background: radial-gradient(1200px 500px at 50% -100px, rgba(16,185,129,.12), transparent); }
|
||||||
|
.hero h1 { font-size: 46px; line-height: 1.25; letter-spacing: -1px; }
|
||||||
|
.hero h1 em { font-style: normal; color: var(--brand); }
|
||||||
|
.hero p.tagline { margin: 18px auto 0; max-width: 640px; font-size: 19px; color: var(--muted); }
|
||||||
|
.hero-actions { margin-top: 34px; display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; }
|
||||||
|
.btn { display: inline-flex; align-items: center; gap: 8px; padding: 12px 26px; border-radius: 10px; font-size: 16px; font-weight: 600; border: 1px solid transparent; transition: all .15s; }
|
||||||
|
.btn-primary { background: var(--brand); color: #fff; }
|
||||||
|
.btn-primary:hover { background: var(--brand-dark); }
|
||||||
|
.btn-outline { border-color: var(--line); color: var(--ink); background: var(--card); }
|
||||||
|
.btn-outline:hover { border-color: var(--brand); color: var(--brand); }
|
||||||
|
.hero-meta { margin-top: 26px; font-size: 14px; color: var(--muted); }
|
||||||
|
|
||||||
|
section.block { padding: 72px 0; }
|
||||||
|
section.block.alt { background: var(--card); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
|
||||||
|
.block h2 { font-size: 30px; text-align: center; }
|
||||||
|
.block .sub { text-align: center; color: var(--muted); margin-top: 10px; margin-bottom: 44px; }
|
||||||
|
|
||||||
|
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
|
||||||
|
.feature { background: var(--card); border: 1px solid var(--line); border-radius: 14px; padding: 26px; }
|
||||||
|
.feature .icon { width: 42px; height: 42px; border-radius: 10px; display: flex; align-items: center; justify-content: center; background: rgba(16,185,129,.1); color: var(--brand); margin-bottom: 14px; }
|
||||||
|
.feature h3 { font-size: 17px; margin-bottom: 8px; }
|
||||||
|
.feature p { font-size: 14.5px; color: var(--muted); }
|
||||||
|
|
||||||
|
.steps { max-width: 760px; margin: 0 auto; }
|
||||||
|
.step { display: flex; gap: 18px; padding: 18px 0; border-bottom: 1px dashed var(--line); }
|
||||||
|
.step:last-child { border-bottom: none; }
|
||||||
|
.step .no { flex-shrink: 0; width: 34px; height: 34px; border-radius: 50%; background: var(--brand); color: #fff; font-weight: 700; display: flex; align-items: center; justify-content: center; }
|
||||||
|
.step h3 { font-size: 16px; }
|
||||||
|
.step p { font-size: 14.5px; color: var(--muted); margin-top: 4px; }
|
||||||
|
code.inline { background: rgba(16,185,129,.08); color: var(--brand-dark); padding: 2px 7px; border-radius: 5px; font-size: 13.5px; font-family: ui-monospace, "SF Mono", Menlo, monospace; }
|
||||||
|
|
||||||
|
.footer { padding: 40px 0 56px; color: var(--muted); font-size: 14px; text-align: center; }
|
||||||
|
.footer .links { display: flex; gap: 22px; justify-content: center; margin-bottom: 14px; }
|
||||||
|
|
||||||
|
@media (max-width: 840px) {
|
||||||
|
.grid { grid-template-columns: 1fr; }
|
||||||
|
.hero h1 { font-size: 34px; }
|
||||||
|
.nav-links { display: none; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN"><head>
|
||||||
|
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<title>查询授权 · LokiStack 文档</title>
|
||||||
|
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%23059669'/%3E%3Ctext x='32' y='44' font-size='34' font-weight='800' fill='%23fff' text-anchor='middle' font-family='sans-serif'%3EL%3C/text%3E%3C/svg%3E">
|
||||||
|
<link rel="stylesheet" href="/docs/assets/loki-docs.css">
|
||||||
|
<style id="h5-fix">@media (max-width:820px){body{-webkit-text-size-adjust:100%}nav a,nav button,.nav-links a,.nav-menu a,.nav-item,.topnav a,.menu a,.side a,.sidebar a,.docs-side a,.toc a,footer a,a.btn,.plan .btn,button.btn{display:inline-flex;align-items:center;min-height:44px}.side a,.sidebar a,.docs-side a{padding:10px 12px;border-radius:8px}.toc a{padding:8px 0}pre{max-width:100%;overflow-x:auto}.plans,.grid,.grid-2,.grid-3{grid-template-columns:1fr!important}.hero h1,.hero-title{font-size:clamp(24px,7vw,34px)!important}.tbl-scroll{max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}}</style>
|
||||||
|
<script id="h5-fix-js">(function(){var f=function(){document.querySelectorAll("table").forEach(function(t){var p=t.parentElement;if(p&&p.classList&&p.classList.contains("tbl-scroll"))return;var w=document.createElement("div");w.className="tbl-scroll";p.insertBefore(w,t);w.appendChild(t);});};if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",f);else f();})();</script>
|
||||||
|
</head><body>
|
||||||
|
<div class="topbar">
|
||||||
|
<a class="brand" href="/"><i>L</i>LokiStack</a>
|
||||||
|
<span style="color:#98a2b3;font-size:13px">文档</span>
|
||||||
|
<nav class="topnav"><a href="/">官网</a><a href="/docs/" class="on">文档</a></nav>
|
||||||
|
</div>
|
||||||
|
<div class="layout">
|
||||||
|
<aside class="side"><h4>开始使用</h4><a data-slug="readme" href="/docs/readme/">产品介绍</a><a data-slug="install" href="/docs/install/">快速安装</a><a data-slug="wizard" href="/docs/wizard/">部署向导</a><h4>采集与查询</h4><a data-slug="collectors" href="/docs/collectors/">日志采集</a><a data-slug="query" href="/docs/query/">日志查询</a><a data-slug="analysis" href="/docs/analysis/">日志分析</a><a data-slug="access" href="/docs/access/" class="on">查询授权</a><h4>告警与运维</h4><a data-slug="alerts" href="/docs/alerts/">告警通知</a><a data-slug="faq" href="/docs/faq/">常见问题</a></aside>
|
||||||
|
<article>
|
||||||
|
<h1>查询授权</h1>
|
||||||
|
<div class="meta">采集与查询 · 更新于 2026-10-28</div>
|
||||||
|
<p>管理员在「日志查询 → 查询授权」用策略组控制普通用户可见的日志范围:</p>
|
||||||
|
<ul>
|
||||||
|
<li>策略组 = 数据源 + 允许的标签范围(命名空间 / App / Pod,均精确匹配,未选不限) + 关联用户。</li>
|
||||||
|
<li>同一用户在同一数据源只能属于一个策略组;已在其他组的用户置灰。</li>
|
||||||
|
<li>支持快捷的「所有人」策略(默认策略的常用形态)。</li>
|
||||||
|
<li>授权在服务端强制执行:普通用户的查询必须以流选择器开头,策略标签自动合并,无法越权。</li>
|
||||||
|
</ul>
|
||||||
|
<p>用户管理(仅管理员)支持创建/重置密码/批量删除;LDAP 用户可在系统设置接入后导入。</p>
|
||||||
|
<div class="pager"><a href="/docs/analysis/">← 日志分析</a><a href="/docs/alerts/">告警通知 →</a></div>
|
||||||
|
</article>
|
||||||
|
<nav class="toc"><b>本页目录</b></nav>
|
||||||
|
</div>
|
||||||
|
<footer>LokiStack · <a href="/">返回官网</a> · © 日理万机</footer>
|
||||||
|
</body></html>
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN"><head>
|
||||||
|
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<title>告警通知 · LokiStack 文档</title>
|
||||||
|
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%23059669'/%3E%3Ctext x='32' y='44' font-size='34' font-weight='800' fill='%23fff' text-anchor='middle' font-family='sans-serif'%3EL%3C/text%3E%3C/svg%3E">
|
||||||
|
<link rel="stylesheet" href="/docs/assets/loki-docs.css">
|
||||||
|
<style id="h5-fix">@media (max-width:820px){body{-webkit-text-size-adjust:100%}nav a,nav button,.nav-links a,.nav-menu a,.nav-item,.topnav a,.menu a,.side a,.sidebar a,.docs-side a,.toc a,footer a,a.btn,.plan .btn,button.btn{display:inline-flex;align-items:center;min-height:44px}.side a,.sidebar a,.docs-side a{padding:10px 12px;border-radius:8px}.toc a{padding:8px 0}pre{max-width:100%;overflow-x:auto}.plans,.grid,.grid-2,.grid-3{grid-template-columns:1fr!important}.hero h1,.hero-title{font-size:clamp(24px,7vw,34px)!important}.tbl-scroll{max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}}</style>
|
||||||
|
<script id="h5-fix-js">(function(){var f=function(){document.querySelectorAll("table").forEach(function(t){var p=t.parentElement;if(p&&p.classList&&p.classList.contains("tbl-scroll"))return;var w=document.createElement("div");w.className="tbl-scroll";p.insertBefore(w,t);w.appendChild(t);});};if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",f);else f();})();</script>
|
||||||
|
</head><body>
|
||||||
|
<div class="topbar">
|
||||||
|
<a class="brand" href="/"><i>L</i>LokiStack</a>
|
||||||
|
<span style="color:#98a2b3;font-size:13px">文档</span>
|
||||||
|
<nav class="topnav"><a href="/">官网</a><a href="/docs/" class="on">文档</a></nav>
|
||||||
|
</div>
|
||||||
|
<div class="layout">
|
||||||
|
<aside class="side"><h4>开始使用</h4><a data-slug="readme" href="/docs/readme/">产品介绍</a><a data-slug="install" href="/docs/install/">快速安装</a><a data-slug="wizard" href="/docs/wizard/">部署向导</a><h4>采集与查询</h4><a data-slug="collectors" href="/docs/collectors/">日志采集</a><a data-slug="query" href="/docs/query/">日志查询</a><a data-slug="analysis" href="/docs/analysis/">日志分析</a><a data-slug="access" href="/docs/access/">查询授权</a><h4>告警与运维</h4><a data-slug="alerts" href="/docs/alerts/" class="on">告警通知</a><a data-slug="faq" href="/docs/faq/">常见问题</a></aside>
|
||||||
|
<article>
|
||||||
|
<h1>告警通知</h1>
|
||||||
|
<div class="meta">告警与运维 · 更新于 2026-10-28</div>
|
||||||
|
<p>「日志告警」页(<code>/alerts</code>)管理规则、通知通道与发送历史。</p>
|
||||||
|
<p><img alt="告警通知" src="/docs/assets/screenshots/alerts.png" /></p>
|
||||||
|
<h2 id="_1">快速开始</h2>
|
||||||
|
<ol>
|
||||||
|
<li>在「通知通道」中编辑默认通道,填入飞书群机器人 Webhook 并启用。</li>
|
||||||
|
<li>内置九条规则默认启用并已绑定默认通道,命中阈值即发送到群。</li>
|
||||||
|
</ol>
|
||||||
|
<h2 id="_2">规则</h2>
|
||||||
|
<ul>
|
||||||
|
<li>查询为 LogQL 日志流匹配;窗口(分钟)、阈值(条数)、冷却(分钟)三要素。</li>
|
||||||
|
<li>内置规则已排除 Loki 自身日志(app=loki),避免告警查询日志造成自我误报。</li>
|
||||||
|
<li>模板按钮一键填充常用规则(命名空间错误 / Ingress 4xx5xx / FATAL 等)。</li>
|
||||||
|
</ul>
|
||||||
|
<h2 id="_3">通道与发送历史</h2>
|
||||||
|
<ul>
|
||||||
|
<li>通道支持飞书 Webhook(可选签名);可建多通道对应不同告警群。</li>
|
||||||
|
<li>发送历史记录每次触发的命中数、投递结果与失败原因;保留天数在「系统设置 → 日志保留时间」调整。</li>
|
||||||
|
</ul>
|
||||||
|
<h2 id="_4">防刷屏机制</h2>
|
||||||
|
<ul>
|
||||||
|
<li>单规则冷却(默认 ≥ 2 小时);全平台每小时发送上限(风暴抑制)。</li>
|
||||||
|
<li>通道未配置/未启用时命中只记入历史,不影响规则评估。</li>
|
||||||
|
</ul>
|
||||||
|
<div class="pager"><a href="/docs/access/">← 查询授权</a><a href="/docs/faq/">常见问题 →</a></div>
|
||||||
|
</article>
|
||||||
|
<nav class="toc"><b>本页目录</b><a href="#_1">快速开始</a><a href="#_2">规则</a><a href="#_3">通道与发送历史</a><a href="#_4">防刷屏机制</a></nav>
|
||||||
|
</div>
|
||||||
|
<footer>LokiStack · <a href="/">返回官网</a> · © 日理万机</footer>
|
||||||
|
</body></html>
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN"><head>
|
||||||
|
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<title>日志分析 · LokiStack 文档</title>
|
||||||
|
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%23059669'/%3E%3Ctext x='32' y='44' font-size='34' font-weight='800' fill='%23fff' text-anchor='middle' font-family='sans-serif'%3EL%3C/text%3E%3C/svg%3E">
|
||||||
|
<link rel="stylesheet" href="/docs/assets/loki-docs.css">
|
||||||
|
<style id="h5-fix">@media (max-width:820px){body{-webkit-text-size-adjust:100%}nav a,nav button,.nav-links a,.nav-menu a,.nav-item,.topnav a,.menu a,.side a,.sidebar a,.docs-side a,.toc a,footer a,a.btn,.plan .btn,button.btn{display:inline-flex;align-items:center;min-height:44px}.side a,.sidebar a,.docs-side a{padding:10px 12px;border-radius:8px}.toc a{padding:8px 0}pre{max-width:100%;overflow-x:auto}.plans,.grid,.grid-2,.grid-3{grid-template-columns:1fr!important}.hero h1,.hero-title{font-size:clamp(24px,7vw,34px)!important}.tbl-scroll{max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}}</style>
|
||||||
|
<script id="h5-fix-js">(function(){var f=function(){document.querySelectorAll("table").forEach(function(t){var p=t.parentElement;if(p&&p.classList&&p.classList.contains("tbl-scroll"))return;var w=document.createElement("div");w.className="tbl-scroll";p.insertBefore(w,t);w.appendChild(t);});};if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",f);else f();})();</script>
|
||||||
|
</head><body>
|
||||||
|
<div class="topbar">
|
||||||
|
<a class="brand" href="/"><i>L</i>LokiStack</a>
|
||||||
|
<span style="color:#98a2b3;font-size:13px">文档</span>
|
||||||
|
<nav class="topnav"><a href="/">官网</a><a href="/docs/" class="on">文档</a></nav>
|
||||||
|
</div>
|
||||||
|
<div class="layout">
|
||||||
|
<aside class="side"><h4>开始使用</h4><a data-slug="readme" href="/docs/readme/">产品介绍</a><a data-slug="install" href="/docs/install/">快速安装</a><a data-slug="wizard" href="/docs/wizard/">部署向导</a><h4>采集与查询</h4><a data-slug="collectors" href="/docs/collectors/">日志采集</a><a data-slug="query" href="/docs/query/">日志查询</a><a data-slug="analysis" href="/docs/analysis/" class="on">日志分析</a><a data-slug="access" href="/docs/access/">查询授权</a><h4>告警与运维</h4><a data-slug="alerts" href="/docs/alerts/">告警通知</a><a data-slug="faq" href="/docs/faq/">常见问题</a></aside>
|
||||||
|
<article>
|
||||||
|
<h1>日志分析</h1>
|
||||||
|
<div class="meta">采集与查询 · 更新于 2026-10-28</div>
|
||||||
|
<p>「日志分析」页(<code>/analysis</code>,管理员)自动聚合日志指标,无需手动查询:</p>
|
||||||
|
<p><img alt="日志分析" src="/docs/assets/screenshots/analysis.png" /></p>
|
||||||
|
<ul>
|
||||||
|
<li><strong>统计卡</strong>:日志总量、日志体积、错误行数、活跃应用</li>
|
||||||
|
<li><strong>趋势折线</strong>:按时间分桶的日志体积(≤12 小时 15 分钟一桶,>12 小时 1 小时一桶)</li>
|
||||||
|
<li><strong>应用排行</strong>:按<strong>日志体积</strong>排 Top 10,支持 10/30/50 与前端分页,点击「查看日志」跳转查询页</li>
|
||||||
|
<li><strong>每日日志量</strong>:平台留存历史,支持 7 / 30 / 90 / 365 天切换(独立于上方时间范围)</li>
|
||||||
|
<li><strong>Ingress 访问分析</strong>:自动识别 ingress-nginx 访问日志,PV/UV、状态码、慢请求与接口排行;未安装 ingress-nginx 时自动折叠</li>
|
||||||
|
</ul>
|
||||||
|
<h2 id="_1">数据来源与耗时</h2>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>数据</th>
|
||||||
|
<th>来源</th>
|
||||||
|
<th>耗时</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>总量/体积趋势、总条数</td>
|
||||||
|
<td>Loki 索引接口(<code>index/volume_range</code>、<code>index/stats</code>),只读 chunk 元数据</td>
|
||||||
|
<td>百毫秒级</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>≤1 小时范围的应用排行</td>
|
||||||
|
<td>实时扫描日志内容(<code>count_over_time</code>)</td>
|
||||||
|
<td>5 分钟窗口约 5~10 秒</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>>1 小时范围的应用排行</td>
|
||||||
|
<td>平台<strong>按小时预聚合快照</strong>(每小时第 5 分钟抓上一个完整小时)</td>
|
||||||
|
<td>毫秒级</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<blockquote>
|
||||||
|
<p>一次分析页要跑多条按应用的重查询,因此筛选栏改条件后<strong>点「刷新」才生效</strong>;<br />
|
||||||
|
应用排行卡片滚动到可视区才发起重查询,避免首屏一起等。</p>
|
||||||
|
</blockquote>
|
||||||
|
<h2 id="_2">应用排行的「体积」口径</h2>
|
||||||
|
<p>预聚合快照对每个应用每小时同时留存 <strong>条数 + 体积</strong>:</p>
|
||||||
|
<ul>
|
||||||
|
<li>条数走 <code>count_over_time</code>(要解码日志内容,一小时代价高,每小时后台跑一次)</li>
|
||||||
|
<li>体积走 <code>index/volume</code>(Loki 索引接口,一个应用约 80ms,所以长范围排行也能按体积排序)</li>
|
||||||
|
</ul>
|
||||||
|
<p>体积优先排序的原因:条数会被高频短日志主导(一条 INFO 刷屏 vs 一条大 JSON),<br />
|
||||||
|
用户真正关心的是「哪个应用把日志量吃掉了」。</p>
|
||||||
|
<p>体积列上线前抓的小时只有条数,页面会在表格下方提示<br />
|
||||||
|
「其中 N/M 小时有体积数据…」——<strong>不要把这个提示当成故障</strong>,<br />
|
||||||
|
它是在说明这段时间的体积偏小是采样口径问题,而不是应用体积真的小。</p>
|
||||||
|
<h2 id="_3">每日日志量的「未留存」</h2>
|
||||||
|
<p>每日量来自平台自己的留存库(默认保留 400 天),不受 Loki retention(72 小时)限制。</p>
|
||||||
|
<ul>
|
||||||
|
<li><strong>今天的柱子</strong>是「进行中」,每 30 分钟刷新一次;零点后 1 分钟结算前一天</li>
|
||||||
|
<li><strong>灰色柱 = 平台没有留存记录</strong>(平台当天没运行 / 超出留存期),<strong>不是「当天没有日志」</strong></li>
|
||||||
|
<li>如果缺失的天画成 0,30/90 天视角会出现大片空柱,容易被误读成「以前日志量很低」甚至「系统停摆过」</li>
|
||||||
|
</ul>
|
||||||
|
<p>时间范围与数据源在页面顶部切换;指标查询经服务端聚合,开销远低于拉取原始日志。</p>
|
||||||
|
<div class="pager"><a href="/docs/query/">← 日志查询</a><a href="/docs/access/">查询授权 →</a></div>
|
||||||
|
</article>
|
||||||
|
<nav class="toc"><b>本页目录</b><a href="#_1">数据来源与耗时</a><a href="#_2">应用排行的「体积」口径</a><a href="#_3">每日日志量的「未留存」</a></nav>
|
||||||
|
</div>
|
||||||
|
<footer>LokiStack · <a href="/">返回官网</a> · © 日理万机</footer>
|
||||||
|
</body></html>
|
||||||
@@ -0,0 +1,255 @@
|
|||||||
|
/* OpsxAPI 文档站 —— 清爽专业风格(浅色) */
|
||||||
|
:root {
|
||||||
|
--blue: #059669;
|
||||||
|
--blue-dark: #047857;
|
||||||
|
--blue-soft: rgba(5, 150, 105, 0.08);
|
||||||
|
--bg: #f6f8fb;
|
||||||
|
--panel: #ffffff;
|
||||||
|
--border: #e4e9f1;
|
||||||
|
--text: #1c2434;
|
||||||
|
--text-2: #5b6880;
|
||||||
|
--text-3: #98a2b3;
|
||||||
|
--code-bg: #f3f6fb;
|
||||||
|
--code-border: #e1e8f3;
|
||||||
|
--green: #059669;
|
||||||
|
--amber: #b45309;
|
||||||
|
--red: #dc2626;
|
||||||
|
--sidebar-w: 262px;
|
||||||
|
--toc-w: 220px;
|
||||||
|
--topbar-h: 56px;
|
||||||
|
--radius: 10px;
|
||||||
|
--shadow: 0 1px 3px rgba(16, 24, 40, 0.06), 0 8px 24px rgba(16, 24, 40, 0.05);
|
||||||
|
--mono: "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace;
|
||||||
|
}
|
||||||
|
* { box-sizing: border-box; }
|
||||||
|
html { scroll-behavior: smooth; scroll-padding-top: 72px; }
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", "Segoe UI", sans-serif;
|
||||||
|
background: var(--bg);
|
||||||
|
color: var(--text);
|
||||||
|
font-size: 14.5px;
|
||||||
|
line-height: 1.75;
|
||||||
|
}
|
||||||
|
a { color: var(--blue); text-decoration: none; }
|
||||||
|
.i { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; vertical-align: -2px; }
|
||||||
|
a:hover { color: var(--blue-dark); text-decoration: underline; }
|
||||||
|
|
||||||
|
/* ---------- 顶栏 ---------- */
|
||||||
|
.topbar {
|
||||||
|
position: sticky; top: 0; z-index: 50;
|
||||||
|
background: rgba(255, 255, 255, 0.92);
|
||||||
|
backdrop-filter: saturate(1.4) blur(8px);
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
.topbar-inner {
|
||||||
|
max-width: 1440px; margin: 0 auto; height: var(--topbar-h);
|
||||||
|
display: flex; align-items: center; gap: 14px; padding: 0 20px;
|
||||||
|
}
|
||||||
|
.menu-btn {
|
||||||
|
display: none; border: 1px solid var(--border); background: #fff;
|
||||||
|
border-radius: 8px; width: 34px; height: 34px; cursor: pointer; color: var(--text-2);
|
||||||
|
place-items: center;
|
||||||
|
}
|
||||||
|
.menu-btn .i { width: 17px; height: 17px; }
|
||||||
|
.brand { display: flex; align-items: center; gap: 9px; text-decoration: none !important; }
|
||||||
|
.brand-logo { display: inline-flex; }
|
||||||
|
.brand-logo svg { display: block; border-radius: 7px; }
|
||||||
|
.brand-name { font-size: 16px; font-weight: 700; color: var(--text); }
|
||||||
|
.brand-name em { font-style: normal; font-weight: 500; color: var(--text-2); margin-left: 2px; }
|
||||||
|
.ver-badge {
|
||||||
|
font-size: 11px; font-weight: 600; color: var(--blue);
|
||||||
|
background: var(--blue-soft); border: 1px solid rgba(5, 150, 105, 0.22);
|
||||||
|
padding: 1px 9px; border-radius: 999px; white-space: nowrap;
|
||||||
|
}
|
||||||
|
.search { position: relative; flex: 1; max-width: 420px; margin-left: 8px; }
|
||||||
|
.search input {
|
||||||
|
width: 100%; height: 36px; border: 1px solid var(--border); border-radius: 9px;
|
||||||
|
background: var(--bg); padding: 0 14px 0 34px; font-size: 13.5px; color: var(--text); outline: none;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' fill='none' stroke='%2398a2b3' stroke-width='2' viewBox='0 0 24 24'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.5-3.5'/%3E%3C/svg%3E");
|
||||||
|
background-repeat: no-repeat; background-position: 12px center;
|
||||||
|
}
|
||||||
|
.search input:focus { border-color: var(--blue); background: #fff; box-shadow: 0 0 0 3px var(--blue-soft); }
|
||||||
|
.search-panel {
|
||||||
|
position: absolute; top: 44px; left: 0; right: 0; background: #fff;
|
||||||
|
border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow);
|
||||||
|
max-height: 420px; overflow: auto; padding: 6px;
|
||||||
|
}
|
||||||
|
.search-item { display: block; padding: 8px 12px; border-radius: 8px; text-decoration: none !important; }
|
||||||
|
.search-item:hover, .search-item.sel { background: var(--blue-soft); }
|
||||||
|
.search-item .si-title { font-weight: 600; color: var(--text); font-size: 13.5px; }
|
||||||
|
.search-item .si-group { color: var(--text-3); font-size: 11px; margin-left: 6px; }
|
||||||
|
.search-item .si-snippet { color: var(--text-2); font-size: 12px; margin-top: 2px; display: block; }
|
||||||
|
.search-empty { padding: 14px; text-align: center; color: var(--text-3); font-size: 13px; }
|
||||||
|
.top-links { margin-left: auto; display: flex; gap: 16px; align-items: center; }
|
||||||
|
.top-links a { font-size: 13.5px; font-weight: 500; }
|
||||||
|
|
||||||
|
/* ---------- 三栏布局 ---------- */
|
||||||
|
.layout {
|
||||||
|
max-width: 1440px; margin: 0 auto; display: grid;
|
||||||
|
grid-template-columns: var(--sidebar-w) minmax(0, 1fr) var(--toc-w);
|
||||||
|
gap: 0 28px; padding: 24px 20px 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 侧栏 */
|
||||||
|
.sidebar { position: sticky; top: calc(var(--topbar-h) + 24px); align-self: start; max-height: calc(100vh - var(--topbar-h) - 48px); overflow-y: auto; padding-right: 8px; }
|
||||||
|
.sidebar::-webkit-scrollbar { width: 4px; }
|
||||||
|
.sidebar::-webkit-scrollbar-thumb { background: #d6dde8; border-radius: 4px; }
|
||||||
|
.nav-group { margin-bottom: 18px; }
|
||||||
|
.nav-group-title {
|
||||||
|
font-size: 11.5px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
|
||||||
|
color: var(--text-3); padding: 0 10px 6px;
|
||||||
|
}
|
||||||
|
.nav-link {
|
||||||
|
display: block; padding: 6px 10px; border-radius: 8px; font-size: 13.5px;
|
||||||
|
color: var(--text-2); text-decoration: none !important; border-left: 2px solid transparent;
|
||||||
|
}
|
||||||
|
.nav-link:hover { background: rgba(5, 150, 105, 0.06); color: var(--text); }
|
||||||
|
.nav-link.active {
|
||||||
|
background: var(--blue-soft); color: var(--blue-dark); font-weight: 600;
|
||||||
|
border-left-color: var(--blue);
|
||||||
|
}
|
||||||
|
.sidebar-foot { margin-top: 24px; padding: 12px 10px 0; border-top: 1px solid var(--border); font-size: 11.5px; color: var(--text-3); }
|
||||||
|
|
||||||
|
/* 内容 */
|
||||||
|
.content { min-width: 0; max-width: 860px; }
|
||||||
|
.breadcrumb { font-size: 12.5px; color: var(--text-3); margin-bottom: 10px; }
|
||||||
|
.breadcrumb span { margin: 0 6px; }
|
||||||
|
.page-title { font-size: 30px; font-weight: 700; letter-spacing: -0.02em; margin: 0 0 6px; line-height: 1.3; }
|
||||||
|
.page-meta { font-size: 12.5px; color: var(--text-3); margin-bottom: 22px; }
|
||||||
|
|
||||||
|
/* Markdown 排版 */
|
||||||
|
.md h2 { font-size: 21px; font-weight: 700; margin: 38px 0 12px; padding-top: 8px; letter-spacing: -0.01em; }
|
||||||
|
.md h3 { font-size: 16.5px; font-weight: 700; margin: 26px 0 8px; }
|
||||||
|
.md h2 + h3, .md h1 + h2 { margin-top: 18px; }
|
||||||
|
.md p { margin: 10px 0; color: #2a3348; }
|
||||||
|
.md ul, .md ol { padding-left: 22px; margin: 10px 0; }
|
||||||
|
.md li { margin: 5px 0; color: #2a3348; }
|
||||||
|
.md li::marker { color: var(--blue); }
|
||||||
|
.md strong { color: var(--text); }
|
||||||
|
.md hr { border: none; border-top: 1px solid var(--border); margin: 30px 0; }
|
||||||
|
.md img { max-width: 100%; border-radius: var(--radius); border: 1px solid var(--border); }
|
||||||
|
.md blockquote {
|
||||||
|
margin: 14px 0; padding: 10px 16px; border-left: 3px solid var(--blue);
|
||||||
|
background: var(--blue-soft); border-radius: 0 8px 8px 0; color: #33415e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 表格 */
|
||||||
|
.md table { border-collapse: collapse; width: 100%; margin: 16px 0; font-size: 13.5px; background: #fff; border-radius: var(--radius); overflow: hidden; box-shadow: 0 0 0 1px var(--border); }
|
||||||
|
.md th, .md td { padding: 9px 14px; text-align: left; border-bottom: 1px solid var(--border); vertical-align: top; }
|
||||||
|
.md th { background: #f9fbfe; font-weight: 600; color: var(--text); white-space: nowrap; }
|
||||||
|
.md tr:last-child td { border-bottom: none; }
|
||||||
|
|
||||||
|
/* 代码块 */
|
||||||
|
.md code { font-family: var(--mono); font-size: 12.8px; background: var(--code-bg); border: 1px solid var(--code-border); border-radius: 5px; padding: 1px 6px; color: #334155; }
|
||||||
|
.md pre {
|
||||||
|
position: relative; background: #0f172a; color: #dbe4f3; border-radius: var(--radius);
|
||||||
|
padding: 16px 16px 14px; overflow-x: auto; margin: 16px 0; font-size: 13px; line-height: 1.65;
|
||||||
|
}
|
||||||
|
.md pre code { background: none; border: none; color: inherit; padding: 0; font-size: inherit; }
|
||||||
|
.md pre .lang-tag {
|
||||||
|
position: absolute; top: 8px; right: 12px; font-size: 10.5px; color: #7c8db0;
|
||||||
|
font-family: var(--mono); text-transform: lowercase; letter-spacing: 0.04em;
|
||||||
|
}
|
||||||
|
.md pre .copy-btn {
|
||||||
|
position: absolute; top: 6px; right: 60px; font-size: 11px; color: #9fb0d0;
|
||||||
|
background: rgba(255, 255, 255, 0.07); border: none; border-radius: 6px; padding: 2px 9px; cursor: pointer;
|
||||||
|
opacity: 0; transition: opacity 0.15s;
|
||||||
|
}
|
||||||
|
.md pre:hover .copy-btn { opacity: 1; }
|
||||||
|
.md pre .copy-btn:hover { color: #fff; background: rgba(255, 255, 255, 0.14); }
|
||||||
|
/* 行内高亮 token */
|
||||||
|
.md pre .tok-key { color: #7dd3fc; }
|
||||||
|
.md pre .tok-str { color: #86efac; }
|
||||||
|
.md pre .tok-num { color: #fcd34d; }
|
||||||
|
.md pre .tok-com { color: #64748b; font-style: italic; }
|
||||||
|
|
||||||
|
/* 提示块(通过 blockquote 首字符约定) */
|
||||||
|
.md blockquote.tip { border-left-color: var(--green); background: rgba(5, 150, 105, 0.07); }
|
||||||
|
.md blockquote.warn { border-left-color: var(--amber); background: rgba(180, 83, 9, 0.07); }
|
||||||
|
|
||||||
|
/* 上下页 */
|
||||||
|
.pn-nav { display: flex; gap: 14px; margin-top: 48px; }
|
||||||
|
.pn {
|
||||||
|
flex: 1; border: 1px solid var(--border); background: #fff; border-radius: var(--radius);
|
||||||
|
padding: 13px 16px; text-decoration: none !important; transition: border-color 0.15s, box-shadow 0.15s;
|
||||||
|
}
|
||||||
|
.pn:hover { border-color: var(--blue); box-shadow: var(--shadow); }
|
||||||
|
.pn.next { text-align: right; }
|
||||||
|
.pn-label { display: block; font-size: 11.5px; color: var(--text-3); }
|
||||||
|
.pn-title { display: block; font-weight: 600; color: var(--text); font-size: 14px; margin-top: 2px; }
|
||||||
|
|
||||||
|
/* 右侧目录 */
|
||||||
|
.toc { position: sticky; top: calc(var(--topbar-h) + 24px); align-self: start; max-height: calc(100vh - var(--topbar-h) - 48px); overflow-y: auto; padding-top: 34px; }
|
||||||
|
.toc-title { font-size: 11.5px; font-weight: 700; letter-spacing: 0.08em; color: var(--text-3); margin-bottom: 8px; }
|
||||||
|
.toc-nav { display: flex; flex-direction: column; gap: 1px; border-left: 2px solid var(--border); padding-left: 0; }
|
||||||
|
.toc-nav a {
|
||||||
|
font-size: 12.5px; color: var(--text-2); padding: 4px 0 4px 12px; text-decoration: none !important;
|
||||||
|
border-left: 2px solid transparent; margin-left: -2px; line-height: 1.5;
|
||||||
|
}
|
||||||
|
.toc-nav a:hover { color: var(--blue); }
|
||||||
|
.toc-nav a.toc-l3 { padding-left: 26px; font-size: 12px; color: var(--text-3); }
|
||||||
|
.toc-nav a.active { color: var(--blue); border-left-color: var(--blue); font-weight: 600; }
|
||||||
|
/* 404 */
|
||||||
|
.doc-404 { display: grid; place-items: center; min-height: 100vh; text-align: center; }
|
||||||
|
.doc-404 h1 { font-size: 56px; margin: 0; color: var(--blue); }
|
||||||
|
.doc-404 .btn {
|
||||||
|
display: inline-block; margin-top: 12px; background: var(--blue); color: #fff;
|
||||||
|
padding: 8px 18px; border-radius: 8px; text-decoration: none !important; font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- 响应式 ---------- */
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.layout { grid-template-columns: var(--sidebar-w) minmax(0, 1fr); }
|
||||||
|
.toc { display: none; }
|
||||||
|
}
|
||||||
|
@media (max-width: 880px) {
|
||||||
|
.menu-btn { display: inline-grid; place-items: center; }
|
||||||
|
.layout { grid-template-columns: minmax(0, 1fr); padding-top: 12px; }
|
||||||
|
.sidebar {
|
||||||
|
position: fixed; z-index: 60; left: 0; top: var(--topbar-h); bottom: 0;
|
||||||
|
width: 280px; background: #fff; border-right: 1px solid var(--border);
|
||||||
|
padding: 16px; transform: translateX(-100%); transition: transform 0.2s; max-height: none;
|
||||||
|
}
|
||||||
|
.sidebar.open { transform: none; box-shadow: var(--shadow); }
|
||||||
|
.ver-badge { display: none; }
|
||||||
|
.top-links a { font-size: 12.5px; }
|
||||||
|
.page-title { font-size: 24px; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- 打印 ---------- */
|
||||||
|
@media print {
|
||||||
|
.topbar, .sidebar, .toc, .pn-nav, .feedback, .menu-btn { display: none !important; }
|
||||||
|
.layout { display: block; max-width: none; padding: 0; }
|
||||||
|
body { background: #fff; }
|
||||||
|
.md pre { background: #f1f5f9 !important; color: #1e293b !important; }
|
||||||
|
.md pre .copy-btn, .md pre .lang-tag { display: none; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- LokiStack 品牌适配 ---------- */
|
||||||
|
.brand-logo {
|
||||||
|
display: inline-flex; align-items: center; justify-content: center;
|
||||||
|
width: 28px; height: 28px; border-radius: 8px;
|
||||||
|
background: linear-gradient(135deg, #10b981, #047857);
|
||||||
|
color: #fff; font-weight: 800; font-size: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式(窄屏收起侧栏与目录) */
|
||||||
|
@media (max-width: 1100px) {
|
||||||
|
.layout { grid-template-columns: var(--sidebar-w) minmax(0, 1fr); }
|
||||||
|
.toc { display: none; }
|
||||||
|
}
|
||||||
|
@media (max-width: 860px) {
|
||||||
|
.layout { grid-template-columns: minmax(0, 1fr); padding: 16px 14px 40px; }
|
||||||
|
.menu-btn { display: grid; }
|
||||||
|
.sidebar {
|
||||||
|
position: fixed; z-index: 60; top: var(--topbar-h); left: 0; bottom: 0;
|
||||||
|
width: var(--sidebar-w); background: #fff; border-right: 1px solid var(--border);
|
||||||
|
transform: translateX(-100%); transition: transform 0.2s; max-height: none; padding: 14px 10px;
|
||||||
|
}
|
||||||
|
.sidebar.open { transform: none; box-shadow: var(--shadow); }
|
||||||
|
.search { max-width: none; }
|
||||||
|
.top-links { display: none; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.pn-empty { flex: 1; }
|
||||||
@@ -0,0 +1,196 @@
|
|||||||
|
/* LokiStack 文档站交互:搜索 / 代码复制 / 目录高亮 / 移动端导航(参考 opsxapi 体系) */
|
||||||
|
(function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/* ---------- 代码块:语言标签 + 复制按钮 + 轻量高亮 ---------- */
|
||||||
|
document.querySelectorAll("article.md pre").forEach(function (pre) {
|
||||||
|
var code = pre.querySelector("code");
|
||||||
|
if (!code) return;
|
||||||
|
var lang = (code.className.match(/language-([\w-]+)/) || [, ""])[1];
|
||||||
|
if (lang) {
|
||||||
|
var tag = document.createElement("span");
|
||||||
|
tag.className = "lang-tag";
|
||||||
|
tag.textContent = lang;
|
||||||
|
pre.appendChild(tag);
|
||||||
|
}
|
||||||
|
// 复制按钮
|
||||||
|
var btn = document.createElement("button");
|
||||||
|
btn.className = "copy-btn";
|
||||||
|
btn.type = "button";
|
||||||
|
btn.textContent = "复制";
|
||||||
|
btn.addEventListener("click", function () {
|
||||||
|
navigator.clipboard.writeText(code.textContent).then(
|
||||||
|
function () {
|
||||||
|
btn.textContent = "已复制 ✓";
|
||||||
|
setTimeout(function () { btn.textContent = "复制"; }, 1400);
|
||||||
|
},
|
||||||
|
function () { btn.textContent = "复制失败"; }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
pre.appendChild(btn);
|
||||||
|
// JSON / bash 轻量高亮
|
||||||
|
if (lang === "json") highlightJSON(code);
|
||||||
|
else if (lang === "bash" || lang === "sh" || lang === "shell") highlightBash(code);
|
||||||
|
});
|
||||||
|
|
||||||
|
function esc(s) {
|
||||||
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
||||||
|
}
|
||||||
|
function highlightJSON(code) {
|
||||||
|
var src = code.textContent;
|
||||||
|
code.innerHTML = esc(src).replace(
|
||||||
|
/("(?:\\.|[^"\\])*")(\s*:)?|\b(true|false|null)\b|(-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)/g,
|
||||||
|
function (m, str, colon, kw, num) {
|
||||||
|
if (str && colon) return '<span class="tok-key">' + str + "</span>" + colon;
|
||||||
|
if (str) return '<span class="tok-str">' + str + "</span>";
|
||||||
|
if (kw) return '<span class="tok-num">' + kw + "</span>";
|
||||||
|
if (num) return '<span class="tok-num">' + num + "</span>";
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function highlightBash(code) {
|
||||||
|
var lines = code.textContent.split("\n");
|
||||||
|
code.innerHTML = lines
|
||||||
|
.map(function (line) {
|
||||||
|
if (/^\s*#/.test(line)) return '<span class="tok-com">' + esc(line) + "</span>";
|
||||||
|
return esc(line).replace(/(^|\s)(-{1,2}[\w-]+)/g, '$1<span class="tok-key">$2</span>');
|
||||||
|
})
|
||||||
|
.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- blockquote 提示样式约定:> **提示** / > **注意** ---------- */
|
||||||
|
document.querySelectorAll("article.md blockquote").forEach(function (bq) {
|
||||||
|
var t = (bq.textContent || "").trim();
|
||||||
|
if (/^(注意|警告|⚠)/.test(t)) bq.classList.add("warn");
|
||||||
|
else if (/^(提示|说明|💡|Tip)/i.test(t)) bq.classList.add("tip");
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ---------- 搜索 ---------- */
|
||||||
|
var input = document.getElementById("search-input");
|
||||||
|
var panel = document.getElementById("search-panel");
|
||||||
|
var entries = null;
|
||||||
|
var selIndex = -1;
|
||||||
|
|
||||||
|
function ensureIndex(cb) {
|
||||||
|
if (entries) return cb();
|
||||||
|
fetch("/docs/search-data.json")
|
||||||
|
.then(function (r) { return r.json(); })
|
||||||
|
.then(function (data) { entries = data; cb(); })
|
||||||
|
.catch(function () { entries = []; cb(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
function snippet(text, q) {
|
||||||
|
var i = text.toLowerCase().indexOf(q);
|
||||||
|
if (i < 0) return text.slice(0, 60) + "…";
|
||||||
|
var start = Math.max(0, i - 24);
|
||||||
|
return (start > 0 ? "…" : "") + text.slice(start, i + q.length + 40) + "…";
|
||||||
|
}
|
||||||
|
|
||||||
|
function doSearch() {
|
||||||
|
var q = input.value.trim().toLowerCase();
|
||||||
|
selIndex = -1;
|
||||||
|
if (!q) { panel.hidden = true; return; }
|
||||||
|
ensureIndex(function () {
|
||||||
|
var hits = [];
|
||||||
|
entries.forEach(function (e) {
|
||||||
|
var titleHit = e.title.toLowerCase().indexOf(q) >= 0;
|
||||||
|
var idx = e.text.toLowerCase().indexOf(q);
|
||||||
|
if (titleHit || idx >= 0) {
|
||||||
|
hits.push({
|
||||||
|
slug: e.slug,
|
||||||
|
title: e.title,
|
||||||
|
group: e.group,
|
||||||
|
score: (titleHit ? 10 : 0) + (idx === 0 ? 3 : 0),
|
||||||
|
snippet: titleHit ? snippet(e.text, q) : snippet(e.text, q),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
hits.sort(function (a, b) { return b.score - a.score; });
|
||||||
|
hits = hits.slice(0, 8);
|
||||||
|
if (!hits.length) {
|
||||||
|
panel.innerHTML = '<div class="search-empty">没有找到相关内容,换个关键词试试</div>';
|
||||||
|
} else {
|
||||||
|
panel.innerHTML = hits
|
||||||
|
.map(function (h) {
|
||||||
|
return (
|
||||||
|
'<a class="search-item" href="/docs/' + h.slug + '">' +
|
||||||
|
'<span class="si-title">' + h.title + '</span><span class="si-group">' + h.group + "</span>" +
|
||||||
|
'<span class="si-snippet">' + h.snippet + "</span></a>"
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.join("");
|
||||||
|
}
|
||||||
|
panel.hidden = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var debounce;
|
||||||
|
if (input) {
|
||||||
|
input.addEventListener("input", function () {
|
||||||
|
clearTimeout(debounce);
|
||||||
|
debounce = setTimeout(doSearch, 160);
|
||||||
|
});
|
||||||
|
input.addEventListener("focus", function () {
|
||||||
|
if (input.value.trim()) doSearch();
|
||||||
|
});
|
||||||
|
input.addEventListener("keydown", function (e) {
|
||||||
|
var items = panel.querySelectorAll(".search-item");
|
||||||
|
if (e.key === "ArrowDown" && items.length) {
|
||||||
|
e.preventDefault();
|
||||||
|
selIndex = Math.min(selIndex + 1, items.length - 1);
|
||||||
|
} else if (e.key === "ArrowUp" && items.length) {
|
||||||
|
e.preventDefault();
|
||||||
|
selIndex = Math.max(selIndex - 1, 0);
|
||||||
|
} else if (e.key === "Enter") {
|
||||||
|
if (selIndex >= 0 && items[selIndex]) { location.href = items[selIndex].href; return; }
|
||||||
|
var first = items[0];
|
||||||
|
if (first) location.href = first.href;
|
||||||
|
return;
|
||||||
|
} else if (e.key === "Escape") {
|
||||||
|
panel.hidden = true;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
items.forEach(function (el, i) { el.classList.toggle("sel", i === selIndex); });
|
||||||
|
});
|
||||||
|
document.addEventListener("click", function (e) {
|
||||||
|
if (!e.target.closest(".search")) panel.hidden = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- 目录滚动高亮 ---------- */
|
||||||
|
var tocLinks = Array.prototype.slice.call(document.querySelectorAll(".toc-nav a"));
|
||||||
|
if (tocLinks.length && "IntersectionObserver" in window) {
|
||||||
|
var byId = {};
|
||||||
|
tocLinks.forEach(function (a) { byId[a.getAttribute("href").slice(1)] = a; });
|
||||||
|
var io = new IntersectionObserver(
|
||||||
|
function (entries) {
|
||||||
|
entries.forEach(function (en) {
|
||||||
|
if (en.isIntersecting) {
|
||||||
|
tocLinks.forEach(function (a) { a.classList.remove("active"); });
|
||||||
|
var a = byId[en.target.id];
|
||||||
|
if (a) a.classList.add("active");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ rootMargin: "-72px 0px -70% 0px", threshold: 0 }
|
||||||
|
);
|
||||||
|
document.querySelectorAll("article.md h2[id], article.md h3[id]").forEach(function (h) { io.observe(h); });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------- 移动端侧栏 ---------- */
|
||||||
|
var menuBtn = document.getElementById("menu-btn");
|
||||||
|
var sidebar = document.getElementById("sidebar");
|
||||||
|
if (menuBtn && sidebar) {
|
||||||
|
menuBtn.addEventListener("click", function () { sidebar.classList.toggle("open"); });
|
||||||
|
document.addEventListener("click", function (e) {
|
||||||
|
if (sidebar.classList.contains("open") && !e.target.closest(".sidebar") && !e.target.closest(".menu-btn")) {
|
||||||
|
sidebar.classList.remove("open");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})();
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
|
||||||
|
:root{--brand:#059669;--brand-d: #047857;--ink:#0f172a;--muted:#5b6676;--line:#e6e9ee;--bg:#fff;--side:#f7f9f8}
|
||||||
|
*{box-sizing:border-box}
|
||||||
|
body{margin:0;font:15px/1.75 -apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;color:var(--ink);background:var(--bg)}
|
||||||
|
a{color:var(--brand-d);text-decoration:none}a:hover{text-decoration:underline}
|
||||||
|
.topbar{position:sticky;top:0;z-index:20;display:flex;align-items:center;gap:18px;height:56px;padding:0 20px;background:rgba(255,255,255,.92);backdrop-filter:blur(8px);border-bottom:1px solid var(--line)}
|
||||||
|
.brand{display:flex;align-items:center;gap:9px;font-weight:800;font-size:15px;color:var(--ink)}
|
||||||
|
.brand i{width:26px;height:26px;border-radius:8px;background:var(--brand);color:#fff;display:grid;place-items:center;font-style:normal;font-weight:800;font-size:14px}
|
||||||
|
.topnav{display:flex;gap:16px;margin-left:auto;font-size:14px}
|
||||||
|
.topnav a{color:var(--muted)}.topnav a:hover{color:var(--brand-d)}
|
||||||
|
.layout{display:grid;grid-template-columns:250px minmax(0,1fr) 200px;gap:34px;max-width:1240px;margin:0 auto;padding:26px 20px 70px}
|
||||||
|
aside.side{position:sticky;top:80px;align-self:start;max-height:calc(100vh - 100px);overflow:auto;font-size:14px}
|
||||||
|
.side h4{margin:18px 0 6px;font-size:11px;letter-spacing:.09em;text-transform:uppercase;color:#93a0af;font-weight:700}
|
||||||
|
.side a{display:block;padding:5px 10px;border-radius:7px;color:#3b4656}
|
||||||
|
.side a:hover{background:var(--side);text-decoration:none}
|
||||||
|
.side a.on{background:#e8f7f1;color:var(--brand-d);font-weight:650}
|
||||||
|
article{min-width:0}
|
||||||
|
article h1{font-size:30px;line-height:1.3;margin:0 0 8px;letter-spacing:-.01em}
|
||||||
|
.meta{color:#98a2b3;font-size:12.5px;margin-bottom:22px}
|
||||||
|
article h2{font-size:21px;margin:32px 0 10px;padding-bottom:7px;border-bottom:1px solid var(--line)}
|
||||||
|
article h3{font-size:17px;margin:24px 0 8px}
|
||||||
|
article p{margin:12px 0}
|
||||||
|
article img{max-width:100%;height:auto;border:1px solid var(--line);border-radius:10px;margin:14px 0;box-shadow:0 1px 3px rgba(16,24,40,.06)}
|
||||||
|
article pre{background:#0f172a;color:#e6edf3;padding:14px 16px;border-radius:10px;overflow:auto;font-size:13px;line-height:1.6}
|
||||||
|
article code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px}
|
||||||
|
article :not(pre)>code{background:#f1f5f9;padding:2px 5px;border-radius:5px;color:#0f766e}
|
||||||
|
article table{border-collapse:collapse;width:100%;margin:14px 0;font-size:14px}
|
||||||
|
article th,article td{border:1px solid var(--line);padding:8px 10px;text-align:left}
|
||||||
|
article th{background:var(--side)}
|
||||||
|
article blockquote{margin:14px 0;padding:10px 16px;border-left:3px solid var(--brand);background:#f4fbf8;color:#33415c;border-radius:0 8px 8px 0}
|
||||||
|
.toc{position:sticky;top:84px;align-self:start;font-size:13px;color:var(--muted)}
|
||||||
|
.toc b{display:block;font-size:11px;letter-spacing:.09em;text-transform:uppercase;color:#93a0af;margin-bottom:8px}
|
||||||
|
.toc a{display:block;padding:3px 0 3px 10px;border-left:2px solid var(--line);color:#5b6676}
|
||||||
|
.toc a:hover{color:var(--brand-d);border-color:var(--brand)}
|
||||||
|
.pager{display:flex;justify-content:space-between;gap:16px;margin-top:46px;padding-top:18px;border-top:1px solid var(--line);font-size:14px}
|
||||||
|
footer{border-top:1px solid var(--line);padding:20px;text-align:center;color:#98a2b3;font-size:12.5px}
|
||||||
|
@media (max-width:1080px){.layout{grid-template-columns:230px minmax(0,1fr)}.toc{display:none}}
|
||||||
|
@media (max-width:820px){.layout{grid-template-columns:1fr;padding-top:16px}aside.side{position:static;max-height:none;border-bottom:1px solid var(--line);padding-bottom:10px}.topnav{display:none}}
|
||||||
|
After Width: | Height: | Size: 275 KiB |
|
After Width: | Height: | Size: 187 KiB |
|
After Width: | Height: | Size: 115 KiB |
|
After Width: | Height: | Size: 291 KiB |
|
After Width: | Height: | Size: 168 KiB |
|
After Width: | Height: | Size: 184 KiB |
@@ -0,0 +1,58 @@
|
|||||||
|
:root {
|
||||||
|
--brand: #059669; --brand-dark: #047857; --ink: #0f172a; --muted: #64748b;
|
||||||
|
--bg: #f8fafc; --card: #ffffff; --line: #e2e8f0;
|
||||||
|
--code-bg: #0f172a; --code-ink: #e2e8f0;
|
||||||
|
}
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
html { scroll-behavior: smooth; }
|
||||||
|
body { font-family: -apple-system, "PingFang SC", "Microsoft YaHei", "Segoe UI", sans-serif; color: var(--ink); background: var(--bg); line-height: 1.7; }
|
||||||
|
a { color: var(--brand); text-decoration: none; }
|
||||||
|
.container { max-width: 1080px; margin: 0 auto; padding: 0 24px; }
|
||||||
|
|
||||||
|
.nav { position: sticky; top: 0; z-index: 10; background: rgba(255,255,255,.92); backdrop-filter: blur(8px); border-bottom: 1px solid var(--line); }
|
||||||
|
.nav-inner { max-width: 1080px; margin: 0 auto; padding: 14px 24px; display: flex; align-items: center; justify-content: space-between; }
|
||||||
|
.brand { display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 20px; color: var(--ink); }
|
||||||
|
.brand-logo { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; border-radius: 9px; background: linear-gradient(135deg, #10b981, #047857); color: #fff; font-weight: 800; }
|
||||||
|
.nav-links { display: flex; gap: 26px; font-size: 15px; }
|
||||||
|
.nav-links a { color: var(--muted); }
|
||||||
|
.nav-links a:hover { color: var(--ink); }
|
||||||
|
|
||||||
|
.hero { padding: 96px 0 84px; text-align: center; background: radial-gradient(1200px 500px at 50% -100px, rgba(16,185,129,.12), transparent); }
|
||||||
|
.hero h1 { font-size: 46px; line-height: 1.25; letter-spacing: -1px; }
|
||||||
|
.hero h1 em { font-style: normal; color: var(--brand); }
|
||||||
|
.hero p.tagline { margin: 18px auto 0; max-width: 640px; font-size: 19px; color: var(--muted); }
|
||||||
|
.hero-actions { margin-top: 34px; display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; }
|
||||||
|
.btn { display: inline-flex; align-items: center; gap: 8px; padding: 12px 26px; border-radius: 10px; font-size: 16px; font-weight: 600; border: 1px solid transparent; transition: all .15s; }
|
||||||
|
.btn-primary { background: var(--brand); color: #fff; }
|
||||||
|
.btn-primary:hover { background: var(--brand-dark); }
|
||||||
|
.btn-outline { border-color: var(--line); color: var(--ink); background: var(--card); }
|
||||||
|
.btn-outline:hover { border-color: var(--brand); color: var(--brand); }
|
||||||
|
.hero-meta { margin-top: 26px; font-size: 14px; color: var(--muted); }
|
||||||
|
|
||||||
|
section.block { padding: 72px 0; }
|
||||||
|
section.block.alt { background: var(--card); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
|
||||||
|
.block h2 { font-size: 30px; text-align: center; }
|
||||||
|
.block .sub { text-align: center; color: var(--muted); margin-top: 10px; margin-bottom: 44px; }
|
||||||
|
|
||||||
|
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
|
||||||
|
.feature { background: var(--card); border: 1px solid var(--line); border-radius: 14px; padding: 26px; }
|
||||||
|
.feature .icon { width: 42px; height: 42px; border-radius: 10px; display: flex; align-items: center; justify-content: center; background: rgba(16,185,129,.1); color: var(--brand); margin-bottom: 14px; }
|
||||||
|
.feature h3 { font-size: 17px; margin-bottom: 8px; }
|
||||||
|
.feature p { font-size: 14.5px; color: var(--muted); }
|
||||||
|
|
||||||
|
.steps { max-width: 760px; margin: 0 auto; }
|
||||||
|
.step { display: flex; gap: 18px; padding: 18px 0; border-bottom: 1px dashed var(--line); }
|
||||||
|
.step:last-child { border-bottom: none; }
|
||||||
|
.step .no { flex-shrink: 0; width: 34px; height: 34px; border-radius: 50%; background: var(--brand); color: #fff; font-weight: 700; display: flex; align-items: center; justify-content: center; }
|
||||||
|
.step h3 { font-size: 16px; }
|
||||||
|
.step p { font-size: 14.5px; color: var(--muted); margin-top: 4px; }
|
||||||
|
code.inline { background: rgba(16,185,129,.08); color: var(--brand-dark); padding: 2px 7px; border-radius: 5px; font-size: 13.5px; font-family: ui-monospace, "SF Mono", Menlo, monospace; }
|
||||||
|
|
||||||
|
.footer { padding: 40px 0 56px; color: var(--muted); font-size: 14px; text-align: center; }
|
||||||
|
.footer .links { display: flex; gap: 22px; justify-content: center; margin-bottom: 14px; }
|
||||||
|
|
||||||
|
@media (max-width: 840px) {
|
||||||
|
.grid { grid-template-columns: 1fr; }
|
||||||
|
.hero h1 { font-size: 34px; }
|
||||||
|
.nav-links { display: none; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN"><head>
|
||||||
|
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<title>日志采集 · LokiStack 文档</title>
|
||||||
|
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%23059669'/%3E%3Ctext x='32' y='44' font-size='34' font-weight='800' fill='%23fff' text-anchor='middle' font-family='sans-serif'%3EL%3C/text%3E%3C/svg%3E">
|
||||||
|
<link rel="stylesheet" href="/docs/assets/loki-docs.css">
|
||||||
|
<style id="h5-fix">@media (max-width:820px){body{-webkit-text-size-adjust:100%}nav a,nav button,.nav-links a,.nav-menu a,.nav-item,.topnav a,.menu a,.side a,.sidebar a,.docs-side a,.toc a,footer a,a.btn,.plan .btn,button.btn{display:inline-flex;align-items:center;min-height:44px}.side a,.sidebar a,.docs-side a{padding:10px 12px;border-radius:8px}.toc a{padding:8px 0}pre{max-width:100%;overflow-x:auto}.plans,.grid,.grid-2,.grid-3{grid-template-columns:1fr!important}.hero h1,.hero-title{font-size:clamp(24px,7vw,34px)!important}.tbl-scroll{max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}}</style>
|
||||||
|
<script id="h5-fix-js">(function(){var f=function(){document.querySelectorAll("table").forEach(function(t){var p=t.parentElement;if(p&&p.classList&&p.classList.contains("tbl-scroll"))return;var w=document.createElement("div");w.className="tbl-scroll";p.insertBefore(w,t);w.appendChild(t);});};if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",f);else f();})();</script>
|
||||||
|
</head><body>
|
||||||
|
<div class="topbar">
|
||||||
|
<a class="brand" href="/"><i>L</i>LokiStack</a>
|
||||||
|
<span style="color:#98a2b3;font-size:13px">文档</span>
|
||||||
|
<nav class="topnav"><a href="/">官网</a><a href="/docs/" class="on">文档</a></nav>
|
||||||
|
</div>
|
||||||
|
<div class="layout">
|
||||||
|
<aside class="side"><h4>开始使用</h4><a data-slug="readme" href="/docs/readme/">产品介绍</a><a data-slug="install" href="/docs/install/">快速安装</a><a data-slug="wizard" href="/docs/wizard/">部署向导</a><h4>采集与查询</h4><a data-slug="collectors" href="/docs/collectors/" class="on">日志采集</a><a data-slug="query" href="/docs/query/">日志查询</a><a data-slug="analysis" href="/docs/analysis/">日志分析</a><a data-slug="access" href="/docs/access/">查询授权</a><h4>告警与运维</h4><a data-slug="alerts" href="/docs/alerts/">告警通知</a><a data-slug="faq" href="/docs/faq/">常见问题</a></aside>
|
||||||
|
<article>
|
||||||
|
<h1>日志采集</h1>
|
||||||
|
<div class="meta">采集与查询 · 更新于 2026-10-28</div>
|
||||||
|
<p>「日志采集」页管理采集策略:主机采集(Promtail)与集群采集(DaemonSet / Fluent Bit Sidecar)。</p>
|
||||||
|
<h2 id="_1">采集范围</h2>
|
||||||
|
<ul>
|
||||||
|
<li><strong>集群采集</strong>:命名空间多选(默认全集群);app 标签按 <code>app.kubernetes.io/name → app → controller 名 → pod 名</code> 四级回退,可自定义来源标签与 app 白名单收敛日志量。</li>
|
||||||
|
<li><strong>主机采集</strong>:填写业务日志路径(glob 通配,如 <code>/var/log/app/*.log</code>);系统日志自动探测(syslog / messages)。</li>
|
||||||
|
<li>敏感路径(/etc/shadow、私钥、/proc 等)会被平台拦截,防止主机凭据进入日志平台。</li>
|
||||||
|
</ul>
|
||||||
|
<h2 id="_2">编辑与下发</h2>
|
||||||
|
<p>保存后点击「部署」下发到目标;「预览 YAML」可先核对将生成的 promtail 配置。修改后同样以「部署」生效。</p>
|
||||||
|
<h2 id="_3">排查</h2>
|
||||||
|
<ul>
|
||||||
|
<li>采集器卡片可看运行状态与日志(主机 docker logs / journalctl,集群 Pod 日志)。</li>
|
||||||
|
<li>常见问题:目标命名空间无工作负载(app 候选为空)、路径无写入权限、Loki 端点不可达。</li>
|
||||||
|
</ul>
|
||||||
|
<div class="pager"><a href="/docs/wizard/">← 部署向导</a><a href="/docs/query/">日志查询 →</a></div>
|
||||||
|
</article>
|
||||||
|
<nav class="toc"><b>本页目录</b><a href="#_1">采集范围</a><a href="#_2">编辑与下发</a><a href="#_3">排查</a></nav>
|
||||||
|
</div>
|
||||||
|
<footer>LokiStack · <a href="/">返回官网</a> · © 日理万机</footer>
|
||||||
|
</body></html>
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN"><head>
|
||||||
|
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<title>常见问题 · LokiStack 文档</title>
|
||||||
|
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%23059669'/%3E%3Ctext x='32' y='44' font-size='34' font-weight='800' fill='%23fff' text-anchor='middle' font-family='sans-serif'%3EL%3C/text%3E%3C/svg%3E">
|
||||||
|
<link rel="stylesheet" href="/docs/assets/loki-docs.css">
|
||||||
|
<style id="h5-fix">@media (max-width:820px){body{-webkit-text-size-adjust:100%}nav a,nav button,.nav-links a,.nav-menu a,.nav-item,.topnav a,.menu a,.side a,.sidebar a,.docs-side a,.toc a,footer a,a.btn,.plan .btn,button.btn{display:inline-flex;align-items:center;min-height:44px}.side a,.sidebar a,.docs-side a{padding:10px 12px;border-radius:8px}.toc a{padding:8px 0}pre{max-width:100%;overflow-x:auto}.plans,.grid,.grid-2,.grid-3{grid-template-columns:1fr!important}.hero h1,.hero-title{font-size:clamp(24px,7vw,34px)!important}.tbl-scroll{max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}}</style>
|
||||||
|
<script id="h5-fix-js">(function(){var f=function(){document.querySelectorAll("table").forEach(function(t){var p=t.parentElement;if(p&&p.classList&&p.classList.contains("tbl-scroll"))return;var w=document.createElement("div");w.className="tbl-scroll";p.insertBefore(w,t);w.appendChild(t);});};if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",f);else f();})();</script>
|
||||||
|
</head><body>
|
||||||
|
<div class="topbar">
|
||||||
|
<a class="brand" href="/"><i>L</i>LokiStack</a>
|
||||||
|
<span style="color:#98a2b3;font-size:13px">文档</span>
|
||||||
|
<nav class="topnav"><a href="/">官网</a><a href="/docs/" class="on">文档</a></nav>
|
||||||
|
</div>
|
||||||
|
<div class="layout">
|
||||||
|
<aside class="side"><h4>开始使用</h4><a data-slug="readme" href="/docs/readme/">产品介绍</a><a data-slug="install" href="/docs/install/">快速安装</a><a data-slug="wizard" href="/docs/wizard/">部署向导</a><h4>采集与查询</h4><a data-slug="collectors" href="/docs/collectors/">日志采集</a><a data-slug="query" href="/docs/query/">日志查询</a><a data-slug="analysis" href="/docs/analysis/">日志分析</a><a data-slug="access" href="/docs/access/">查询授权</a><h4>告警与运维</h4><a data-slug="alerts" href="/docs/alerts/">告警通知</a><a data-slug="faq" href="/docs/faq/" class="on">常见问题</a></aside>
|
||||||
|
<article>
|
||||||
|
<h1>常见问题</h1>
|
||||||
|
<div class="meta">告警与运维 · 更新于 2026-10-28</div>
|
||||||
|
<h2 id="_1">登录后看不到「部署向导」「用户管理」等菜单?</h2>
|
||||||
|
<p>这些页面仅管理员可见。普通用户默认只有日志查询与日志告警;查询范围由策略组控制(见<a href="access.md">查询授权</a>)。</p>
|
||||||
|
<h2 id="loki-ingress">部署的 Loki 怎么访问?必须配 Ingress 吗?</h2>
|
||||||
|
<p>集群内部署经 API Server Service Proxy 查询,不需要 Ingress。跨集群 / 公网查询才需要为 Loki 暴露域名后在「数据源管理」用 URL 直连关联。</p>
|
||||||
|
<h2 id="_2">「停止部署」会删掉日志数据吗?</h2>
|
||||||
|
<p>不会。停止只回收工作负载;数据卷(PVC / 主机数据目录)保留,重新启动即可恢复。仅显式删除部署记录不影响远端资源,卸载需按页面指引执行。</p>
|
||||||
|
<h2 id="_3">告警一直不发送?</h2>
|
||||||
|
<p>按顺序检查:通道是否启用、Webhook 是否正确(通道页有测试)、规则是否启用且命中阈值、发送历史里是否有「冷却抑制」或失败原因。通道未就绪时历史会明确记录失败原因。</p>
|
||||||
|
<h2 id="_4">忘记管理员密码?</h2>
|
||||||
|
<p>管理员可在「用户管理」重置任意账号密码;若唯一管理员丢失密码,参考仓库 README 的离线重置说明。</p>
|
||||||
|
<h2 id="_5">平台可以多实例部署吗?</h2>
|
||||||
|
<p>不可以。JSON 文件存储为单实例设计(防抖串行落盘),水平扩展会互相覆盖;需要高可用时请保持单实例并对数据目录做系统级快照。</p>
|
||||||
|
<h2 id="_6">升级安全吗?</h2>
|
||||||
|
<p>配置与数据向后兼容,结构变更按 schema 版本自动迁移;建议升级前对数据目录(lokistack.json)做一次文件级拷贝。</p>
|
||||||
|
<div class="pager"><a href="/docs/alerts/">← 告警通知</a></div>
|
||||||
|
</article>
|
||||||
|
<nav class="toc"><b>本页目录</b><a href="#_1">登录后看不到「部署向导」「用户管理」等菜单?</a><a href="#loki-ingress">部署的 Loki 怎么访问?必须配 Ingress 吗?</a><a href="#_2">「停止部署」会删掉日志数据吗?</a><a href="#_3">告警一直不发送?</a><a href="#_4">忘记管理员密码?</a><a href="#_5">平台可以多实例部署吗?</a><a href="#_6">升级安全吗?</a></nav>
|
||||||
|
</div>
|
||||||
|
<footer>LokiStack · <a href="/">返回官网</a> · © 日理万机</footer>
|
||||||
|
</body></html>
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN"><head>
|
||||||
|
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<title>LokiStack 用户手册 · LokiStack 文档</title>
|
||||||
|
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%23059669'/%3E%3Ctext x='32' y='44' font-size='34' font-weight='800' fill='%23fff' text-anchor='middle' font-family='sans-serif'%3EL%3C/text%3E%3C/svg%3E">
|
||||||
|
<link rel="stylesheet" href="/docs/assets/loki-docs.css">
|
||||||
|
<style id="h5-fix">@media (max-width:820px){body{-webkit-text-size-adjust:100%}nav a,nav button,.nav-links a,.nav-menu a,.nav-item,.topnav a,.menu a,.side a,.sidebar a,.docs-side a,.toc a,footer a,a.btn,.plan .btn,button.btn{display:inline-flex;align-items:center;min-height:44px}.side a,.sidebar a,.docs-side a{padding:10px 12px;border-radius:8px}.toc a{padding:8px 0}pre{max-width:100%;overflow-x:auto}.plans,.grid,.grid-2,.grid-3{grid-template-columns:1fr!important}.hero h1,.hero-title{font-size:clamp(24px,7vw,34px)!important}.tbl-scroll{max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}}</style>
|
||||||
|
<script id="h5-fix-js">(function(){var f=function(){document.querySelectorAll("table").forEach(function(t){var p=t.parentElement;if(p&&p.classList&&p.classList.contains("tbl-scroll"))return;var w=document.createElement("div");w.className="tbl-scroll";p.insertBefore(w,t);w.appendChild(t);});};if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",f);else f();})();</script>
|
||||||
|
</head><body>
|
||||||
|
<div class="topbar">
|
||||||
|
<a class="brand" href="/"><i>L</i>LokiStack</a>
|
||||||
|
<span style="color:#98a2b3;font-size:13px">文档</span>
|
||||||
|
<nav class="topnav"><a href="/">官网</a><a href="/docs/" class="on">文档</a></nav>
|
||||||
|
</div>
|
||||||
|
<div class="layout">
|
||||||
|
<aside class="side"><h4>开始使用</h4><a data-slug="readme" href="/docs/readme/" class="on">产品介绍</a><a data-slug="install" href="/docs/install/">快速安装</a><a data-slug="wizard" href="/docs/wizard/">部署向导</a><h4>采集与查询</h4><a data-slug="collectors" href="/docs/collectors/">日志采集</a><a data-slug="query" href="/docs/query/">日志查询</a><a data-slug="analysis" href="/docs/analysis/">日志分析</a><a data-slug="access" href="/docs/access/">查询授权</a><h4>告警与运维</h4><a data-slug="alerts" href="/docs/alerts/">告警通知</a><a data-slug="faq" href="/docs/faq/">常见问题</a></aside>
|
||||||
|
<article>
|
||||||
|
<h1>LokiStack 用户手册</h1>
|
||||||
|
<div class="meta">开始使用 · 更新于 2026-10-28</div>
|
||||||
|
<p>LokiStack 把 Grafana Loki 日志聚合的部署、采集、查询、分析与告警收进一个平台:向导式部署到 Kubernetes 集群或裸金属主机,内置中文/英文界面,单二进制交付。</p>
|
||||||
|
<h2 id="_1">平台能做什么</h2>
|
||||||
|
<ul>
|
||||||
|
<li><strong>部署 Loki</strong>:三步向导(环境与目标 → 存储 → 部署与采集),支持 Kubernetes(YAML 直发)、裸金属二进制、主机 Docker 三种模式,不需要在平台所在机器安装 kubectl 或 Helm。</li>
|
||||||
|
<li><strong>采集日志</strong>:Promtail / Fluent Bit 采集策略可视化配置,命名空间多选、app 标签来源四级回退、敏感路径拦截。</li>
|
||||||
|
<li><strong>查询与分析</strong>:LogQL 高亮补全、快捷查询、Live Tail;分析页自动聚合日志量、错误与 Ingress 访问指标。</li>
|
||||||
|
<li><strong>告警</strong>:内置九条应用日志规则,绑定默认通道后填入飞书 Webhook 即可接收;支持冷却与风暴抑制。</li>
|
||||||
|
<li><strong>运维底座</strong>:凭证加密存储、操作审计、标准 Prometheus 指标端点(/api/v1/metrics)。</li>
|
||||||
|
</ul>
|
||||||
|
<h2 id="_2">界面预览</h2>
|
||||||
|
<div class="shot-grid">
|
||||||
|
<img src="/docs/assets/screenshots/dashboard.png" alt="仪表盘" />
|
||||||
|
<img src="/docs/assets/screenshots/wizard.png" alt="部署向导" />
|
||||||
|
<img src="/docs/assets/screenshots/logs-query.png" alt="日志查询" />
|
||||||
|
<img src="/docs/assets/screenshots/analysis.png" alt="日志分析" />
|
||||||
|
<img src="/docs/assets/screenshots/alerts.png" alt="告警通知" />
|
||||||
|
<img src="/docs/assets/screenshots/settings.png" alt="系统设置" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 id="_3">下一步</h2>
|
||||||
|
<p>阅读<a href="install.md">快速安装</a>,或直接进入<a href="wizard.md">部署向导</a>。</p>
|
||||||
|
<div class="pager"><span></span><a href="/docs/install/">快速安装 →</a></div>
|
||||||
|
</article>
|
||||||
|
<nav class="toc"><b>本页目录</b><a href="#_1">平台能做什么</a><a href="#_2">界面预览</a><a href="#_3">下一步</a></nav>
|
||||||
|
</div>
|
||||||
|
<footer>LokiStack · <a href="/">返回官网</a> · © 日理万机</footer>
|
||||||
|
</body></html>
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN"><head>
|
||||||
|
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<title>快速安装 · LokiStack 文档</title>
|
||||||
|
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%23059669'/%3E%3Ctext x='32' y='44' font-size='34' font-weight='800' fill='%23fff' text-anchor='middle' font-family='sans-serif'%3EL%3C/text%3E%3C/svg%3E">
|
||||||
|
<link rel="stylesheet" href="/docs/assets/loki-docs.css">
|
||||||
|
<style id="h5-fix">@media (max-width:820px){body{-webkit-text-size-adjust:100%}nav a,nav button,.nav-links a,.nav-menu a,.nav-item,.topnav a,.menu a,.side a,.sidebar a,.docs-side a,.toc a,footer a,a.btn,.plan .btn,button.btn{display:inline-flex;align-items:center;min-height:44px}.side a,.sidebar a,.docs-side a{padding:10px 12px;border-radius:8px}.toc a{padding:8px 0}pre{max-width:100%;overflow-x:auto}.plans,.grid,.grid-2,.grid-3{grid-template-columns:1fr!important}.hero h1,.hero-title{font-size:clamp(24px,7vw,34px)!important}.tbl-scroll{max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}}</style>
|
||||||
|
<script id="h5-fix-js">(function(){var f=function(){document.querySelectorAll("table").forEach(function(t){var p=t.parentElement;if(p&&p.classList&&p.classList.contains("tbl-scroll"))return;var w=document.createElement("div");w.className="tbl-scroll";p.insertBefore(w,t);w.appendChild(t);});};if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",f);else f();})();</script>
|
||||||
|
</head><body>
|
||||||
|
<div class="topbar">
|
||||||
|
<a class="brand" href="/"><i>L</i>LokiStack</a>
|
||||||
|
<span style="color:#98a2b3;font-size:13px">文档</span>
|
||||||
|
<nav class="topnav"><a href="/">官网</a><a href="/docs/" class="on">文档</a></nav>
|
||||||
|
</div>
|
||||||
|
<div class="layout">
|
||||||
|
<aside class="side"><h4>开始使用</h4><a data-slug="readme" href="/docs/readme/">产品介绍</a><a data-slug="install" href="/docs/install/" class="on">快速安装</a><a data-slug="wizard" href="/docs/wizard/">部署向导</a><h4>采集与查询</h4><a data-slug="collectors" href="/docs/collectors/">日志采集</a><a data-slug="query" href="/docs/query/">日志查询</a><a data-slug="analysis" href="/docs/analysis/">日志分析</a><a data-slug="access" href="/docs/access/">查询授权</a><h4>告警与运维</h4><a data-slug="alerts" href="/docs/alerts/">告警通知</a><a data-slug="faq" href="/docs/faq/">常见问题</a></aside>
|
||||||
|
<article>
|
||||||
|
<h1>快速安装</h1>
|
||||||
|
<div class="meta">开始使用 · 更新于 2026-10-28</div>
|
||||||
|
<h2 id="kubernetes">方式一:Kubernetes</h2>
|
||||||
|
<pre><code class="language-bash">bash kubernetes/install.sh
|
||||||
|
</code></pre>
|
||||||
|
<h2 id="docker">方式二:Docker</h2>
|
||||||
|
<pre><code class="language-bash">docker compose up -d
|
||||||
|
</code></pre>
|
||||||
|
<h2 id="_1">方式三:单二进制</h2>
|
||||||
|
<pre><code class="language-bash">curl -LO https://gitea.91ai.io/rlwj-lab/LokiStack/releases/download/v2.0.0/lokistack-linux-amd64.tar.gz
|
||||||
|
tar xzf lokistack-linux-amd64.tar.gz && cd lokistack-linux-amd64
|
||||||
|
./lokistack
|
||||||
|
</code></pre>
|
||||||
|
<p>arm64 服务器下载 <code>lokistack-linux-arm64.tar.gz</code>。</p>
|
||||||
|
<h2 id="_2">说明</h2>
|
||||||
|
<ul>
|
||||||
|
<li>未提供 <code>JWT_SECRET</code> / <code>ENCRYPTION_KEY</code> 时,自动生成随机密钥并持久化到数据目录(<code>.secrets.env</code>,权限 0600),重启与升级保持不变;显式设置环境变量可随时覆盖</li>
|
||||||
|
<li>全部状态存储在 <code>$DATA_DIR/lokistack.json</code>,单实例运行;首次启动自动创建管理员账号,初始密码在 <code>$DATA_DIR/initial-admin-password.txt</code></li>
|
||||||
|
<li>升级:替换二进制或重新拉取镜像后重启,历史数据自动迁移</li>
|
||||||
|
</ul>
|
||||||
|
<div class="pager"><a href="/docs/readme/">← 产品介绍</a><a href="/docs/wizard/">部署向导 →</a></div>
|
||||||
|
</article>
|
||||||
|
<nav class="toc"><b>本页目录</b><a href="#kubernetes">方式一:Kubernetes</a><a href="#docker">方式二:Docker</a><a href="#_1">方式三:单二进制</a><a href="#_2">说明</a></nav>
|
||||||
|
</div>
|
||||||
|
<footer>LokiStack · <a href="/">返回官网</a> · © 日理万机</footer>
|
||||||
|
</body></html>
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN"><head>
|
||||||
|
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<title>日志查询 · LokiStack 文档</title>
|
||||||
|
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%23059669'/%3E%3Ctext x='32' y='44' font-size='34' font-weight='800' fill='%23fff' text-anchor='middle' font-family='sans-serif'%3EL%3C/text%3E%3C/svg%3E">
|
||||||
|
<link rel="stylesheet" href="/docs/assets/loki-docs.css">
|
||||||
|
<style id="h5-fix">@media (max-width:820px){body{-webkit-text-size-adjust:100%}nav a,nav button,.nav-links a,.nav-menu a,.nav-item,.topnav a,.menu a,.side a,.sidebar a,.docs-side a,.toc a,footer a,a.btn,.plan .btn,button.btn{display:inline-flex;align-items:center;min-height:44px}.side a,.sidebar a,.docs-side a{padding:10px 12px;border-radius:8px}.toc a{padding:8px 0}pre{max-width:100%;overflow-x:auto}.plans,.grid,.grid-2,.grid-3{grid-template-columns:1fr!important}.hero h1,.hero-title{font-size:clamp(24px,7vw,34px)!important}.tbl-scroll{max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}}</style>
|
||||||
|
<script id="h5-fix-js">(function(){var f=function(){document.querySelectorAll("table").forEach(function(t){var p=t.parentElement;if(p&&p.classList&&p.classList.contains("tbl-scroll"))return;var w=document.createElement("div");w.className="tbl-scroll";p.insertBefore(w,t);w.appendChild(t);});};if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",f);else f();})();</script>
|
||||||
|
</head><body>
|
||||||
|
<div class="topbar">
|
||||||
|
<a class="brand" href="/"><i>L</i>LokiStack</a>
|
||||||
|
<span style="color:#98a2b3;font-size:13px">文档</span>
|
||||||
|
<nav class="topnav"><a href="/">官网</a><a href="/docs/" class="on">文档</a></nav>
|
||||||
|
</div>
|
||||||
|
<div class="layout">
|
||||||
|
<aside class="side"><h4>开始使用</h4><a data-slug="readme" href="/docs/readme/">产品介绍</a><a data-slug="install" href="/docs/install/">快速安装</a><a data-slug="wizard" href="/docs/wizard/">部署向导</a><h4>采集与查询</h4><a data-slug="collectors" href="/docs/collectors/">日志采集</a><a data-slug="query" href="/docs/query/" class="on">日志查询</a><a data-slug="analysis" href="/docs/analysis/">日志分析</a><a data-slug="access" href="/docs/access/">查询授权</a><h4>告警与运维</h4><a data-slug="alerts" href="/docs/alerts/">告警通知</a><a data-slug="faq" href="/docs/faq/">常见问题</a></aside>
|
||||||
|
<article>
|
||||||
|
<h1>日志查询</h1>
|
||||||
|
<div class="meta">采集与查询 · 更新于 2026-10-28</div>
|
||||||
|
<p>「日志查询」页(<code>/logs</code>)按 LogQL 与时间范围检索日志。</p>
|
||||||
|
<p><img alt="日志查询" src="/docs/assets/screenshots/logs-query.png" /></p>
|
||||||
|
<h2 id="_1">查询方式</h2>
|
||||||
|
<ul>
|
||||||
|
<li><strong>LogQL 编辑器</strong>:语法高亮与标签/管道补全;回车执行。</li>
|
||||||
|
<li><strong>快捷查询</strong>:先选命名空间,再选 App / Pod(候选值<strong>按级联懒加载</strong>:选了命名空间才会去取 App 列表,选了 App 才取 Pod 列表,避免一进页面就把 Loki 索引扫一遍),选中即自动填入并执行;Ingress 访问日志按钮在选择 ingress 命名空间或 app 时出现。</li>
|
||||||
|
<li><strong>Label 浏览器</strong>:按标签与值点选构建查询;点结果行的标签值可快速加过滤。</li>
|
||||||
|
<li><strong>Live Tail</strong>:3 秒轮询最近 5 分钟,编辑查询自动防抖后切换。</li>
|
||||||
|
</ul>
|
||||||
|
<h2 id="_2">结果区</h2>
|
||||||
|
<ul>
|
||||||
|
<li>顶部时间线展示整个查询范围的日志量,拖选高峰时段自动重查。</li>
|
||||||
|
<li>原始日志支持关键字高亮、标签过滤、查看上下文(前后 N 行)。</li>
|
||||||
|
<li>翻页向后游标推进,每页最多 1000 条。</li>
|
||||||
|
</ul>
|
||||||
|
<h2 id="_3">数据源</h2>
|
||||||
|
<p>「数据源管理」维护 Loki 连接:平台部署自动注册(随部署托管),也可手动添加 URL 直连或集群 Service 数据源,支持 Basic / Bearer / 自定义 Header 认证与连接测试。</p>
|
||||||
|
<div class="pager"><a href="/docs/collectors/">← 日志采集</a><a href="/docs/analysis/">日志分析 →</a></div>
|
||||||
|
</article>
|
||||||
|
<nav class="toc"><b>本页目录</b><a href="#_1">查询方式</a><a href="#_2">结果区</a><a href="#_3">数据源</a></nav>
|
||||||
|
</div>
|
||||||
|
<footer>LokiStack · <a href="/">返回官网</a> · © 日理万机</footer>
|
||||||
|
</body></html>
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN"><head>
|
||||||
|
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<title>LokiStack 用户手册 · LokiStack 文档</title>
|
||||||
|
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%23059669'/%3E%3Ctext x='32' y='44' font-size='34' font-weight='800' fill='%23fff' text-anchor='middle' font-family='sans-serif'%3EL%3C/text%3E%3C/svg%3E">
|
||||||
|
<link rel="stylesheet" href="/docs/assets/loki-docs.css">
|
||||||
|
<style id="h5-fix">@media (max-width:820px){body{-webkit-text-size-adjust:100%}nav a,nav button,.nav-links a,.nav-menu a,.nav-item,.topnav a,.menu a,.side a,.sidebar a,.docs-side a,.toc a,footer a,a.btn,.plan .btn,button.btn{display:inline-flex;align-items:center;min-height:44px}.side a,.sidebar a,.docs-side a{padding:10px 12px;border-radius:8px}.toc a{padding:8px 0}pre{max-width:100%;overflow-x:auto}.plans,.grid,.grid-2,.grid-3{grid-template-columns:1fr!important}.hero h1,.hero-title{font-size:clamp(24px,7vw,34px)!important}.tbl-scroll{max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}}</style>
|
||||||
|
<script id="h5-fix-js">(function(){var f=function(){document.querySelectorAll("table").forEach(function(t){var p=t.parentElement;if(p&&p.classList&&p.classList.contains("tbl-scroll"))return;var w=document.createElement("div");w.className="tbl-scroll";p.insertBefore(w,t);w.appendChild(t);});};if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",f);else f();})();</script>
|
||||||
|
</head><body>
|
||||||
|
<div class="topbar">
|
||||||
|
<a class="brand" href="/"><i>L</i>LokiStack</a>
|
||||||
|
<span style="color:#98a2b3;font-size:13px">文档</span>
|
||||||
|
<nav class="topnav"><a href="/">官网</a><a href="/docs/" class="on">文档</a></nav>
|
||||||
|
</div>
|
||||||
|
<div class="layout">
|
||||||
|
<aside class="side"><h4>开始使用</h4><a data-slug="readme" href="/docs/readme/" class="on">产品介绍</a><a data-slug="install" href="/docs/install/">快速安装</a><a data-slug="wizard" href="/docs/wizard/">部署向导</a><h4>采集与查询</h4><a data-slug="collectors" href="/docs/collectors/">日志采集</a><a data-slug="query" href="/docs/query/">日志查询</a><a data-slug="analysis" href="/docs/analysis/">日志分析</a><a data-slug="access" href="/docs/access/">查询授权</a><h4>告警与运维</h4><a data-slug="alerts" href="/docs/alerts/">告警通知</a><a data-slug="faq" href="/docs/faq/">常见问题</a></aside>
|
||||||
|
<article>
|
||||||
|
<h1>LokiStack 用户手册</h1>
|
||||||
|
<div class="meta">开始使用 · 更新于 2026-10-28</div>
|
||||||
|
<p>LokiStack 把 Grafana Loki 日志聚合的部署、采集、查询、分析与告警收进一个平台:向导式部署到 Kubernetes 集群或裸金属主机,内置中文/英文界面,单二进制交付。</p>
|
||||||
|
<h2 id="_1">平台能做什么</h2>
|
||||||
|
<ul>
|
||||||
|
<li><strong>部署 Loki</strong>:三步向导(环境与目标 → 存储 → 部署与采集),支持 Kubernetes(YAML 直发)、裸金属二进制、主机 Docker 三种模式,不需要在平台所在机器安装 kubectl 或 Helm。</li>
|
||||||
|
<li><strong>采集日志</strong>:Promtail / Fluent Bit 采集策略可视化配置,命名空间多选、app 标签来源四级回退、敏感路径拦截。</li>
|
||||||
|
<li><strong>查询与分析</strong>:LogQL 高亮补全、快捷查询、Live Tail;分析页自动聚合日志量、错误与 Ingress 访问指标。</li>
|
||||||
|
<li><strong>告警</strong>:内置九条应用日志规则,绑定默认通道后填入飞书 Webhook 即可接收;支持冷却与风暴抑制。</li>
|
||||||
|
<li><strong>运维底座</strong>:凭证加密存储、操作审计、标准 Prometheus 指标端点(/api/v1/metrics)。</li>
|
||||||
|
</ul>
|
||||||
|
<h2 id="_2">界面预览</h2>
|
||||||
|
<div class="shot-grid">
|
||||||
|
<img src="/docs/assets/screenshots/dashboard.png" alt="仪表盘" />
|
||||||
|
<img src="/docs/assets/screenshots/wizard.png" alt="部署向导" />
|
||||||
|
<img src="/docs/assets/screenshots/logs-query.png" alt="日志查询" />
|
||||||
|
<img src="/docs/assets/screenshots/analysis.png" alt="日志分析" />
|
||||||
|
<img src="/docs/assets/screenshots/alerts.png" alt="告警通知" />
|
||||||
|
<img src="/docs/assets/screenshots/settings.png" alt="系统设置" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 id="_3">下一步</h2>
|
||||||
|
<p>阅读<a href="install.md">快速安装</a>,或直接进入<a href="wizard.md">部署向导</a>。</p>
|
||||||
|
<div class="pager"><span></span><a href="/docs/install/">快速安装 →</a></div>
|
||||||
|
</article>
|
||||||
|
<nav class="toc"><b>本页目录</b><a href="#_1">平台能做什么</a><a href="#_2">界面预览</a><a href="#_3">下一步</a></nav>
|
||||||
|
</div>
|
||||||
|
<footer>LokiStack · <a href="/">返回官网</a> · © 日理万机</footer>
|
||||||
|
</body></html>
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN"><head>
|
||||||
|
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<title>部署向导 · LokiStack 文档</title>
|
||||||
|
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%23059669'/%3E%3Ctext x='32' y='44' font-size='34' font-weight='800' fill='%23fff' text-anchor='middle' font-family='sans-serif'%3EL%3C/text%3E%3C/svg%3E">
|
||||||
|
<link rel="stylesheet" href="/docs/assets/loki-docs.css">
|
||||||
|
<style id="h5-fix">@media (max-width:820px){body{-webkit-text-size-adjust:100%}nav a,nav button,.nav-links a,.nav-menu a,.nav-item,.topnav a,.menu a,.side a,.sidebar a,.docs-side a,.toc a,footer a,a.btn,.plan .btn,button.btn{display:inline-flex;align-items:center;min-height:44px}.side a,.sidebar a,.docs-side a{padding:10px 12px;border-radius:8px}.toc a{padding:8px 0}pre{max-width:100%;overflow-x:auto}.plans,.grid,.grid-2,.grid-3{grid-template-columns:1fr!important}.hero h1,.hero-title{font-size:clamp(24px,7vw,34px)!important}.tbl-scroll{max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}}</style>
|
||||||
|
<script id="h5-fix-js">(function(){var f=function(){document.querySelectorAll("table").forEach(function(t){var p=t.parentElement;if(p&&p.classList&&p.classList.contains("tbl-scroll"))return;var w=document.createElement("div");w.className="tbl-scroll";p.insertBefore(w,t);w.appendChild(t);});};if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",f);else f();})();</script>
|
||||||
|
</head><body>
|
||||||
|
<div class="topbar">
|
||||||
|
<a class="brand" href="/"><i>L</i>LokiStack</a>
|
||||||
|
<span style="color:#98a2b3;font-size:13px">文档</span>
|
||||||
|
<nav class="topnav"><a href="/">官网</a><a href="/docs/" class="on">文档</a></nav>
|
||||||
|
</div>
|
||||||
|
<div class="layout">
|
||||||
|
<aside class="side"><h4>开始使用</h4><a data-slug="readme" href="/docs/readme/">产品介绍</a><a data-slug="install" href="/docs/install/">快速安装</a><a data-slug="wizard" href="/docs/wizard/" class="on">部署向导</a><h4>采集与查询</h4><a data-slug="collectors" href="/docs/collectors/">日志采集</a><a data-slug="query" href="/docs/query/">日志查询</a><a data-slug="analysis" href="/docs/analysis/">日志分析</a><a data-slug="access" href="/docs/access/">查询授权</a><h4>告警与运维</h4><a data-slug="alerts" href="/docs/alerts/">告警通知</a><a data-slug="faq" href="/docs/faq/">常见问题</a></aside>
|
||||||
|
<article>
|
||||||
|
<h1>部署向导</h1>
|
||||||
|
<div class="meta">开始使用 · 更新于 2026-10-28</div>
|
||||||
|
<p>部署向导(<code>/wizard</code>)三步完成 Loki 上线:环境与目标 → 存储 → 部署 Loki 与采集。</p>
|
||||||
|
<p><img alt="部署向导" src="/docs/assets/screenshots/wizard.png" /></p>
|
||||||
|
<h2 id="_1">第一步:环境与目标</h2>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Kubernetes 集群</strong>:粘贴 kubeconfig,或按页面给出的 RBAC 脚本在集群执行一次后粘贴 ServiceAccount 长期 Token。平台经 API Server 操作集群,无需安装 kubectl/Helm。</li>
|
||||||
|
<li><strong>裸金属主机</strong>:填写 SSH 地址与凭证(密码或私钥,AES-GCM 加密存储)。适合二进制或 Docker 模式。</li>
|
||||||
|
</ul>
|
||||||
|
<p>创建后平台自动验证连通性;Kubernetes 资源默认落在 <code>log</code> 命名空间(可改)。</p>
|
||||||
|
<h2 id="_2">第二步:准备存储</h2>
|
||||||
|
<p>推荐对象存储(MinIO / RustFS / S3 / OSS):多副本与数据保留更可靠,创建时可用「测试连接」验证凭证并自动建桶;跳过则使用本地磁盘。</p>
|
||||||
|
<h2 id="_3">第三步:部署与采集</h2>
|
||||||
|
<ul>
|
||||||
|
<li>选择目标、Loki 版本(支持 2.8+ / 3.x)、保留天数与资源规格,点击部署。</li>
|
||||||
|
<li>部署成功后平台自动注册同名数据源,日志查询页立即可用;按提示添加采集策略(见<a href="collectors.md">日志采集</a>)。</li>
|
||||||
|
</ul>
|
||||||
|
<h2 id="_4">三种部署模式</h2>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>模式</th>
|
||||||
|
<th>适用</th>
|
||||||
|
<th>说明</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>k8s-yaml</td>
|
||||||
|
<td>Kubernetes</td>
|
||||||
|
<td>StatefulSet + SSA 直发,平台全托管</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>host-binary</td>
|
||||||
|
<td>裸金属</td>
|
||||||
|
<td>SSH 安装二进制 + systemd 托管</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>host-docker</td>
|
||||||
|
<td>裸金属</td>
|
||||||
|
<td>Docker 容器运行,自动目录迁移</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="pager"><a href="/docs/install/">← 快速安装</a><a href="/docs/collectors/">日志采集 →</a></div>
|
||||||
|
</article>
|
||||||
|
<nav class="toc"><b>本页目录</b><a href="#_1">第一步:环境与目标</a><a href="#_2">第二步:准备存储</a><a href="#_3">第三步:部署与采集</a><a href="#_4">三种部署模式</a></nav>
|
||||||
|
</div>
|
||||||
|
<footer>LokiStack · <a href="/">返回官网</a> · © 日理万机</footer>
|
||||||
|
</body></html>
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>LokiStack — Loki 日志管理平台</title>
|
||||||
|
<meta name="description" content="LokiStack:把 Grafana Loki 部署到 Kubernetes 或裸金属,内置日志查询、日志分析与告警的一体化平台。部署向导、采集策略、查询授权、飞书告警开箱即用。">
|
||||||
|
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%23059669'/%3E%3Ctext x='32' y='44' font-size='34' font-weight='800' fill='%23fff' text-anchor='middle' font-family='sans-serif'%3EL%3C/text%3E%3C/svg%3E">
|
||||||
|
<link rel="stylesheet" href="assets/site.css">
|
||||||
|
<style id="h5-fix">@media (max-width:820px){body{-webkit-text-size-adjust:100%}nav a,nav button,.nav-links a,.nav-menu a,.nav-item,.topnav a,.menu a,.side a,.sidebar a,.docs-side a,.toc a,footer a,a.btn,.plan .btn,button.btn{display:inline-flex;align-items:center;min-height:44px}.side a,.sidebar a,.docs-side a{padding:10px 12px;border-radius:8px}.toc a{padding:8px 0}pre{max-width:100%;overflow-x:auto}.plans,.grid,.grid-2,.grid-3{grid-template-columns:1fr!important}.hero h1,.hero-title{font-size:clamp(24px,7vw,34px)!important}.tbl-scroll{max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}}</style>
|
||||||
|
<script id="h5-fix-js">(function(){var f=function(){document.querySelectorAll("table").forEach(function(t){var p=t.parentElement;if(p&&p.classList&&p.classList.contains("tbl-scroll"))return;var w=document.createElement("div");w.className="tbl-scroll";p.insertBefore(w,t);w.appendChild(t);});};if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",f);else f();})();</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header class="nav">
|
||||||
|
<div class="nav-inner">
|
||||||
|
<a class="brand" href="#">
|
||||||
|
<span class="brand-logo">L</span>
|
||||||
|
<span>LokiStack</span>
|
||||||
|
</a>
|
||||||
|
<nav class="nav-links">
|
||||||
|
<a href="#features">特性</a>
|
||||||
|
<a href="/docs/">文档</a>
|
||||||
|
<a href="/pricing">定价</a>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section class="hero">
|
||||||
|
<div class="container">
|
||||||
|
<h1>把 Loki 日志聚合<br>变成<em>五分钟</em>的事</h1>
|
||||||
|
<p class="tagline">向导式部署 Grafana Loki 到 Kubernetes 集群或裸金属主机,内置日志查询、可视化分析与飞书告警 —— 不写 YAML、不装 kubectl/Helm。</p>
|
||||||
|
<div class="hero-actions">
|
||||||
|
<a class="btn btn-primary" href="/docs/">快速开始</a>
|
||||||
|
<a class="btn btn-outline" href="/docs/">阅读文档</a>
|
||||||
|
</div>
|
||||||
|
<p class="hero-meta">Go + React 单二进制交付 · JSON 文件存储零依赖 · 中文/英文界面</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="block" id="features">
|
||||||
|
<div class="container">
|
||||||
|
<h2>为运维而生的完整日志链路</h2>
|
||||||
|
<p class="sub">从部署、采集、查询到告警,一个平台全部覆盖</p>
|
||||||
|
<div class="grid">
|
||||||
|
<div class="feature">
|
||||||
|
<div class="icon"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09"/><path d="m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z"/><path d="M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0"/><path d="M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5"/></svg></div>
|
||||||
|
<h3>向导式部署</h3>
|
||||||
|
<p>三步完成:环境与目标 → 存储 → 部署 Loki 与采集。支持 Kubernetes(YAML 直发)、裸金属二进制与 Docker 三种模式。</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature">
|
||||||
|
<div class="icon"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 10a1 1 0 0 0 1 1h2.5a1 1 0 0 1 .8.4l.9 1.2a1 1 0 0 0 .8.4H12a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1h-2a1 1 0 0 0-.8.4l-.9 1.2a1 1 0 0 1-.8.4H5a1 1 0 0 0-1 1z"/><path d="M3 5v13a2 2 0 0 0 2 2h3"/></svg></div>
|
||||||
|
<h3>策略化采集</h3>
|
||||||
|
<p>Promtail / Fluent Bit 采集策略可视化配置:命名空间多选、app 标签四级回退、敏感路径拦截、配置预览与一键下发。</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature">
|
||||||
|
<div class="icon"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg></div>
|
||||||
|
<h3>专业日志查询</h3>
|
||||||
|
<p>LogQL 高亮补全、快捷查询选中即执行、Live Tail 实时追踪、时间线拖选、上下文查看,细到按用户的查询授权。</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature">
|
||||||
|
<div class="icon"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 3v16a2 2 0 0 0 2 2h16"/><path d="m7 14 4-4 4 4 6-6"/></svg></div>
|
||||||
|
<h3>日志分析大盘</h3>
|
||||||
|
<p>统计卡、趋势折线、命名空间分布、应用流图、每日日志量、Top 10 排行与 Ingress 访问分析,自动聚合无需配置。</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature">
|
||||||
|
<div class="icon"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 8.5a2.5 2.5 0 0 0-2.5-2.5h-15A2.5 2.5 0 0 0 2 8.5v7a2.5 2.5 0 0 0 2.5 2.5h15A2.5 2.5 0 0 0 22 15.5z"/><path d="M6 9v6"/><path d="M10 9v6"/><path d="M14 9v6"/><path d="M18 9v6"/></svg></div>
|
||||||
|
<h3>开箱告警</h3>
|
||||||
|
<p>内置九条应用日志告警规则,默认启用并绑定默认通道;填好飞书 Webhook 即可接收,冷却与风暴抑制防刷屏。</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature">
|
||||||
|
<div class="icon"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"/><path d="m9 12 2 2 4-4"/></svg></div>
|
||||||
|
<h3>工程级可靠性</h3>
|
||||||
|
<p>凭证加密存储、操作审计、标准 Prometheus 指标端点、CI 门禁与测试覆盖,按生产标准构建。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="block alt" id="quickstart">
|
||||||
|
<div class="container">
|
||||||
|
<h2>五分钟启动</h2>
|
||||||
|
<p class="sub">单二进制或 Docker,一条命令拉起完整平台</p>
|
||||||
|
<div class="steps">
|
||||||
|
<div class="step">
|
||||||
|
<span class="no">1</span>
|
||||||
|
<div>
|
||||||
|
<h3>准备密钥并启动</h3>
|
||||||
|
<p><code class="inline">export JWT_SECRET=... ENCRYPTION_KEY=...</code> 后执行 <code class="inline">./run.sh</code>(开发)或 <code class="inline">docker compose up -d</code>(生产)。默认账号在首次启动时自动生成。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="step">
|
||||||
|
<span class="no">2</span>
|
||||||
|
<div>
|
||||||
|
<h3>走完部署向导</h3>
|
||||||
|
<p>接入 Kubernetes 集群或 SSH 主机,选择对象存储或本地磁盘,三步部署 Loki 并下发采集策略。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="step">
|
||||||
|
<span class="no">3</span>
|
||||||
|
<div>
|
||||||
|
<h3>查询、分析、告警</h3>
|
||||||
|
<p>日志查询页检索与实时追踪,日志分析页看聚合大盘,告警页填入飞书 Webhook 开始接收告警。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="block" id="docs">
|
||||||
|
<div class="container">
|
||||||
|
<h2>文档</h2>
|
||||||
|
<p class="sub">用户手册覆盖部署、采集、查询、分析与告警全流程</p>
|
||||||
|
<div class="hero-actions">
|
||||||
|
<a class="btn btn-primary" href="/docs/">打开用户手册</a>
|
||||||
|
<a class="btn btn-outline" href="/pricing">许可和定价</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="links">
|
||||||
|
<a href="#features">特性</a>
|
||||||
|
<a href="/docs/">快速开始</a>
|
||||||
|
<a href="/docs/">文档</a>
|
||||||
|
<a href="https://gitea.91ai.io/rlwj-lab/LokiStack" target="_blank" rel="noopener">Gitea</a>
|
||||||
|
</div>
|
||||||
|
<p>LokiStack — Loki 日志管理平台 · Grafana Loki 是 Grafana Labs 的商标</p>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,213 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>License & Pricing 许可和定价 · LokiStack</title>
|
||||||
|
<meta name="description" content="LokiStack 许可与定价:社区版免费,专业版 ¥99/年起,永久授权 ¥199,团队版按席位,企业私有化交付。">
|
||||||
|
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%23059669'/%3E%3Ctext x='32' y='44' font-size='34' font-weight='800' fill='%23fff' text-anchor='middle' font-family='sans-serif'%3EL%3C/text%3E%3C/svg%3E">
|
||||||
|
<style>
|
||||||
|
:root{--brand:#059669;--brand-d:#047857;--ink:#0f172a;--muted:#5b6676;--line:#e6e9ee;--bg:#fff;--soft:#f7faf9}
|
||||||
|
*{box-sizing:border-box}
|
||||||
|
body{margin:0;font:15px/1.7 -apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;color:var(--ink);background:var(--bg)}
|
||||||
|
a{color:var(--brand-d);text-decoration:none}a:hover{text-decoration:underline}
|
||||||
|
.wrap{max-width:1140px;margin:0 auto;padding:0 20px}
|
||||||
|
header.top{position:sticky;top:0;z-index:30;background:rgba(255,255,255,.92);backdrop-filter:blur(8px);border-bottom:1px solid var(--line)}
|
||||||
|
.top-in{display:flex;align-items:center;gap:26px;height:62px}
|
||||||
|
.brand{display:flex;align-items:center;gap:9px;font-weight:800;font-size:16px;color:var(--ink)}
|
||||||
|
.brand i{width:28px;height:28px;border-radius:9px;background:var(--brand);color:#fff;display:grid;place-items:center;font-style:normal;font-weight:800}
|
||||||
|
nav.menu{display:flex;gap:22px;font-size:14.5px}
|
||||||
|
nav.menu a{color:#46505f}nav.menu a:hover{color:var(--brand-d)}
|
||||||
|
nav.menu a.on{color:var(--brand-d);font-weight:650}
|
||||||
|
.top-cta{margin-left:auto}
|
||||||
|
.btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:9px 16px;border-radius:9px;font-size:14px;font-weight:600;border:1px solid transparent;cursor:pointer}
|
||||||
|
.btn-primary{background:var(--brand);color:#fff}.btn-primary:hover{background:var(--brand-d);text-decoration:none}
|
||||||
|
.btn-outline{border-color:#cfd8d4;color:#26313f;background:#fff}.btn-outline:hover{border-color:var(--brand);color:var(--brand-d);text-decoration:none}
|
||||||
|
.hero{padding:56px 0 30px;text-align:center}
|
||||||
|
.badge{display:inline-block;padding:5px 12px;border-radius:999px;background:#e8f7f1;color:var(--brand-d);font-size:12.5px;font-weight:650;letter-spacing:.01em}
|
||||||
|
.hero h1{font-size:40px;line-height:1.22;margin:16px 0 10px;letter-spacing:-.02em}
|
||||||
|
.hero p{color:var(--muted);max-width:640px;margin:0 auto;font-size:16px}
|
||||||
|
#intent-bar{position:sticky;top:62px;z-index:29;background:#e8f7f1;border-bottom:1px solid #cdeee1;color:#065f46}
|
||||||
|
#intent-bar .in{display:flex;align-items:center;gap:10px;padding:10px 0;font-size:13.5px}
|
||||||
|
#intent-bar b{font-weight:700}
|
||||||
|
#intent-bar button{margin-left:auto;background:none;border:0;color:#065f46;font-size:18px;cursor:pointer;line-height:1}
|
||||||
|
.plans{display:grid;grid-template-columns:repeat(4,1fr);gap:18px;margin:34px 0 10px;align-items:stretch}
|
||||||
|
.plan{display:flex;flex-direction:column;border:1px solid var(--line);border-radius:14px;padding:20px;background:#fff;transition:.18s}
|
||||||
|
.plan:hover{box-shadow:0 8px 24px rgba(15,23,42,.07);transform:translateY(-2px)}
|
||||||
|
.plan.rec{border-color:var(--brand);box-shadow:0 0 0 1px var(--brand) inset}
|
||||||
|
.plan.hl{outline:3px solid rgba(5,150,105,.28);outline-offset:2px;animation:pulse 1.6s ease-in-out 2}
|
||||||
|
@keyframes pulse{0%,100%{box-shadow:0 0 0 0 rgba(5,150,105,.25)}50%{box-shadow:0 0 0 10px rgba(5,150,105,0)}}
|
||||||
|
.plan h3{margin:0 0 4px;font-size:16px}
|
||||||
|
.plan .sub{color:#8a94a3;font-size:12.5px;min-height:18px}
|
||||||
|
.price{margin:14px 0 4px;font-size:34px;font-weight:800;letter-spacing:-.02em}
|
||||||
|
.price small{font-size:13px;font-weight:600;color:#8a94a3;margin-left:3px}
|
||||||
|
.plan ul{list-style:none;padding:0;margin:16px 0 20px;font-size:13.5px;color:#3c4757;flex:1}
|
||||||
|
.plan li{padding:5px 0 5px 22px;position:relative}
|
||||||
|
.plan li:before{content:"";position:absolute;left:2px;top:11px;width:13px;height:7px;border-left:2px solid var(--brand);border-bottom:2px solid var(--brand);transform:rotate(-45deg)}
|
||||||
|
.plan .btn{width:100%}
|
||||||
|
.tag{display:inline-block;padding:2px 8px;border-radius:6px;background:#e8f7f1;color:var(--brand-d);font-size:11.5px;font-weight:700;margin-bottom:8px}
|
||||||
|
#activate{scroll-margin-top:90px;margin:56px 0 0;padding:26px;border:1px solid var(--line);border-radius:16px;background:var(--soft)}
|
||||||
|
#activate h2{margin:0 0 6px;font-size:22px}
|
||||||
|
#activate p.lead{color:var(--muted);margin:0 0 18px;font-size:14px}
|
||||||
|
.steps{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;counter-reset:s}
|
||||||
|
.step{background:#fff;border:1px solid var(--line);border-radius:12px;padding:14px 16px 14px 44px;position:relative;font-size:13.5px;color:#3c4757}
|
||||||
|
.step:before{counter-increment:s;content:counter(s);position:absolute;left:14px;top:13px;width:20px;height:20px;border-radius:50%;background:var(--brand);color:#fff;font-size:12px;font-weight:700;display:grid;place-items:center}
|
||||||
|
.step b{display:block;color:var(--ink);font-size:14px;margin-bottom:3px}
|
||||||
|
kbd{background:#eef2f4;border:1px solid #dbe2e6;border-bottom-width:2px;border-radius:5px;padding:1px 5px;font:12px ui-monospace,Menlo,monospace}
|
||||||
|
.faq{margin:54px 0 0}
|
||||||
|
.faq h2{font-size:22px;margin:0 0 14px}
|
||||||
|
details{border-bottom:1px solid var(--line);padding:14px 0}
|
||||||
|
summary{cursor:pointer;font-weight:600;font-size:15px;list-style:none}
|
||||||
|
summary::-webkit-details-marker{display:none}
|
||||||
|
summary:after{content:"+";float:right;color:#98a2b3;font-weight:400}
|
||||||
|
details[open] summary:after{content:"–"}
|
||||||
|
details p{color:var(--muted);font-size:14px;margin:10px 0 0}
|
||||||
|
.cta{margin:56px 0;padding:30px;border-radius:16px;background:linear-gradient(135deg,#059669,#065f46);color:#fff;display:flex;align-items:center;gap:20px;flex-wrap:wrap}
|
||||||
|
.cta h2{margin:0;font-size:22px}.cta p{margin:4px 0 0;opacity:.9;font-size:14px}
|
||||||
|
.cta .btn{margin-left:auto;background:#fff;color:var(--brand-d)}
|
||||||
|
footer{border-top:1px solid var(--line);padding:24px 0;color:#98a2b3;font-size:12.5px}
|
||||||
|
footer .wrap{display:flex;gap:16px;flex-wrap:wrap;align-items:center}
|
||||||
|
footer a{color:#6b7684}
|
||||||
|
@media (max-width:960px){.plans{grid-template-columns:repeat(2,1fr)}.steps{grid-template-columns:repeat(2,1fr)}.hero h1{font-size:30px}}
|
||||||
|
@media (max-width:640px){nav.menu{display:none}.plans{grid-template-columns:1fr}.steps{grid-template-columns:1fr}.hero{padding:36px 0 20px}.hero h1{font-size:26px}}
|
||||||
|
</style>
|
||||||
|
<style id="h5-fix">@media (max-width:820px){body{-webkit-text-size-adjust:100%}nav a,nav button,.nav-links a,.nav-menu a,.nav-item,.topnav a,.menu a,.side a,.sidebar a,.docs-side a,.toc a,footer a,a.btn,.plan .btn,button.btn{display:inline-flex;align-items:center;min-height:44px}.side a,.sidebar a,.docs-side a{padding:10px 12px;border-radius:8px}.toc a{padding:8px 0}pre{max-width:100%;overflow-x:auto}.plans,.grid,.grid-2,.grid-3{grid-template-columns:1fr!important}.hero h1,.hero-title{font-size:clamp(24px,7vw,34px)!important}.tbl-scroll{max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}}</style>
|
||||||
|
|
||||||
|
<script id="h5-fix-js">(function(){var f=function(){document.querySelectorAll("table").forEach(function(t){var p=t.parentElement;if(p&&p.classList&&p.classList.contains("tbl-scroll"))return;var w=document.createElement("div");w.className="tbl-scroll";p.insertBefore(w,t);w.appendChild(t);});};if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",f);else f();})();</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header class="top"><div class="wrap top-in">
|
||||||
|
<a class="brand" href="/"><i>L</i>LokiStack</a>
|
||||||
|
<nav class="menu">
|
||||||
|
<a href="/#features">特性</a>
|
||||||
|
<a href="/docs/">文档</a>
|
||||||
|
<a href="/pricing" class="on">License & Pricing 许可和定价</a>
|
||||||
|
</nav>
|
||||||
|
<div class="top-cta"><a class="btn btn-primary" href="/docs/">快速开始</a></div>
|
||||||
|
</div></header>
|
||||||
|
|
||||||
|
<div id="intent-bar" hidden><div class="wrap in">
|
||||||
|
<span>🔗 你从应用内跳转而来</span><b id="intent-text"></b>
|
||||||
|
<a id="intent-link" href="#activate" style="display:none">查看激活步骤 →</a>
|
||||||
|
<button type="button" aria-label="关闭" onclick="document.getElementById('intent-bar').hidden=true">×</button>
|
||||||
|
</div></div>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<section class="hero wrap">
|
||||||
|
<span class="badge">30 天全功能试用 · 离线可激活 · 无需注册</span>
|
||||||
|
<h1>License & Pricing<br>许可和定价</h1>
|
||||||
|
<p>社区版永久免费;专业版 ¥99/年起,永久授权 ¥199 一次买断。所有版本功能完整,差别只在授权方式与设备数。</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="wrap">
|
||||||
|
<div class="plans">
|
||||||
|
<div class="plan" id="plan-free">
|
||||||
|
<h3>社区版</h3><div class="sub">个人 / 非商业使用</div>
|
||||||
|
<div class="price">¥0<small>/ 永久</small></div>
|
||||||
|
<ul>
|
||||||
|
<li>日志采集与查询</li><li>告警规则与通知</li><li>基础仪表盘</li><li>单机部署</li><li>社区支持</li>
|
||||||
|
</ul>
|
||||||
|
<a class="btn btn-outline" href="/docs/">免费开始</a>
|
||||||
|
</div>
|
||||||
|
<div class="plan rec" id="plan-pro">
|
||||||
|
<span class="tag">最受欢迎</span>
|
||||||
|
<h3>专业版 · 包年</h3><div class="sub">单设备授权 · 全功能</div>
|
||||||
|
<div class="price">¥99<small>/ 年</small></div>
|
||||||
|
<ul>
|
||||||
|
<li>全部功能 + 高级分析</li><li>在线授权 <kbd>LIC-</kbd></li><li>1 台设备</li><li>一年免费升级</li><li>邮件技术支持</li>
|
||||||
|
</ul>
|
||||||
|
<a class="btn btn-primary" href="mailto:admin@rlwj.cn?subject=%E8%B4%AD%E4%B9%B0%20LokiStack%20%E4%B8%93%E4%B8%9A%E7%89%88%E5%8C%85%E5%B9%B4">立即购买</a>
|
||||||
|
</div>
|
||||||
|
<div class="plan" id="plan-perpetual">
|
||||||
|
<h3>专业版 · 永久</h3><div class="sub">一次买断 · 离线许可</div>
|
||||||
|
<div class="price">¥199<small>/ 永久</small></div>
|
||||||
|
<ul>
|
||||||
|
<li>当前大版本永久可用</li><li>离线许可 <kbd>LICOFF-</kbd></li><li>1 台设备</li><li>1 年免费升级</li><li>邮件技术支持</li>
|
||||||
|
</ul>
|
||||||
|
<a class="btn btn-outline" href="mailto:admin@rlwj.cn?subject=%E8%B4%AD%E4%B9%B0%20LokiStack%20%E6%B0%B8%E4%B9%85%E7%89%88">立即购买</a>
|
||||||
|
</div>
|
||||||
|
<div class="plan" id="plan-ent">
|
||||||
|
<h3>企业私有化</h3><div class="sub">按席位 · 5 席起</div>
|
||||||
|
<div class="price">¥6,000<small>起 / 年</small></div>
|
||||||
|
<ul>
|
||||||
|
<li>集群 / 高可用部署</li><li>私有化与白牌交付</li><li>SSO / 审计 / 数据留存</li><li>专属支持与培训</li><li>可签合同与发票</li>
|
||||||
|
</ul>
|
||||||
|
<a class="btn btn-outline" href="mailto:admin@rlwj.cn?subject=%E5%92%A8%E8%AF%A2%20LokiStack%20%E4%BC%81%E4%B8%9A%E7%89%88">预约报价</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="wrap" id="activate">
|
||||||
|
<h2>激活:粘贴授权码即可</h2>
|
||||||
|
<p class="lead">付款后我们通过邮件交付授权码。在线授权以 <kbd>LIC-</kbd> 开头,离线许可证文件以 <kbd>LICOFF-</kbd> 开头。</p>
|
||||||
|
<div class="steps">
|
||||||
|
<div class="step"><b>邮件收码</b>付款后 1 个工作日内,授权码发送到你预留的邮箱</div>
|
||||||
|
<div class="step"><b>打开设置</b>程序内「设置 → 账户 / 授权」</div>
|
||||||
|
<div class="step"><b>粘贴激活</b>填入 <kbd>LIC-…</kbd> 点击激活;离线环境导入 <kbd>LICOFF-</kbd> 文件</div>
|
||||||
|
<div class="step"><b>完成</b>状态显示「已激活 / 剩余 N 天」,可在同一页解绑换机</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="faq wrap">
|
||||||
|
<h2>常见问题</h2>
|
||||||
|
<details open><summary>授权如何交付?包含哪些内容?</summary><p>邮件交付授权码 + 发票。授权与设备绑定,包含对应版本的全部功能与一年升级。</p></details>
|
||||||
|
<details><summary>换电脑怎么办?</summary><p>在程序「设置 → 授权」里先解绑,再在新设备激活;解绑次数不限,同一时间仅一台设备在线。</p></details>
|
||||||
|
<details><summary>可以离线使用吗?</summary><p>可以。选择永久/离线许可,我们会提供 <kbd>LICOFF-</kbd> 许可证文件,导入后无需联网校验。</p></details>
|
||||||
|
<details><summary>团队 / 企业怎么买?</summary><p>5 席起按席位计价,支持私有化与白牌交付、SSO 与审计。邮件说明规模与环境,我们给方案与报价。</p></details>
|
||||||
|
<details><summary>怎么付款?支持哪些方式?</summary><p>对公转账 / 支付宝,支持开票。本站不介入在线支付,付款与发票均走人工邮件确认。</p></details>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="cta wrap">
|
||||||
|
<div><h2>先用起来,再决定</h2><p>下载即含 30 天全功能试用,到期前随时激活。</p></div>
|
||||||
|
<a class="btn" href="/docs/">打开用户手册</a>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer><div class="wrap">
|
||||||
|
<span>© 2026 杭州日理万机智能科技有限公司</span>
|
||||||
|
<a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener">浙ICP备2026068677号</a>
|
||||||
|
<span>@日理万机</span>
|
||||||
|
<a href="/docs/">文档</a><a href="/pricing">许可和定价</a>
|
||||||
|
</div></footer>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var map = {
|
||||||
|
'app.license.purchase': { t: '为你定位到「专业版 · 包年」', target: 'plan-pro' },
|
||||||
|
'app.license.purchase.trialing': { t: '试用中 —— 升级到专业版可继续使用全部功能', target: 'plan-pro' },
|
||||||
|
'app.license.activate': { t: '按下面四步粘贴授权码即可激活', target: 'activate', link: true },
|
||||||
|
'purchase': { t: '为你定位到「专业版 · 包年」', target: 'plan-pro' },
|
||||||
|
'trialing': { t: '试用中 —— 升级到专业版可继续使用全部功能', target: 'plan-pro' },
|
||||||
|
'trial': { t: '试用中 —— 升级到专业版可继续使用全部功能', target: 'plan-pro' },
|
||||||
|
'activate': { t: '按下面四步粘贴授权码即可激活', target: 'activate', link: true },
|
||||||
|
'activation': { t: '按下面四步粘贴授权码即可激活', target: 'activate', link: true }
|
||||||
|
};
|
||||||
|
var q = new URLSearchParams(location.search);
|
||||||
|
var raw = (q.get('intent') || '').trim();
|
||||||
|
if (!raw) return;
|
||||||
|
var hit = map[raw] || map[raw.toLowerCase()];
|
||||||
|
if (!hit) {
|
||||||
|
for (var k in map) { if (raw.indexOf(k) === 0) { hit = map[k]; break; } }
|
||||||
|
}
|
||||||
|
if (!hit) hit = { t: '为你定位到许可与定价', target: 'plan-pro' };
|
||||||
|
var bar = document.getElementById('intent-bar');
|
||||||
|
document.getElementById('intent-text').textContent = ' ' + hit.t;
|
||||||
|
if (hit.link) document.getElementById('intent-link').style.display = '';
|
||||||
|
bar.hidden = false;
|
||||||
|
var el = document.getElementById(hit.target);
|
||||||
|
if (!el) return;
|
||||||
|
function go() {
|
||||||
|
el.scrollIntoView({ behavior: 'auto', block: 'center' });
|
||||||
|
if (el.classList.contains('plan')) el.classList.add('hl');
|
||||||
|
}
|
||||||
|
if (document.readyState === 'complete') setTimeout(go, 60);
|
||||||
|
else window.addEventListener('load', function () { setTimeout(go, 60); });
|
||||||
|
var stop = false;
|
||||||
|
['wheel', 'touchstart', 'keydown'].forEach(function (e) {
|
||||||
|
window.addEventListener(e, function () { stop = true; }, { once: true, passive: true });
|
||||||
|
});
|
||||||
|
window.addEventListener('load', function () { if (!stop) setTimeout(go, 400); });
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -7,6 +7,8 @@
|
|||||||
<meta name="description" content="LokiStack:把 Grafana Loki 部署到 Kubernetes 或裸金属,内置日志查询、日志分析与告警的一体化平台。部署向导、采集策略、查询授权、飞书告警开箱即用。">
|
<meta name="description" content="LokiStack:把 Grafana Loki 部署到 Kubernetes 或裸金属,内置日志查询、日志分析与告警的一体化平台。部署向导、采集策略、查询授权、飞书告警开箱即用。">
|
||||||
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%23059669'/%3E%3Ctext x='32' y='44' font-size='34' font-weight='800' fill='%23fff' text-anchor='middle' font-family='sans-serif'%3EL%3C/text%3E%3C/svg%3E">
|
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%23059669'/%3E%3Ctext x='32' y='44' font-size='34' font-weight='800' fill='%23fff' text-anchor='middle' font-family='sans-serif'%3EL%3C/text%3E%3C/svg%3E">
|
||||||
<link rel="stylesheet" href="assets/site.css">
|
<link rel="stylesheet" href="assets/site.css">
|
||||||
|
<style id="h5-fix">@media (max-width:820px){body{-webkit-text-size-adjust:100%}nav a,nav button,.nav-links a,.nav-menu a,.nav-item,.topnav a,.menu a,.side a,.sidebar a,.docs-side a,.toc a,footer a,a.btn,.plan .btn,button.btn{display:inline-flex;align-items:center;min-height:44px}.side a,.sidebar a,.docs-side a{padding:10px 12px;border-radius:8px}.toc a{padding:8px 0}pre{max-width:100%;overflow-x:auto}.plans,.grid,.grid-2,.grid-3{grid-template-columns:1fr!important}.hero h1,.hero-title{font-size:clamp(24px,7vw,34px)!important}.tbl-scroll{max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}}</style>
|
||||||
|
<script id="h5-fix-js">(function(){var f=function(){document.querySelectorAll("table").forEach(function(t){var p=t.parentElement;if(p&&p.classList&&p.classList.contains("tbl-scroll"))return;var w=document.createElement("div");w.className="tbl-scroll";p.insertBefore(w,t);w.appendChild(t);});};if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",f);else f();})();</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
@@ -18,9 +20,8 @@
|
|||||||
</a>
|
</a>
|
||||||
<nav class="nav-links">
|
<nav class="nav-links">
|
||||||
<a href="#features">特性</a>
|
<a href="#features">特性</a>
|
||||||
<a href="#quickstart">快速开始</a>
|
<a href="/docs/">文档</a>
|
||||||
<a href="#docs">文档</a>
|
<a href="/pricing">定价</a>
|
||||||
<a href="https://gitea.91ai.io/rlwj-lab/LokiStack" target="_blank" rel="noopener">源码</a>
|
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@@ -30,8 +31,8 @@
|
|||||||
<h1>把 Loki 日志聚合<br>变成<em>五分钟</em>的事</h1>
|
<h1>把 Loki 日志聚合<br>变成<em>五分钟</em>的事</h1>
|
||||||
<p class="tagline">向导式部署 Grafana Loki 到 Kubernetes 集群或裸金属主机,内置日志查询、可视化分析与飞书告警 —— 不写 YAML、不装 kubectl/Helm。</p>
|
<p class="tagline">向导式部署 Grafana Loki 到 Kubernetes 集群或裸金属主机,内置日志查询、可视化分析与飞书告警 —— 不写 YAML、不装 kubectl/Helm。</p>
|
||||||
<div class="hero-actions">
|
<div class="hero-actions">
|
||||||
<a class="btn btn-primary" href="#quickstart">快速开始</a>
|
<a class="btn btn-primary" href="/docs/">快速开始</a>
|
||||||
<a class="btn btn-outline" href="#docs">阅读文档</a>
|
<a class="btn btn-outline" href="/docs/">阅读文档</a>
|
||||||
</div>
|
</div>
|
||||||
<p class="hero-meta">Go + React 单二进制交付 · JSON 文件存储零依赖 · 中文/英文界面</p>
|
<p class="hero-meta">Go + React 单二进制交付 · JSON 文件存储零依赖 · 中文/英文界面</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -112,7 +113,7 @@
|
|||||||
<p class="sub">用户手册覆盖部署、采集、查询、分析与告警全流程</p>
|
<p class="sub">用户手册覆盖部署、采集、查询、分析与告警全流程</p>
|
||||||
<div class="hero-actions">
|
<div class="hero-actions">
|
||||||
<a class="btn btn-primary" href="/docs/">打开用户手册</a>
|
<a class="btn btn-primary" href="/docs/">打开用户手册</a>
|
||||||
<a class="btn btn-outline" href="https://gitea.91ai.io/rlwj-lab/LokiStack" target="_blank" rel="noopener">查看源码</a>
|
<a class="btn btn-outline" href="/pricing">许可和定价</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -120,7 +121,7 @@
|
|||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
<div class="links">
|
<div class="links">
|
||||||
<a href="#features">特性</a>
|
<a href="#features">特性</a>
|
||||||
<a href="#quickstart">快速开始</a>
|
<a href="/docs/">快速开始</a>
|
||||||
<a href="/docs/">文档</a>
|
<a href="/docs/">文档</a>
|
||||||
<a href="https://gitea.91ai.io/rlwj-lab/LokiStack" target="_blank" rel="noopener">Gitea</a>
|
<a href="https://gitea.91ai.io/rlwj-lab/LokiStack" target="_blank" rel="noopener">Gitea</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,213 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>License & Pricing 许可和定价 · LokiStack</title>
|
||||||
|
<meta name="description" content="LokiStack 许可与定价:社区版免费,专业版 ¥99/年起,永久授权 ¥199,团队版按席位,企业私有化交付。">
|
||||||
|
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%23059669'/%3E%3Ctext x='32' y='44' font-size='34' font-weight='800' fill='%23fff' text-anchor='middle' font-family='sans-serif'%3EL%3C/text%3E%3C/svg%3E">
|
||||||
|
<style>
|
||||||
|
:root{--brand:#059669;--brand-d:#047857;--ink:#0f172a;--muted:#5b6676;--line:#e6e9ee;--bg:#fff;--soft:#f7faf9}
|
||||||
|
*{box-sizing:border-box}
|
||||||
|
body{margin:0;font:15px/1.7 -apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;color:var(--ink);background:var(--bg)}
|
||||||
|
a{color:var(--brand-d);text-decoration:none}a:hover{text-decoration:underline}
|
||||||
|
.wrap{max-width:1140px;margin:0 auto;padding:0 20px}
|
||||||
|
header.top{position:sticky;top:0;z-index:30;background:rgba(255,255,255,.92);backdrop-filter:blur(8px);border-bottom:1px solid var(--line)}
|
||||||
|
.top-in{display:flex;align-items:center;gap:26px;height:62px}
|
||||||
|
.brand{display:flex;align-items:center;gap:9px;font-weight:800;font-size:16px;color:var(--ink)}
|
||||||
|
.brand i{width:28px;height:28px;border-radius:9px;background:var(--brand);color:#fff;display:grid;place-items:center;font-style:normal;font-weight:800}
|
||||||
|
nav.menu{display:flex;gap:22px;font-size:14.5px}
|
||||||
|
nav.menu a{color:#46505f}nav.menu a:hover{color:var(--brand-d)}
|
||||||
|
nav.menu a.on{color:var(--brand-d);font-weight:650}
|
||||||
|
.top-cta{margin-left:auto}
|
||||||
|
.btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:9px 16px;border-radius:9px;font-size:14px;font-weight:600;border:1px solid transparent;cursor:pointer}
|
||||||
|
.btn-primary{background:var(--brand);color:#fff}.btn-primary:hover{background:var(--brand-d);text-decoration:none}
|
||||||
|
.btn-outline{border-color:#cfd8d4;color:#26313f;background:#fff}.btn-outline:hover{border-color:var(--brand);color:var(--brand-d);text-decoration:none}
|
||||||
|
.hero{padding:56px 0 30px;text-align:center}
|
||||||
|
.badge{display:inline-block;padding:5px 12px;border-radius:999px;background:#e8f7f1;color:var(--brand-d);font-size:12.5px;font-weight:650;letter-spacing:.01em}
|
||||||
|
.hero h1{font-size:40px;line-height:1.22;margin:16px 0 10px;letter-spacing:-.02em}
|
||||||
|
.hero p{color:var(--muted);max-width:640px;margin:0 auto;font-size:16px}
|
||||||
|
#intent-bar{position:sticky;top:62px;z-index:29;background:#e8f7f1;border-bottom:1px solid #cdeee1;color:#065f46}
|
||||||
|
#intent-bar .in{display:flex;align-items:center;gap:10px;padding:10px 0;font-size:13.5px}
|
||||||
|
#intent-bar b{font-weight:700}
|
||||||
|
#intent-bar button{margin-left:auto;background:none;border:0;color:#065f46;font-size:18px;cursor:pointer;line-height:1}
|
||||||
|
.plans{display:grid;grid-template-columns:repeat(4,1fr);gap:18px;margin:34px 0 10px;align-items:stretch}
|
||||||
|
.plan{display:flex;flex-direction:column;border:1px solid var(--line);border-radius:14px;padding:20px;background:#fff;transition:.18s}
|
||||||
|
.plan:hover{box-shadow:0 8px 24px rgba(15,23,42,.07);transform:translateY(-2px)}
|
||||||
|
.plan.rec{border-color:var(--brand);box-shadow:0 0 0 1px var(--brand) inset}
|
||||||
|
.plan.hl{outline:3px solid rgba(5,150,105,.28);outline-offset:2px;animation:pulse 1.6s ease-in-out 2}
|
||||||
|
@keyframes pulse{0%,100%{box-shadow:0 0 0 0 rgba(5,150,105,.25)}50%{box-shadow:0 0 0 10px rgba(5,150,105,0)}}
|
||||||
|
.plan h3{margin:0 0 4px;font-size:16px}
|
||||||
|
.plan .sub{color:#8a94a3;font-size:12.5px;min-height:18px}
|
||||||
|
.price{margin:14px 0 4px;font-size:34px;font-weight:800;letter-spacing:-.02em}
|
||||||
|
.price small{font-size:13px;font-weight:600;color:#8a94a3;margin-left:3px}
|
||||||
|
.plan ul{list-style:none;padding:0;margin:16px 0 20px;font-size:13.5px;color:#3c4757;flex:1}
|
||||||
|
.plan li{padding:5px 0 5px 22px;position:relative}
|
||||||
|
.plan li:before{content:"";position:absolute;left:2px;top:11px;width:13px;height:7px;border-left:2px solid var(--brand);border-bottom:2px solid var(--brand);transform:rotate(-45deg)}
|
||||||
|
.plan .btn{width:100%}
|
||||||
|
.tag{display:inline-block;padding:2px 8px;border-radius:6px;background:#e8f7f1;color:var(--brand-d);font-size:11.5px;font-weight:700;margin-bottom:8px}
|
||||||
|
#activate{scroll-margin-top:90px;margin:56px 0 0;padding:26px;border:1px solid var(--line);border-radius:16px;background:var(--soft)}
|
||||||
|
#activate h2{margin:0 0 6px;font-size:22px}
|
||||||
|
#activate p.lead{color:var(--muted);margin:0 0 18px;font-size:14px}
|
||||||
|
.steps{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;counter-reset:s}
|
||||||
|
.step{background:#fff;border:1px solid var(--line);border-radius:12px;padding:14px 16px 14px 44px;position:relative;font-size:13.5px;color:#3c4757}
|
||||||
|
.step:before{counter-increment:s;content:counter(s);position:absolute;left:14px;top:13px;width:20px;height:20px;border-radius:50%;background:var(--brand);color:#fff;font-size:12px;font-weight:700;display:grid;place-items:center}
|
||||||
|
.step b{display:block;color:var(--ink);font-size:14px;margin-bottom:3px}
|
||||||
|
kbd{background:#eef2f4;border:1px solid #dbe2e6;border-bottom-width:2px;border-radius:5px;padding:1px 5px;font:12px ui-monospace,Menlo,monospace}
|
||||||
|
.faq{margin:54px 0 0}
|
||||||
|
.faq h2{font-size:22px;margin:0 0 14px}
|
||||||
|
details{border-bottom:1px solid var(--line);padding:14px 0}
|
||||||
|
summary{cursor:pointer;font-weight:600;font-size:15px;list-style:none}
|
||||||
|
summary::-webkit-details-marker{display:none}
|
||||||
|
summary:after{content:"+";float:right;color:#98a2b3;font-weight:400}
|
||||||
|
details[open] summary:after{content:"–"}
|
||||||
|
details p{color:var(--muted);font-size:14px;margin:10px 0 0}
|
||||||
|
.cta{margin:56px 0;padding:30px;border-radius:16px;background:linear-gradient(135deg,#059669,#065f46);color:#fff;display:flex;align-items:center;gap:20px;flex-wrap:wrap}
|
||||||
|
.cta h2{margin:0;font-size:22px}.cta p{margin:4px 0 0;opacity:.9;font-size:14px}
|
||||||
|
.cta .btn{margin-left:auto;background:#fff;color:var(--brand-d)}
|
||||||
|
footer{border-top:1px solid var(--line);padding:24px 0;color:#98a2b3;font-size:12.5px}
|
||||||
|
footer .wrap{display:flex;gap:16px;flex-wrap:wrap;align-items:center}
|
||||||
|
footer a{color:#6b7684}
|
||||||
|
@media (max-width:960px){.plans{grid-template-columns:repeat(2,1fr)}.steps{grid-template-columns:repeat(2,1fr)}.hero h1{font-size:30px}}
|
||||||
|
@media (max-width:640px){nav.menu{display:none}.plans{grid-template-columns:1fr}.steps{grid-template-columns:1fr}.hero{padding:36px 0 20px}.hero h1{font-size:26px}}
|
||||||
|
</style>
|
||||||
|
<style id="h5-fix">@media (max-width:820px){body{-webkit-text-size-adjust:100%}nav a,nav button,.nav-links a,.nav-menu a,.nav-item,.topnav a,.menu a,.side a,.sidebar a,.docs-side a,.toc a,footer a,a.btn,.plan .btn,button.btn{display:inline-flex;align-items:center;min-height:44px}.side a,.sidebar a,.docs-side a{padding:10px 12px;border-radius:8px}.toc a{padding:8px 0}pre{max-width:100%;overflow-x:auto}.plans,.grid,.grid-2,.grid-3{grid-template-columns:1fr!important}.hero h1,.hero-title{font-size:clamp(24px,7vw,34px)!important}.tbl-scroll{max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}}</style>
|
||||||
|
|
||||||
|
<script id="h5-fix-js">(function(){var f=function(){document.querySelectorAll("table").forEach(function(t){var p=t.parentElement;if(p&&p.classList&&p.classList.contains("tbl-scroll"))return;var w=document.createElement("div");w.className="tbl-scroll";p.insertBefore(w,t);w.appendChild(t);});};if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",f);else f();})();</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header class="top"><div class="wrap top-in">
|
||||||
|
<a class="brand" href="/"><i>L</i>LokiStack</a>
|
||||||
|
<nav class="menu">
|
||||||
|
<a href="/#features">特性</a>
|
||||||
|
<a href="/docs/">文档</a>
|
||||||
|
<a href="/pricing" class="on">License & Pricing 许可和定价</a>
|
||||||
|
</nav>
|
||||||
|
<div class="top-cta"><a class="btn btn-primary" href="/docs/">快速开始</a></div>
|
||||||
|
</div></header>
|
||||||
|
|
||||||
|
<div id="intent-bar" hidden><div class="wrap in">
|
||||||
|
<span>🔗 你从应用内跳转而来</span><b id="intent-text"></b>
|
||||||
|
<a id="intent-link" href="#activate" style="display:none">查看激活步骤 →</a>
|
||||||
|
<button type="button" aria-label="关闭" onclick="document.getElementById('intent-bar').hidden=true">×</button>
|
||||||
|
</div></div>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<section class="hero wrap">
|
||||||
|
<span class="badge">30 天全功能试用 · 离线可激活 · 无需注册</span>
|
||||||
|
<h1>License & Pricing<br>许可和定价</h1>
|
||||||
|
<p>社区版永久免费;专业版 ¥99/年起,永久授权 ¥199 一次买断。所有版本功能完整,差别只在授权方式与设备数。</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="wrap">
|
||||||
|
<div class="plans">
|
||||||
|
<div class="plan" id="plan-free">
|
||||||
|
<h3>社区版</h3><div class="sub">个人 / 非商业使用</div>
|
||||||
|
<div class="price">¥0<small>/ 永久</small></div>
|
||||||
|
<ul>
|
||||||
|
<li>日志采集与查询</li><li>告警规则与通知</li><li>基础仪表盘</li><li>单机部署</li><li>社区支持</li>
|
||||||
|
</ul>
|
||||||
|
<a class="btn btn-outline" href="/docs/">免费开始</a>
|
||||||
|
</div>
|
||||||
|
<div class="plan rec" id="plan-pro">
|
||||||
|
<span class="tag">最受欢迎</span>
|
||||||
|
<h3>专业版 · 包年</h3><div class="sub">单设备授权 · 全功能</div>
|
||||||
|
<div class="price">¥99<small>/ 年</small></div>
|
||||||
|
<ul>
|
||||||
|
<li>全部功能 + 高级分析</li><li>在线授权 <kbd>LIC-</kbd></li><li>1 台设备</li><li>一年免费升级</li><li>邮件技术支持</li>
|
||||||
|
</ul>
|
||||||
|
<a class="btn btn-primary" href="mailto:admin@rlwj.cn?subject=%E8%B4%AD%E4%B9%B0%20LokiStack%20%E4%B8%93%E4%B8%9A%E7%89%88%E5%8C%85%E5%B9%B4">立即购买</a>
|
||||||
|
</div>
|
||||||
|
<div class="plan" id="plan-perpetual">
|
||||||
|
<h3>专业版 · 永久</h3><div class="sub">一次买断 · 离线许可</div>
|
||||||
|
<div class="price">¥199<small>/ 永久</small></div>
|
||||||
|
<ul>
|
||||||
|
<li>当前大版本永久可用</li><li>离线许可 <kbd>LICOFF-</kbd></li><li>1 台设备</li><li>1 年免费升级</li><li>邮件技术支持</li>
|
||||||
|
</ul>
|
||||||
|
<a class="btn btn-outline" href="mailto:admin@rlwj.cn?subject=%E8%B4%AD%E4%B9%B0%20LokiStack%20%E6%B0%B8%E4%B9%85%E7%89%88">立即购买</a>
|
||||||
|
</div>
|
||||||
|
<div class="plan" id="plan-ent">
|
||||||
|
<h3>企业私有化</h3><div class="sub">按席位 · 5 席起</div>
|
||||||
|
<div class="price">¥6,000<small>起 / 年</small></div>
|
||||||
|
<ul>
|
||||||
|
<li>集群 / 高可用部署</li><li>私有化与白牌交付</li><li>SSO / 审计 / 数据留存</li><li>专属支持与培训</li><li>可签合同与发票</li>
|
||||||
|
</ul>
|
||||||
|
<a class="btn btn-outline" href="mailto:admin@rlwj.cn?subject=%E5%92%A8%E8%AF%A2%20LokiStack%20%E4%BC%81%E4%B8%9A%E7%89%88">预约报价</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="wrap" id="activate">
|
||||||
|
<h2>激活:粘贴授权码即可</h2>
|
||||||
|
<p class="lead">付款后我们通过邮件交付授权码。在线授权以 <kbd>LIC-</kbd> 开头,离线许可证文件以 <kbd>LICOFF-</kbd> 开头。</p>
|
||||||
|
<div class="steps">
|
||||||
|
<div class="step"><b>邮件收码</b>付款后 1 个工作日内,授权码发送到你预留的邮箱</div>
|
||||||
|
<div class="step"><b>打开设置</b>程序内「设置 → 账户 / 授权」</div>
|
||||||
|
<div class="step"><b>粘贴激活</b>填入 <kbd>LIC-…</kbd> 点击激活;离线环境导入 <kbd>LICOFF-</kbd> 文件</div>
|
||||||
|
<div class="step"><b>完成</b>状态显示「已激活 / 剩余 N 天」,可在同一页解绑换机</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="faq wrap">
|
||||||
|
<h2>常见问题</h2>
|
||||||
|
<details open><summary>授权如何交付?包含哪些内容?</summary><p>邮件交付授权码 + 发票。授权与设备绑定,包含对应版本的全部功能与一年升级。</p></details>
|
||||||
|
<details><summary>换电脑怎么办?</summary><p>在程序「设置 → 授权」里先解绑,再在新设备激活;解绑次数不限,同一时间仅一台设备在线。</p></details>
|
||||||
|
<details><summary>可以离线使用吗?</summary><p>可以。选择永久/离线许可,我们会提供 <kbd>LICOFF-</kbd> 许可证文件,导入后无需联网校验。</p></details>
|
||||||
|
<details><summary>团队 / 企业怎么买?</summary><p>5 席起按席位计价,支持私有化与白牌交付、SSO 与审计。邮件说明规模与环境,我们给方案与报价。</p></details>
|
||||||
|
<details><summary>怎么付款?支持哪些方式?</summary><p>对公转账 / 支付宝,支持开票。本站不介入在线支付,付款与发票均走人工邮件确认。</p></details>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="cta wrap">
|
||||||
|
<div><h2>先用起来,再决定</h2><p>下载即含 30 天全功能试用,到期前随时激活。</p></div>
|
||||||
|
<a class="btn" href="/docs/">打开用户手册</a>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer><div class="wrap">
|
||||||
|
<span>© 2026 杭州日理万机智能科技有限公司</span>
|
||||||
|
<a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener">浙ICP备2026068677号</a>
|
||||||
|
<span>@日理万机</span>
|
||||||
|
<a href="/docs/">文档</a><a href="/pricing">许可和定价</a>
|
||||||
|
</div></footer>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var map = {
|
||||||
|
'app.license.purchase': { t: '为你定位到「专业版 · 包年」', target: 'plan-pro' },
|
||||||
|
'app.license.purchase.trialing': { t: '试用中 —— 升级到专业版可继续使用全部功能', target: 'plan-pro' },
|
||||||
|
'app.license.activate': { t: '按下面四步粘贴授权码即可激活', target: 'activate', link: true },
|
||||||
|
'purchase': { t: '为你定位到「专业版 · 包年」', target: 'plan-pro' },
|
||||||
|
'trialing': { t: '试用中 —— 升级到专业版可继续使用全部功能', target: 'plan-pro' },
|
||||||
|
'trial': { t: '试用中 —— 升级到专业版可继续使用全部功能', target: 'plan-pro' },
|
||||||
|
'activate': { t: '按下面四步粘贴授权码即可激活', target: 'activate', link: true },
|
||||||
|
'activation': { t: '按下面四步粘贴授权码即可激活', target: 'activate', link: true }
|
||||||
|
};
|
||||||
|
var q = new URLSearchParams(location.search);
|
||||||
|
var raw = (q.get('intent') || '').trim();
|
||||||
|
if (!raw) return;
|
||||||
|
var hit = map[raw] || map[raw.toLowerCase()];
|
||||||
|
if (!hit) {
|
||||||
|
for (var k in map) { if (raw.indexOf(k) === 0) { hit = map[k]; break; } }
|
||||||
|
}
|
||||||
|
if (!hit) hit = { t: '为你定位到许可与定价', target: 'plan-pro' };
|
||||||
|
var bar = document.getElementById('intent-bar');
|
||||||
|
document.getElementById('intent-text').textContent = ' ' + hit.t;
|
||||||
|
if (hit.link) document.getElementById('intent-link').style.display = '';
|
||||||
|
bar.hidden = false;
|
||||||
|
var el = document.getElementById(hit.target);
|
||||||
|
if (!el) return;
|
||||||
|
function go() {
|
||||||
|
el.scrollIntoView({ behavior: 'auto', block: 'center' });
|
||||||
|
if (el.classList.contains('plan')) el.classList.add('hl');
|
||||||
|
}
|
||||||
|
if (document.readyState === 'complete') setTimeout(go, 60);
|
||||||
|
else window.addEventListener('load', function () { setTimeout(go, 60); });
|
||||||
|
var stop = false;
|
||||||
|
['wheel', 'touchstart', 'keydown'].forEach(function (e) {
|
||||||
|
window.addEventListener(e, function () { stop = true; }, { once: true, passive: true });
|
||||||
|
});
|
||||||
|
window.addEventListener('load', function () { if (!stop) setTimeout(go, 400); });
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,195 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""把 /srv/LokiStack/docs/user-guide/*.md 按 manifest.json 静态渲染成文档站,
|
||||||
|
输出到 /srv/LokiStack/homepage/dist/docs/ (与 landing 一起构成 dist 产物) // Logan.Li
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import markdown
|
||||||
|
|
||||||
|
SRC = Path("/srv/LokiStack/docs")
|
||||||
|
GUIDE = SRC / "user-guide"
|
||||||
|
OUT = Path("/srv/LokiStack/homepage/dist")
|
||||||
|
DOCS_OUT = OUT / "docs"
|
||||||
|
|
||||||
|
CSS = """
|
||||||
|
:root{--brand:#059669;--brand-d: #047857;--ink:#0f172a;--muted:#5b6676;--line:#e6e9ee;--bg:#fff;--side:#f7f9f8}
|
||||||
|
*{box-sizing:border-box}
|
||||||
|
body{margin:0;font:15px/1.75 -apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;color:var(--ink);background:var(--bg)}
|
||||||
|
a{color:var(--brand-d);text-decoration:none}a:hover{text-decoration:underline}
|
||||||
|
.topbar{position:sticky;top:0;z-index:20;display:flex;align-items:center;gap:18px;height:56px;padding:0 20px;background:rgba(255,255,255,.92);backdrop-filter:blur(8px);border-bottom:1px solid var(--line)}
|
||||||
|
.brand{display:flex;align-items:center;gap:9px;font-weight:800;font-size:15px;color:var(--ink)}
|
||||||
|
.brand i{width:26px;height:26px;border-radius:8px;background:var(--brand);color:#fff;display:grid;place-items:center;font-style:normal;font-weight:800;font-size:14px}
|
||||||
|
.topnav{display:flex;gap:16px;margin-left:auto;font-size:14px}
|
||||||
|
.topnav a{color:var(--muted)}.topnav a:hover{color:var(--brand-d)}
|
||||||
|
.layout{display:grid;grid-template-columns:250px minmax(0,1fr) 200px;gap:34px;max-width:1240px;margin:0 auto;padding:26px 20px 70px}
|
||||||
|
aside.side{position:sticky;top:80px;align-self:start;max-height:calc(100vh - 100px);overflow:auto;font-size:14px}
|
||||||
|
.side h4{margin:18px 0 6px;font-size:11px;letter-spacing:.09em;text-transform:uppercase;color:#93a0af;font-weight:700}
|
||||||
|
.side a{display:block;padding:5px 10px;border-radius:7px;color:#3b4656}
|
||||||
|
.side a:hover{background:var(--side);text-decoration:none}
|
||||||
|
.side a.on{background:#e8f7f1;color:var(--brand-d);font-weight:650}
|
||||||
|
article{min-width:0}
|
||||||
|
article h1{font-size:30px;line-height:1.3;margin:0 0 8px;letter-spacing:-.01em}
|
||||||
|
.meta{color:#98a2b3;font-size:12.5px;margin-bottom:22px}
|
||||||
|
article h2{font-size:21px;margin:32px 0 10px;padding-bottom:7px;border-bottom:1px solid var(--line)}
|
||||||
|
article h3{font-size:17px;margin:24px 0 8px}
|
||||||
|
article p{margin:12px 0}
|
||||||
|
article img{max-width:100%;height:auto;border:1px solid var(--line);border-radius:10px;margin:14px 0;box-shadow:0 1px 3px rgba(16,24,40,.06)}
|
||||||
|
article pre{background:#0f172a;color:#e6edf3;padding:14px 16px;border-radius:10px;overflow:auto;font-size:13px;line-height:1.6}
|
||||||
|
article code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px}
|
||||||
|
article :not(pre)>code{background:#f1f5f9;padding:2px 5px;border-radius:5px;color:#0f766e}
|
||||||
|
article table{border-collapse:collapse;width:100%;margin:14px 0;font-size:14px}
|
||||||
|
article th,article td{border:1px solid var(--line);padding:8px 10px;text-align:left}
|
||||||
|
article th{background:var(--side)}
|
||||||
|
article blockquote{margin:14px 0;padding:10px 16px;border-left:3px solid var(--brand);background:#f4fbf8;color:#33415c;border-radius:0 8px 8px 0}
|
||||||
|
.toc{position:sticky;top:84px;align-self:start;font-size:13px;color:var(--muted)}
|
||||||
|
.toc b{display:block;font-size:11px;letter-spacing:.09em;text-transform:uppercase;color:#93a0af;margin-bottom:8px}
|
||||||
|
.toc a{display:block;padding:3px 0 3px 10px;border-left:2px solid var(--line);color:#5b6676}
|
||||||
|
.toc a:hover{color:var(--brand-d);border-color:var(--brand)}
|
||||||
|
.pager{display:flex;justify-content:space-between;gap:16px;margin-top:46px;padding-top:18px;border-top:1px solid var(--line);font-size:14px}
|
||||||
|
footer{border-top:1px solid var(--line);padding:20px;text-align:center;color:#98a2b3;font-size:12.5px}
|
||||||
|
@media (max-width:1080px){.layout{grid-template-columns:230px minmax(0,1fr)}.toc{display:none}}
|
||||||
|
@media (max-width:820px){.layout{grid-template-columns:1fr;padding-top:16px}aside.side{position:static;max-height:none;border-bottom:1px solid var(--line);padding-bottom:10px}.topnav{display:none}}
|
||||||
|
"""
|
||||||
|
|
||||||
|
H5_FIX = """<style id="h5-fix">@media (max-width:820px){body{-webkit-text-size-adjust:100%}nav a,nav button,.nav-links a,.nav-menu a,.nav-item,.topnav a,.menu a,.side a,.sidebar a,.docs-side a,.toc a,footer a,a.btn,.plan .btn,button.btn{display:inline-flex;align-items:center;min-height:44px}.side a,.sidebar a,.docs-side a{padding:10px 12px;border-radius:8px}.toc a{padding:8px 0}pre{max-width:100%;overflow-x:auto}.plans,.grid,.grid-2,.grid-3{grid-template-columns:1fr!important}.hero h1,.hero-title{font-size:clamp(24px,7vw,34px)!important}.tbl-scroll{max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}}</style>
|
||||||
|
<script id="h5-fix-js">(function(){var f=function(){document.querySelectorAll("table").forEach(function(t){var p=t.parentElement;if(p&&p.classList&&p.classList.contains("tbl-scroll"))return;var w=document.createElement("div");w.className="tbl-scroll";p.insertBefore(w,t);w.appendChild(t);});};if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",f);else f();})();</script>"""
|
||||||
|
|
||||||
|
PAGE = """<!doctype html>
|
||||||
|
<html lang="zh-CN"><head>
|
||||||
|
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<title>{title} · LokiStack 文档</title>
|
||||||
|
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%23059669'/%3E%3Ctext x='32' y='44' font-size='34' font-weight='800' fill='%23fff' text-anchor='middle' font-family='sans-serif'%3EL%3C/text%3E%3C/svg%3E">
|
||||||
|
<link rel="stylesheet" href="/docs/assets/loki-docs.css">
|
||||||
|
{h5fix}
|
||||||
|
</head><body>
|
||||||
|
<div class="topbar">
|
||||||
|
<a class="brand" href="/"><i>L</i>LokiStack</a>
|
||||||
|
<span style="color:#98a2b3;font-size:13px">文档</span>
|
||||||
|
<nav class="topnav"><a href="/">官网</a><a href="/docs/" class="on">文档</a></nav>
|
||||||
|
</div>
|
||||||
|
<div class="layout">
|
||||||
|
<aside class="side">{side}</aside>
|
||||||
|
<article>
|
||||||
|
<h1>{h1}</h1>
|
||||||
|
<div class="meta">{group} · 更新于 {updated}</div>
|
||||||
|
{body}
|
||||||
|
<div class="pager">{pager}</div>
|
||||||
|
</article>
|
||||||
|
<nav class="toc"><b>本页目录</b>{toc}</nav>
|
||||||
|
</div>
|
||||||
|
<footer>LokiStack · <a href="/">返回官网</a> · © 日理万机</footer>
|
||||||
|
</body></html>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def slugify(t):
|
||||||
|
return re.sub(r"[^\w\u4e00-\u9fa5]+", "-", t.lower()).strip("-")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
manifest = json.loads((GUIDE / "manifest.json").read_text(encoding="utf-8"))
|
||||||
|
groups = manifest.get("groups", [])
|
||||||
|
version = manifest.get("productVersion", "")
|
||||||
|
|
||||||
|
pages = []
|
||||||
|
for g in groups:
|
||||||
|
for p in g.get("pages", []):
|
||||||
|
pages.append({
|
||||||
|
"group": g.get("name", ""),
|
||||||
|
"file": p.get("file", ""),
|
||||||
|
"slug": p.get("slug") or slugify(p.get("title", "")),
|
||||||
|
"title": p.get("title", ""),
|
||||||
|
"updated": p.get("updated", ""),
|
||||||
|
})
|
||||||
|
print(f" manifest: {len(groups)} 组 / {len(pages)} 页 (v{version})")
|
||||||
|
|
||||||
|
# 资源
|
||||||
|
DOCS_OUT.mkdir(parents=True, exist_ok=True)
|
||||||
|
# 文档资源:优先用 homepage/assets(站点自包含,不再依赖仓库 docs/ 目录) // Logan.Li
|
||||||
|
hp_assets = Path("/srv/LokiStack/homepage/assets")
|
||||||
|
if hp_assets.exists():
|
||||||
|
shutil.copytree(hp_assets, DOCS_OUT / "assets", dirs_exist_ok=True)
|
||||||
|
if (SRC / "assets").exists():
|
||||||
|
shutil.copytree(SRC / "assets", DOCS_OUT / "assets", dirs_exist_ok=True)
|
||||||
|
(DOCS_OUT / "assets").mkdir(parents=True, exist_ok=True)
|
||||||
|
(DOCS_OUT / "assets" / "loki-docs.css").write_text(CSS, encoding="utf-8")
|
||||||
|
print(f" assets: {(SRC / 'assets').exists() and '已复制' or '无'}(含 screenshots)")
|
||||||
|
|
||||||
|
md = markdown.Markdown(extensions=["extra", "toc", "sane_lists", "nl2br"],
|
||||||
|
extension_configs={"toc": {"permalink": False}})
|
||||||
|
|
||||||
|
# 侧栏(所有页共用一个 DOM)
|
||||||
|
side = ""
|
||||||
|
last_group = None
|
||||||
|
for p in pages:
|
||||||
|
if p["group"] != last_group:
|
||||||
|
side += f'<h4>{p["group"]}</h4>'
|
||||||
|
last_group = p["group"]
|
||||||
|
side += f'<a data-slug="{p["slug"]}" href="/docs/{p["slug"]}/">{p["title"]}</a>'
|
||||||
|
|
||||||
|
out_pages = []
|
||||||
|
for i, p in enumerate(pages):
|
||||||
|
src = GUIDE / p["file"]
|
||||||
|
if not src.exists():
|
||||||
|
print(f" ⚠️ 缺文件: {p['file']}")
|
||||||
|
continue
|
||||||
|
text = src.read_text(encoding="utf-8")
|
||||||
|
# 第一行若是 H1 就当标题用掉
|
||||||
|
h1 = p["title"]
|
||||||
|
m = re.match(r"^\s*#\s+(.+)$", text, re.M)
|
||||||
|
if m:
|
||||||
|
h1 = m.group(1).strip()
|
||||||
|
text = re.sub(r"^\s*#\s+.+\n", "", text, count=1)
|
||||||
|
md.reset()
|
||||||
|
body = md.convert(text)
|
||||||
|
toc_html = ""
|
||||||
|
for t in md.toc_tokens:
|
||||||
|
if t["level"] <= 3:
|
||||||
|
toc_html += f'<a href="#{t["id"]}">{t["name"]}</a>'
|
||||||
|
# 图片相对路径: docs 页里的 images 走 /docs/assets/screenshots/
|
||||||
|
body = re.sub(r'src="(?!https?:|/|data:)', 'src="/docs/assets/', body)
|
||||||
|
pager = ""
|
||||||
|
if i > 0:
|
||||||
|
pager += f'<a href="/docs/{pages[i-1]["slug"]}/">← {pages[i-1]["title"]}</a>'
|
||||||
|
else:
|
||||||
|
pager += "<span></span>"
|
||||||
|
if i < len(pages) - 1:
|
||||||
|
pager += f'<a href="/docs/{pages[i+1]["slug"]}/">{pages[i+1]["title"]} →</a>'
|
||||||
|
html = PAGE.format(h5fix=H5_FIX, title=h1, h1=h1, group=p["group"], updated=p["updated"] or "—",
|
||||||
|
body=body, side=side, toc=toc_html, pager=pager)
|
||||||
|
html = html.replace('href="/docs/%s/"' % p["slug"], 'href="/docs/%s/" class="on"' % p["slug"])
|
||||||
|
d = DOCS_OUT / p["slug"]
|
||||||
|
d.mkdir(parents=True, exist_ok=True)
|
||||||
|
(d / "index.html").write_text(html, encoding="utf-8")
|
||||||
|
out_pages.append(p)
|
||||||
|
print(f" ✓ /docs/{p['slug']}/ ({len(html)}B)")
|
||||||
|
|
||||||
|
# /docs/ 入口 = 第一页内容
|
||||||
|
if out_pages:
|
||||||
|
first = out_pages[0]
|
||||||
|
idx = (DOCS_OUT / first["slug"] / "index.html").read_text(encoding="utf-8")
|
||||||
|
(DOCS_OUT / "index.html").write_text(idx, encoding="utf-8")
|
||||||
|
print(f" ✓ /docs/ → {first['title']}")
|
||||||
|
|
||||||
|
# 落地页与资源一并进 dist(与其它三站一致的“dist 即产物”结构)
|
||||||
|
hp = Path("/srv/LokiStack/homepage")
|
||||||
|
for page in ("index.html", "pricing.html"):
|
||||||
|
if (hp / page).exists():
|
||||||
|
shutil.copy2(hp / page, OUT / page)
|
||||||
|
if (hp / "assets").exists():
|
||||||
|
# 只同步顶层静态资源(site.css 等);截图仅由 docs 走 /docs/assets/screenshots/,避免 dist 里存两份副本 // Logan.Li
|
||||||
|
(OUT / "assets").mkdir(parents=True, exist_ok=True)
|
||||||
|
for item in (hp / "assets").iterdir():
|
||||||
|
if item.is_file():
|
||||||
|
shutil.copy2(item, OUT / "assets" / item.name)
|
||||||
|
print(f" 落地页/资源已同步进 dist")
|
||||||
|
print(f" 产物文件数: {sum(1 for _ in OUT.rglob('*') if _.is_file())}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||