figure:first-child { margin-top: -20px; }
#write ol, #write ul { position: relative; }
img { max-width: 100%; vertical-align: middle; }
button, input, select, textarea { color: inherit; font-family: inherit; font-size: inherit; font-style: inherit; font-variant-caps: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; }
input[type="checkbox"], input[type="radio"] { line-height: normal; padding: 0px; }
*, ::after, ::before { box-sizing: border-box; }
#write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write p, #write pre { width: inherit; }
#write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write p { position: relative; }
h1, h2, h3, h4, h5, h6 { break-after: avoid-page; break-inside: avoid; orphans: 2; }
p { orphans: 4; }
h1 { font-size: 2rem; }
h2 { font-size: 1.8rem; }
h3 { font-size: 1.6rem; }
h4 { font-size: 1.4rem; }
h5 { font-size: 1.2rem; }
h6 { font-size: 1rem; }
.md-math-block, .md-rawblock, h1, h2, h3, h4, h5, h6, p { margin-top: 1rem; margin-bottom: 1rem; }
.hidden { display: none; }
.md-blockmeta { color: rgb(204, 204, 204); font-weight: 700; font-style: italic; }
a { cursor: pointer; }
sup.md-footnote { padding: 2px 4px; background-color: rgba(238, 238, 238, 0.701961); color: rgb(85, 85, 85); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; cursor: pointer; }
sup.md-footnote a, sup.md-footnote a:hover { color: inherit; text-transform: inherit; text-decoration: inherit; }
#write input[type="checkbox"] { cursor: pointer; width: inherit; height: inherit; }
figure { overflow-x: auto; margin: 1.2em 0px; max-width: calc(100% + 16px); padding: 0px; }
figure > table { margin: 0px !important; }
tr { break-inside: avoid; break-after: auto; }
thead { display: table-header-group; }
table { border-collapse: collapse; border-spacing: 0px; width: 100%; overflow: auto; break-inside: auto; text-align: left; }
table.md-table td { min-width: 32px; }
.CodeMirror-gutters { border-right-width: 0px; background-color: inherit; }
.CodeMirror { text-align: left; }
.CodeMirror-placeholder { opacity: 0.3; }
.CodeMirror pre { padding: 0px 4px; }
.CodeMirror-lines { padding: 0px; }
div.hr:focus { cursor: none; }
#write pre { white-space: pre-wrap; }
#write.fences-no-line-wrapping pre { white-space: pre; }
#write pre.ty-contain-cm { white-space: normal; }
.CodeMirror-gutters { margin-right: 4px; }
.md-fences { font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; overflow: visible; white-space: pre; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; position: relative !important; background-position: inherit inherit; background-repeat: inherit inherit; }
.md-diagram-panel { width: 100%; margin-top: 10px; text-align: center; padding-top: 0px; padding-bottom: 8px; overflow-x: auto; }
#write .md-fences.mock-cm { white-space: pre-wrap; }
.md-fences.md-fences-with-lineno { padding-left: 0px; }
#write.fences-no-line-wrapping .md-fences.mock-cm { white-space: pre; overflow-x: auto; }
.md-fences.mock-cm.md-fences-with-lineno { padding-left: 8px; }
.CodeMirror-line, twitterwidget { break-inside: avoid; }
.footnotes { opacity: 0.8; font-size: 0.9rem; margin-top: 1em; margin-bottom: 1em; }
.footnotes + .footnotes { margin-top: 0px; }
.md-reset { margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: top; text-decoration: none; text-shadow: none; float: none; position: static; width: auto; height: auto; white-space: nowrap; cursor: inherit; line-height: normal; font-weight: 400; text-align: left; box-sizing: content-box; direction: ltr; background-position: 0px 0px; background-repeat: initial initial; }
li div { padding-top: 0px; }
blockquote { margin: 1rem 0px; }
li .mathjax-block, li p { margin: 0.5rem 0px; }
li { margin: 0px; position: relative; }
blockquote > :last-child { margin-bottom: 0px; }
blockquote > :first-child, li > :first-child { margin-top: 0px; }
.footnotes-area { color: rgb(136, 136, 136); margin-top: 0.714rem; padding-bottom: 0.143rem; white-space: normal; }
#write .footnote-line { white-space: pre-wrap; }
@media print {
body, html { border: 1px solid transparent; height: 99%; break-after: avoid-page; break-before: avoid-page; }
#write { margin-top: 0px; padding-top: 0px; border-color: transparent !important; }
.typora-export * { -webkit-print-color-adjust: exact; }
html.blink-to-pdf { font-size: 13px; }
.typora-export #write { padding-left: 32px; padding-right: 32px; padding-bottom: 0px; break-after: avoid-page; }
.typora-export #write::after { height: 0px; }
@page { margin: 20mm 0px; }
}
.footnote-line { margin-top: 0.714em; font-size: 0.7em; }
a img, img a { cursor: pointer; }
pre.md-meta-block { font-size: 0.8rem; min-height: 0.8rem; white-space: pre-wrap; background-color: rgb(204, 204, 204); display: block; overflow-x: hidden; background-position: initial initial; background-repeat: initial initial; }
p > .md-image:only-child:not(.md-img-error) img, p > img:only-child { display: block; margin: auto; }
p > .md-image:only-child { display: inline-block; width: 100%; }
#write .MathJax_Display { margin: 0.8em 0px 0px; }
.md-math-block { width: 100%; }
.md-math-block:not(:empty)::after { display: none; }
[contenteditable="true"]:active, [contenteditable="true"]:focus { outline: 0px; box-shadow: none; }
.md-task-list-item { position: relative; list-style-type: none; }
.task-list-item.md-task-list-item { padding-left: 0px; }
.md-task-list-item > input { position: absolute; top: 0px; left: 0px; margin-left: -1.2em; margin-top: calc(1em - 10px); border: none; }
.math { font-size: 1rem; }
.md-toc { min-height: 3.58rem; position: relative; font-size: 0.9rem; border-top-left-radius: 10px; border-top-right-radius: 10px; border-bottom-right-radius: 10px; border-bottom-left-radius: 10px; }
.md-toc-content { position: relative; margin-left: 0px; }
.md-toc-content::after, .md-toc::after { display: none; }
.md-toc-item { display: block; color: rgb(65, 131, 196); }
.md-toc-item a { text-decoration: none; }
.md-toc-inner:hover { text-decoration: underline; }
.md-toc-inner { display: inline-block; cursor: pointer; }
.md-toc-h1 .md-toc-inner { margin-left: 0px; font-weight: 700; }
.md-toc-h2 .md-toc-inner { margin-left: 2em; }
.md-toc-h3 .md-toc-inner { margin-left: 4em; }
.md-toc-h4 .md-toc-inner { margin-left: 6em; }
.md-toc-h5 .md-toc-inner { margin-left: 8em; }
.md-toc-h6 .md-toc-inner { margin-left: 10em; }
@media screen and (max-width: 48em) {
.md-toc-h3 .md-toc-inner { margin-left: 3.5em; }
.md-toc-h4 .md-toc-inner { margin-left: 5em; }
.md-toc-h5 .md-toc-inner { margin-left: 6.5em; }
.md-toc-h6 .md-toc-inner { margin-left: 8em; }
}
a.md-toc-inner { font-size: inherit; font-style: inherit; font-weight: inherit; line-height: inherit; }
.footnote-line a:not(.reversefootnote) { color: inherit; }
.md-attr { display: none; }
.md-fn-count::after { content: "."; }
code, pre, samp, tt { font-family: var(--monospace); }
kbd { margin: 0px 0.1em; padding: 0.1em 0.6em; font-size: 0.8em; color: rgb(36, 39, 41); background-color: rgb(255, 255, 255); border: 1px solid rgb(173, 179, 185); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; box-shadow: rgba(12, 13, 14, 0.2) 0px 1px 0px, rgb(255, 255, 255) 0px 0px 0px 2px inset; white-space: nowrap; vertical-align: middle; background-position: initial initial; background-repeat: initial initial; }
.md-comment { color: rgb(162, 127, 3); opacity: 0.8; font-family: var(--monospace); }
code { text-align: left; }
a.md-print-anchor { white-space: pre !important; border: none !important; display: inline-block !important; position: absolute !important; width: 1px !important; right: 0px !important; outline: 0px !important; text-shadow: initial !important; background-position: 0px 0px !important; background-repeat: initial initial !important; }
.md-inline-math .MathJax_SVG .noError { display: none !important; }
.html-for-mac .inline-math-svg .MathJax_SVG { vertical-align: 0.2px; }
.md-math-block .MathJax_SVG_Display { text-align: center; margin: 0px; position: relative; text-indent: 0px; max-width: none; max-height: none; min-height: 0px; min-width: 100%; width: auto; overflow-y: hidden; display: block !important; }
.MathJax_SVG_Display, .md-inline-math .MathJax_SVG_Display { width: auto; margin: inherit; display: inline-block !important; }
.MathJax_SVG .MJX-monospace { font-family: var(--monospace); }
.MathJax_SVG .MJX-sans-serif { font-family: sans-serif; }
.MathJax_SVG { display: inline; font-style: normal; font-weight: 400; line-height: normal; zoom: 90%; text-indent: 0px; text-align: left; text-transform: none; letter-spacing: normal; word-spacing: normal; word-wrap: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border: 0px; padding: 0px; margin: 0px; }
.MathJax_SVG * { transition: none; }
.MathJax_SVG_Display svg { vertical-align: middle !important; margin-bottom: 0px !important; }
.os-windows.monocolor-emoji .md-emoji { font-family: "Segoe UI Symbol", sans-serif; }
.md-diagram-panel > svg { max-width: 100%; }
[lang="mermaid"] svg, [lang="flow"] svg { max-width: 100%; }
[lang="mermaid"] .node text { font-size: 1rem; }
table tr th { border-bottom-width: 0px; }
video { max-width: 100%; display: block; margin: 0px auto; }
iframe { max-width: 100%; width: 100%; border: none; }
.highlight td, .highlight tr { border: 0px; }

.CodeMirror { height: auto; }
.CodeMirror.cm-s-inner { background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; background-position: inherit inherit; background-repeat: inherit inherit; }
.CodeMirror-scroll { overflow-y: hidden; overflow-x: auto; z-index: 3; }
.CodeMirror-gutter-filler, .CodeMirror-scrollbar-filler { background-color: rgb(255, 255, 255); }
.CodeMirror-gutters { border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; white-space: nowrap; background-position: inherit inherit; background-repeat: inherit inherit; }
.CodeMirror-linenumber { padding: 0px 3px 0px 5px; text-align: right; color: rgb(153, 153, 153); }
.cm-s-inner .cm-keyword { color: rgb(119, 0, 136); }
.cm-s-inner .cm-atom, .cm-s-inner.cm-atom { color: rgb(34, 17, 153); }
.cm-s-inner .cm-number { color: rgb(17, 102, 68); }
.cm-s-inner .cm-def { color: rgb(0, 0, 255); }
.cm-s-inner .cm-variable { color: rgb(0, 0, 0); }
.cm-s-inner .cm-variable-2 { color: rgb(0, 85, 170); }
.cm-s-inner .cm-variable-3 { color: rgb(0, 136, 85); }
.cm-s-inner .cm-string { color: rgb(170, 17, 17); }
.cm-s-inner .cm-property { color: rgb(0, 0, 0); }
.cm-s-inner .cm-operator { color: rgb(152, 26, 26); }
.cm-s-inner .cm-comment, .cm-s-inner.cm-comment { color: rgb(170, 85, 0); }
.cm-s-inner .cm-string-2 { color: rgb(255, 85, 0); }
.cm-s-inner .cm-meta { color: rgb(85, 85, 85); }
.cm-s-inner .cm-qualifier { color: rgb(85, 85, 85); }
.cm-s-inner .cm-builtin { color: rgb(51, 0, 170); }
.cm-s-inner .cm-bracket { color: rgb(153, 153, 119); }
.cm-s-inner .cm-tag { color: rgb(17, 119, 0); }
.cm-s-inner .cm-attribute { color: rgb(0, 0, 204); }
.cm-s-inner .cm-header, .cm-s-inner.cm-header { color: rgb(0, 0, 255); }
.cm-s-inner .cm-quote, .cm-s-inner.cm-quote { color: rgb(0, 153, 0); }
.cm-s-inner .cm-hr, .cm-s-inner.cm-hr { color: rgb(153, 153, 153); }
.cm-s-inner .cm-link, .cm-s-inner.cm-link { color: rgb(0, 0, 204); }
.cm-negative { color: rgb(221, 68, 68); }
.cm-positive { color: rgb(34, 153, 34); }
.cm-header, .cm-strong { font-weight: 700; }
.cm-del { text-decoration: line-through; }
.cm-em { font-style: italic; }
.cm-link { text-decoration: underline; }
.cm-error { color: red; }
.cm-invalidchar { color: red; }
.cm-constant { color: rgb(38, 139, 210); }
.cm-defined { color: rgb(181, 137, 0); }
div.CodeMirror span.CodeMirror-matchingbracket { color: rgb(0, 255, 0); }
div.CodeMirror span.CodeMirror-nonmatchingbracket { color: rgb(255, 34, 34); }
.cm-s-inner .CodeMirror-activeline-background { background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; background-position: inherit inherit; background-repeat: inherit inherit; }
.CodeMirror { position: relative; overflow: hidden; }
.CodeMirror-scroll { height: 100%; outline: 0px; position: relative; box-sizing: content-box; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; background-position: inherit inherit; background-repeat: inherit inherit; }
.CodeMirror-sizer { position: relative; }
.CodeMirror-gutter-filler, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-vscrollbar { position: absolute; z-index: 6; display: none; }
.CodeMirror-vscrollbar { right: 0px; top: 0px; overflow: hidden; }
.CodeMirror-hscrollbar { bottom: 0px; left: 0px; overflow: hidden; }
.CodeMirror-scrollbar-filler { right: 0px; bottom: 0px; }
.CodeMirror-gutter-filler { left: 0px; bottom: 0px; }
.CodeMirror-gutters { position: absolute; left: 0px; top: 0px; padding-bottom: 30px; z-index: 3; }
.CodeMirror-gutter { white-space: normal; height: 100%; box-sizing: content-box; padding-bottom: 30px; margin-bottom: -32px; display: inline-block; }
.CodeMirror-gutter-wrapper { position: absolute; z-index: 4; border: none !important; background-position: 0px 0px !important; background-repeat: initial initial !important; }
.CodeMirror-gutter-background { position: absolute; top: 0px; bottom: 0px; z-index: 4; }
.CodeMirror-gutter-elt { position: absolute; cursor: default; z-index: 4; }
.CodeMirror-lines { cursor: text; }
.CodeMirror pre { border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; border-width: 0px; font-family: inherit; font-size: inherit; margin: 0px; white-space: pre; word-wrap: normal; color: inherit; z-index: 2; position: relative; overflow: visible; background-position: 0px 0px; background-repeat: initial initial; }
.CodeMirror-wrap pre { word-wrap: break-word; white-space: pre-wrap; word-break: normal; }
.CodeMirror-code pre { border-right-width: 30px; border-right-style: solid; border-right-color: transparent; width: fit-content; }
.CodeMirror-wrap .CodeMirror-code pre { border-right-style: none; width: auto; }
.CodeMirror-linebackground { position: absolute; left: 0px; right: 0px; top: 0px; bottom: 0px; z-index: 0; }
.CodeMirror-linewidget { position: relative; z-index: 2; overflow: auto; }
.CodeMirror-wrap .CodeMirror-scroll { overflow-x: hidden; }
.CodeMirror-measure { position: absolute; width: 100%; height: 0px; overflow: hidden; visibility: hidden; }
.CodeMirror-measure pre { position: static; }
.CodeMirror div.CodeMirror-cursor { position: absolute; visibility: hidden; border-right-style: none; width: 0px; }
.CodeMirror div.CodeMirror-cursor { visibility: hidden; }
.CodeMirror-focused div.CodeMirror-cursor { visibility: inherit; }
.cm-searching { background-color: rgba(255, 255, 0, 0.4); background-position: initial initial; background-repeat: initial initial; }
@media print {
.CodeMirror div.CodeMirror-cursor { visibility: hidden; }
}

@charset "utf-8";

:root {
--active-file-bg-color: #dadada;
--active-file-bg-color: rgba(32, 43, 51, 0.63);
--active-file-text-color: white;
--bg-color: #fff;
--text-color: #333;
--side-bar-bg-color: #f5f5f5;
--control-text-color: #666;
}

/* 防止用户自定义背景颜色对网页的影响,添加让用户可以自定义字体 */
html {
color: #333;
background: #fff;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
text-rendering: optimizelegibility;
font-size: 14px;
-webkit-font-smoothing: initial;
}

#write {
max-width: 960px;
padding-top: 2em;
padding-left: 60px;
padding-right: 60px;
min-height: calc(100vh - 6em);
-webkit-font-smoothing: antialiased;
font-size: 16px;
}

.typora-node #write {
min-height: calc(100% - 6em);
}

pre.md-meta-block {
background: #f5f5f5;
padding: 1em;
border-radius: 3px;
font-size: 14px;
}

@media screen and (max-width: 800px) {
html {
font-size: 14px;
}

#write {
padding-left: 30px;
padding-right: 30px;
font-size: 14px;
}
}

@media screen and (min-width: 1100px) {
body, #footer-word-count-info {
background: #f5f5f5;
}

body.pin-outline,
.pin-outline #footer-word-count-info,
.pin-outline footer {
background: #fff;
}

#write {
max-width: 1000px;
padding: 40px 60px;
background: #fff;
margin: 3em auto 3em;
border: 1px solid #ddd;
border-width: 0 1px;
}

.pin-outline #write {
max-width: 1000px;
background: #fff;
margin: 0 0 0;
border: 0;
padding-left: 60px;
padding-right: 60px;
}

footer {
background-color: transparent;
}
}

@media screen and (min-width: 1300px) {
body.pin-outline,
.pin-outline #footer-word-count-info,
.pin-outline footer {
background: #f5f5f5;
}

.pin-outline #write {
max-width: 1000px;
padding: 40px 60px;
background: #fff;
margin: 3em auto 3em;
border: 1px solid #ddd;
border-width: 0 1px;
}

.pin-outline footer {
background-color: transparent;
}

#footer-word-count-info {
background: #f5f5f5;
}
}

/* 如果你的项目仅支持 IE9+ | Chrome | Firefox 等,推荐在 中添加 .borderbox 这个 class */
html.borderbox *, html.borderbox *:before, html.borderbox *:after {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}

/* 内外边距通常让各个浏览器样式的表现位置不同 */
body, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, code, form, fieldset, legend, input, textarea, p, blockquote, th, td, hr, button, article, aside, details, figcaption, figure, footer, header, menu, nav, section {
margin: 0;
padding: 0;
}

/* 重设 HTML5 标签, IE 需要在 js 中 createElement(TAG) */
article, aside, details, figcaption, figure, footer, header, menu, nav, section {
display: block;
}

/* HTML5 媒体文件跟 img 保持一致 */
audio, canvas, video {
display: inline-block;
}

/* 要注意表单元素并不继承父级 font 的问题 */
body, button, input, select, textarea {
font: 300 1em/1.8 "PingFang SC", "Lantinghei SC", "Microsoft Yahei", "Hiragino Sans GB", "Microsoft Sans Serif", "WenQuanYi Micro Hei", sans;
}

body {
font-family: "PingFang SC", "Lantinghei SC", "Microsoft Yahei", "Hiragino Sans GB", "Microsoft Sans Serif", "WenQuanYi Micro Hei", sans;
}

h1, h2, h3, h4, h5, h6 {
font-family: "TimesNewRomanPS-ItalicMT", "PingFang SC", "Lantinghei SC", "Microsoft Yahei", "Hiragino Sans GB", "Microsoft Sans Serif", "WenQuanYi Micro Hei", sans;
/*font-family: "PingFang SC", "Lantinghei SC", "Microsoft Yahei", "Hiragino Sans GB", "Microsoft Sans Serif", "WenQuanYi Micro Hei", sans;*/
-webkit-font-smoothing: initial;
font-weight: 100;
color: var(--text-color);
line-height: 1.35;
font-variant-numeric: lining-nums;
margin-bottom: 1em;
}

em {
font-family: Georgia-Italic, STSongti-SC-Light, serif;
}

strong em,
em strong {
font-family: Georgia-BoldItalic, STSongti-SC-Regular, serif;
}

button::-moz-focus-inner,
input::-moz-focus-inner {
padding: 0;
border: 0;
}

/* 去掉各Table cell 的边距并让其边重合 */
table {
border-collapse: collapse;
border-spacing: 0;
}

/* 去除默认边框 */
fieldset, img {
border: 0;
}

/* 块/段落引用 */
blockquote {
position: relative;
color: #999;
font-weight: 400;
border-left: 1px solid #1abc9c;
padding-left: 1em;
margin: 1em 3em 1em 2em;
}

@media only screen and ( max-width: 640px ) {
blockquote {
margin: 1em 0;
}
}

/* Firefox 以外,元素没有下划线,需添加 */
acronym, abbr {
border-bottom: 1px dotted;
font-variant: normal;
}

/* 添加鼠标问号,进一步确保应用的语义是正确的(要知道,交互他们也有洁癖,如果你不去掉,那得多花点口舌) */
abbr {
cursor: help;
}

address, caption, cite, code, dfn, th, var {
font-style: normal;
font-weight: 400;
}

/* 去掉列表前的标识, li 会继承,大部分网站通常用列表来很多内容,所以应该当去 */
ul, ol {
list-style: none;
}

/* 对齐是排版最重要的因素, 别让什么都居中 */
caption, th {
text-align: left;
}

q:before, q:after {
content: '';
}

/* 统一上标和下标 */
sub, sup {
font-size: 75%;
line-height: 0;
position: relative;
}

:root sub, :root sup {
vertical-align: baseline; /* for ie9 and other modern browsers */
}

sup {
top: -0.5em;
}

sub {
bottom: -0.25em;
}

/* 让链接在 hover 状态下显示下划线 */
a {
color: #1abc9c;
}

a:hover {
text-decoration: underline;
}

#write a {
border-bottom: 1px solid #1abc9c;
}

#write a:hover {
border-bottom-color: #555;
color: #555;
text-decoration: none;
}

/* 默认不显示下划线,保持页面简洁 */
ins, a {
text-decoration: none;
}

/* 标记,类似于手写的荧光笔的作用 */
mark {
background: #fffdd1;
border-bottom: 1px solid #ffedce;
padding: 2px;
margin: 0 5px;
}

/* 代码片断 */
pre, code, pre tt {
font-family: Courier, 'Courier New', monospace;
}

#write .md-fences {
border: 1px solid #ddd;
padding: 1em 0.5em;
display: block;
-webkit-overflow-scrolling: touch;
}

/* 一致化 horizontal rule */
hr {
border: none;
border-bottom: 1px solid #cfcfcf;
margin-bottom: 0.8em;
height: 10px;
}

#write strong {
font-weight: bolder;
color: #000;
}

.code-tooltip.md-hover-tip strong {
color: white;
}

/* 保证块/段落之间的空白隔行 */
#write p, #write .md-fences, #write ul, #write ol, #write dl, #write form, #write hr, #write figure,
#write-p, #write-pre, #write-ul, #write-ol, #write-dl, #write-form, #write-hr, #write-table, blockquote {
margin-bottom: 1.2em
}

html {
font-family: PingFang SC, Verdana, Helvetica Neue, Microsoft Yahei, Hiragino Sans GB, Microsoft Sans Serif, WenQuanYi Micro Hei, sans-serif;
}

/* 标题应该更贴紧内容,并与其他块区分,margin 值要相应做优化 */
#write h1, #write h2, #write h3, #write h4, #write h5, #write h6,
#write-h1, #write-h2, #write-h3, #write-h4, #write-h5, #write-h6 {
margin-top: 1.2em;
margin-bottom: 0.6em;
line-height: 1.35;
color: #000;
}

#write h1, #write-h1 {
font-size: 2.4em;
padding-bottom: 1em;
border-bottom: 3px double #eee;
}

#write h2, #write-h2 {
font-size: 1.8em;
}

#write h3, #write-h3 {
font-size: 1.6em;
}

#write h4, #write-h4 {
font-size: 1.4em;
}

#write h5, #write h6, #write-h5, #write-h6 {
font-size: 1.2em;
}

/* 在文章中,应该还原 ul 和 ol 的样式 */
#write ul, #write-ul {
margin-left: 1.3em;
list-style: disc;
}

#write ol, #write-ol {
list-style: decimal;
margin-left: 1.9em;
}

#write li ul, #write li ol, #write-ul ul, #write-ul ol, #write-ol ul, #write-ol ol {
margin-bottom: 0.8em;
margin-left: 2em;
}

#write li ul, #write-ul ul, #write-ol ul {
list-style: circle;
}

#write table th, #write table td {
border: 1px solid #ddd;
padding: 0.5em 1em;
color: #666;
}

#write table .md-table-edit th {
border: none;
padding: 0;
color: inherit;
}

#write table th, #write-table th {
background: #fbfbfb;
}

#write table thead th, #write-table thead th {
background: #f1f1f1;
}

#write table caption {
border-bottom: none;
}

#write em {
font-weight: inherit;
font-style: inherit;
}

li>p {
margin-bottom: 0 !important;
}

/* Responsive images */
#write img {
max-width: 100%;
}

a.md-toc-inner {
border-bottom: 0 !important;
}

.md-toc-h1:first-of-type:last-of-type{
display: none;
}

.md-toc {
font-size: inherit;
}

.md-toc-h1 .md-toc-inner {
font-weight: normal;
}

.md-table-edit th {
padding: 0 !important;
border: 0 !important;
}

.mac-seamless-mode #write {
min-height: calc(100vh - 6em - 20px);
}

.typora-quick-open-item.active {
color: var(--active-file-text-color);
}

*.in-text-selection, ::selection {
background: var(--active-file-bg-color);
text-shadow: none;
color: white;
}

.btn-primary {
background-color: #2d2d2d;
border-color: #020202;
}

.btn-primary:hover, .btn-primary:focus, .btn-primary.focus, .btn-primary:active, .btn-primary.active, .open > .dropdown-toggle.btn-primary {
background-color: #4e4c4e;
border: #4e4c4e;
}

#preference-dialog .modal-content{
background: #6e757a;
--bg-color: #6e757a;
--text-color: #f1f1f1;
color: #f1f1f1;
}

#typora-source,
.typora-sourceview-on {
--bg-color: #eee;
background: #eee;
}

.cm-s-typora-default .cm-header, .cm-s-typora-default .cm-property {
color: #116098;
}

.cm-s-typora-default .cm-link {
color: #11987d;
}

.cm-s-typora-default .cm-em {
font-family: Georgia-Italic, STSongti-SC-Light, serif;
color: #6f6400;
}

.cm-s-typora-default .cm-em{
color: rgb(0, 22, 45);
}

.CodeMirror.cm-s-typora-default div.CodeMirror-cursor{
border-left: 3px solid #6e757a;
}

.cm-s-typora-default .CodeMirror-selectedtext,
.typora-sourceview-on .CodeMirror-focused .CodeMirror-selected {
background: #6e757a;
color: white;
}

.file-node-icon.fa.fa-folder:before {
color: rgba(32, 43, 51, 0.49);
}

#preference-dialog .megamenu-menu-panel h1 {
margin-bottom: 1em;
}

::-webkit-scrollbar-corner {
display: none;
background: transparent;
}

/*.file-node-icon.fa.fa-folder:before {
content: "\f114";
}

#typora-sidebar {

}*/

/*.cm-s-typora-default .cm-header, .cm-s-typora-default .cm-property {
color: #fffff1;
}

.cm-s-typora-default .cm-link {
color: #86f9e2;
color: #e5f7eb;
}

.cm-s-typora-default .cm-comment, .cm-s-typora-default .cm-code {
color: rgb(255, 199, 199);
}

.cm-s-typora-default .cm-atom, .cm-s-typora-default .cm-number {
color: #dec4c7;
}

.cm-s-typora-default .cm-em {
font-family: Georgia-Italic, STSongti-SC-Light, serif;
color: #f3ff7e;
}

.typora-sourceview-on .CodeMirror-cursor {
border-left: 3px solid #ffffd6;
}

.typora-sourceview-on #toggle-sourceview-btn {
background: #505050;
}

.typora-sourceview-on .cm-s-inner .cm-variable,
.typora-sourceview-on .cm-s-inner .cm-operator,
.typora-sourceview-on .cm-s-inner .cm-property {
color: #b8bfc6;
}

.typora-sourceview-on .cm-s-inner .cm-keyword {
color: #C88FD0;
}

.typora-sourceview-on .cm-s-inner .cm-tag {
color: #7DF46A;
}

.typora-sourceview-on .cm-s-inner .cm-attribute {
color: #7575E4;
}

.typora-sourceview-on .cm-s-inner .cm-string {
color: #D26B6B;
}

.typora-sourceview-on .cm-s-inner .cm-comment,
.typora-sourceview-on .cm-s-inner.cm-comment {
color: #DA924A;
}

.typora-sourceview-on .cm-s-inner .cm-header,
.typora-sourceview-on .cm-s-inner .cm-def,
.typora-sourceview-on .cm-s-inner.cm-header,
.typora-sourceview-on .cm-s-inner.cm-def {
color: #8d8df0;
}

.typora-sourceview-on .cm-s-inner .cm-quote,
.typora-sourceview-on .cm-s-inner.cm-quote {
color: #57ac57;
}

.typora-sourceview-on .cm-s-inner .cm-hr {
color: #d8d5d5;
}

.typora-sourceview-on .cm-s-inner .cm-link {
color: #d3d3ef;
}

.typora-sourceview-on .cm-s-inner .cm-negative {
color: #d95050;
}

.typora-sourceview-on .cm-s-inner .cm-positive {
color: #50e650;
}

.typora-sourceview-on .cm-s-inner .cm-string-2 {
color: #f50;
}

.typora-sourceview-on .cm-s-inner .cm-meta,
.typora-sourceview-on .cm-s-inner .cm-qualifier {
color: #b7b3b3;
}

.typora-sourceview-on .cm-s-inner .cm-builtin {
color: #f3b3f8;
}

.typora-sourceview-on .cm-s-inner .cm-bracket {
color: #997;
}

.typora-sourceview-on .cm-s-inner .cm-atom,
.typora-sourceview-on .cm-s-inner.cm-atom {
color: #84B6CB;
}

.typora-sourceview-on .cm-s-inner .cm-number {
color: #64AB8F;
}

.typora-sourceview-on .cm-s-inner .cm-variable {
color: #b8bfc6;
}

.typora-sourceview-on .cm-s-inner .cm-variable-2 {
color: #9FBAD5;
}

.typora-sourceview-on .cm-s-inner .cm-variable-3 {
color: #1cc685;
}

.typora-sourceview-on .CodeMirror div.CodeMirror-cursor {
border-left: 1px solid #b8bfc6;
z-index: 3;
}

.cm-s-typora-default .CodeMirror-selectedtext,
.typora-sourceview-on .CodeMirror-focused .CodeMirror-selected {
background: #212324;
}

.typora-sourceview-on .CodeMirror-linenumber {
color: rgb(255, 255, 255);
}*/

.typora-export li, .typora-export p, .typora-export, .footnote-line {white-space: normal;}
-->

1. 需求是这样的

一台机器上有两种不同类型的日志数据,且是按天存储的。目录结构是这样的:

 
 
 
 
 
 
 
 
--/data/log
  --/access_log
    --190101.txt
    --190102.txt
    ...
  --/click_log
    --190101.txt
    --190102.txt
    ... 
 
 

access_log每行是一个JSON字符串,长得像这样:

 
 
 
xxxxxxxxxx
 
 
 
 
{
    "url": "index", 
    "server": {
        ...
    }, 
    "timestamp": 1551369609, 
    "ip": "188.138.188.34", 
    "session_id": "l9tooea23s6mjlid1q01svmc80", 
    "method": "GET", 
    "request_id": "a7ce6bc3e6c39e65eb5d11c979956acf"
}
 
 

click_log每行也是一个JSON字符串,长得像这样:

 
 
 
xxxxxxxxxx
 
 
 
 
{
    "click_id": "474b927e12731128579b8100f4f8918b", 
    "click_obj": [
        ...
    ], 
    "data": {
        ...
    }
}
 
 

需求比较简单,提供一个可查功能就可以了:

  • 针对access_log,需要解析其中timestamp,方便按时间筛选日志;
  • access_log和click_log都需要解析JSON;

2. 调研与实施

在百度一搜,就是ELK,社区又比较火,索性就直接上吧。

2.1 搭建ES集群

比较简单,照着官网来即可,不想英文的,就百度吧,前人已经出了很多案例了。列几个比较好的参考吧: http://jiangew.me/es-deploy-proxy/ https://www.cnblogs.com/leeSmall/p/9189078.html https://www.cnblogs.com/leeSmall/p/9220535.html 我搭建的集群是6节点的,配置如下:

 
 
 
xxxxxxxxxx
 
 
 
 
cluster.name: myname
node.name: 192-168-0-106
node.master: false
node.data: false
path.data: /data/es/data
path.logs: /data/es/log
network.host: 192.168.0.106
http.port: 9200
discovery.zen.ping.unicast.hosts: ["192.168.0.106", "192.168.0.107", "192.168.0.108", "192.168.0.109", "192.168.0.110", "192.168.0.111"]
discovery.zen.minimum_master_nodes: 3
 
 
2.2 搭建kibana

直接用192.168.0.106那个节点,下包、解压、改配置,配置如下:

 
 
 
xxxxxxxxxx
 
 
 
 
server.host: "192.168.0.106"
elasticsearch.hosts: ["http://192.168.0.106:9200"]
 
 
2.3 搭建FileBeat

网上说logstash较重,FileBeat比较轻量,想想,我的需求这么简单就从了。 轻量是轻量,但搭建过程,对于新手来说,还是不容易,中间遇到了很多问题,弯路就不提了,只提两个重要的。

2.3.1 如何解析JSON

参考官网这一页:https://www.elastic.co/guide/en/beats/filebeat/6.6/filebeat-input-log.html 就这两行代码:

 
 
 
xxxxxxxxxx
 
 
 
 
filebeat.inputs:
- type: log
  paths:
    - /data/log/access_log/*   -- 日志路径
  json.keys_under_root: true   -- 把JSON中key移到根上(日志JSON只是beat上传数据的一项)
  json.add_error_key: true     -- 解析失败,把错误放出来
 
 
2.3.2 ES 的mapping设置与输出设置
 
 
 
xxxxxxxxxx
 
 
 
 
setup.template.fields: "access_fields.yml"
setup.template.pattern: "access*"
setup.template.name: "access"
output.elasticsearch:
  hosts: ["192.168.0.106:9200"]
  index: "access_%{[dissect.key4]}"
  pipeline: "log_pipeline"
processors:
  - add_host_metadata: ~
  - add_cloud_metadata: ~
  - dissect:
      tokenizer: "%{key1}/%{key2}/%{key3}/%{key4}"
      field: "source"
      target_prefix: "dissect"
 
 

A. 没有用默认的fields.yml,在里面加了一个log_time,且要定义成date类型,需要从数据中的timestamp解析出来,用的pipeline。在kibana上的dev tools功能中console,贴入这段代码,并执行。

 
 
 
xxxxxxxxxx
 
 
 
 
PUT _ingest/pipeline/log_pipeline
{
    "description": "log processor", 
    "processors": [
        {
            "date": {
                "field": "timestamp", 
                "target_field" : "log_time",
                "formats": [
                    "UNIX"
                ], 
                "timezone":"Asia/Shanghai",
                "on_failure": [
                    {
                        "set": {
                            "field": "date_processor_error", 
                            "value": "{{ _ingest.on_failure_message }}"
                        }
                    }
                ]
            }
        }
    ]
}
 
 

B. 由于每天的数据要单独建索引,而且只能从文件名中提取年月日,所以用了dissect processor。

2.3.2 一个filebeat发一类索引,还是发多类索引

我用的后者,不知道会不会有什么问题,从运行来看,没出什么错。

3. 总结

不得不说,ES的文档写得真详细,搭个demo非常快,但要用好,还是有很多值得探索的地方,抽空再研究一下吧。

一个ELK日志检索实施案例的更多相关文章

  1. ELK日志检索并邮件微信通知

    简介 脚本为通过api检索日志内容,并通过邮件或者微信发送出来. 脚本 index检索脚本 #!/usr/bin/env python # coding:utf-8 from elasticsearc ...

  2. ELK日志监控平台安装部署简介--Elasticsearch安装部署

    最近由于工作需要,需要搭建一个ELK日志监控平台,本次采用Filebeat(采集数据)+Elasticsearch(建立索引)+Kibana(展示)架构,实现日志搜索展示功能. 一.安装环境描述: 1 ...

  3. 创业公司做数据分析(四)ELK日志系统 (转)

    http://blog.csdn.net/zwgdft/article/details/53842574 作为系列文章的第四篇,本文将重点探讨数据采集层中的ELK日志系统.日志,指的是后台服务中产生的 ...

  4. ELK日志分析 学习笔记

    (贴一篇之前工作期间整理的elk学习笔记) ELK官网 https://www.elastic.co   ELK日志分析系统 学习笔记 概念:ELK = elasticsearch + logstas ...

  5. 创业公司做数据分析(四)ELK日志系统

      作为系列文章的第四篇.本文将重点探讨数据採集层中的ELK日志系统.日志.指的是后台服务中产生的log信息,一般会输入到不同的文件里.比方Django服务下,一般会有nginx日志和uWSGI日志. ...

  6. TKE 用户故事 - 作业帮 PB 级低成本日志检索服务

    作者 吕亚霖,2019年加入作业帮,作业帮架构研发负责人,在作业帮期间主导了云原生架构演进.推动实施容器化改造.服务治理.GO微服务框架.DevOps的落地实践. 莫仁鹏,2020年加入作业帮,作业帮 ...

  7. ELK 日志分析系统概述及部署

    ELK 日志分析系统概述及部署 1.ELK概述: ELK简介 : ELK平台是一套完整的日志集中处理解决方案,将 ElasticSearch.Logstash 和 Kiabana 三个开源工具配合使用 ...

  8. ELK日志分析系统搭建(转)

    摘要: 前段时间研究的Log4j+Kafka中,有人建议把Kafka收集到的日志存放于ES(ElasticSearch,一款基于Apache Lucene的开源分布式搜索引擎)中便于查找和分析,在研究 ...

  9. ELK 日志分析体系

    ELK   日志分析体系 ELK 是指 Elasticsearch.Logstash.Kibana三个开源软件的组合. logstash                       负责日志的收集,处 ...

随机推荐

  1. vue组件-构成组件-父子组件相互传递数据

    组件对于vue来说非常重要,学习学习了基础vue后,再回过头来把组件弄透! 一.概念 组件意味着协同工作,通常父子组件会是这样的关系:组件 A 在它的模版中使用了组件 B . 它们之间必然需要相互通信 ...

  2. ASP.NET Core 快速入门(实战篇)

    上篇讲了<asp.net core在linux上的环境部署>.今天我们将做几个小玩意实战一下.用到的技术和工具有mysql.websocket.AngleSharp(爬虫html解析).n ...

  3. MYSQL如何计算两个日期间隔天数

    如何透过MYSQL自带函数计算给定的两个日期的间隔天数   有两个途径可获得   1.利用TO_DAYS函数   select to_days(now()) - to_days('20120512') ...

  4. 聊聊Mysql索引和redis跳表

    摘要 面试时,交流有关mysql索引问题时,发现有些人能够涛涛不绝的说出B+树和B树,平衡二叉树的区别,却说不出B+树和hash索引的区别.这种一看就知道是死记硬背,没有理解索引的本质.本文旨在剖析这 ...

  5. C# 《编写高质量代码改善建议》整理&笔记 --(五)类型设计

    1.区分接口和抽象类的应用场合 区别: ①接口支持多继承,抽象类则不能. ②接口可以包含方法,属性,索引器,事件的签名,但不能有实现,抽象类则可以. ③接口在增加新方法后,所有的继承者都必须重构,否则 ...

  6. Python:tesserocr 在 windows 下的安装及简单使用

    tesserocr 是 python 的一个 OCR 库,它是对 tesseract 做的一层 Python API 封装,所以他的核心是tesseract. tesseract 的安装见 https ...

  7. Windows Server 2012 R2安装SqlServer 2016

    1.系统安装 微软操作系统 Windows Server 2012 R2 官方原版镜像 Windows Server 2012 R2 是由微软公司(Microsoft)设计开发的新一代的服务器专属操作 ...

  8. Powershell:关于PSCustomObject你想知道的一切(译)

    PSCustomObject是Powershell里非常重要的一个工具,我们先从基础开始然后再循序渐进讲到一些更高级的话题.PSCustomObject旨在于用简单的方法来创建结构化数据.下面的第一个 ...

  9. Python3+Selenium2完整的自动化测试实现之旅(一):自动化测试环境搭建

    1     环境搭建准备 (1)    下载Python3版本的安装包,直接官网下载即可:Python官网:https://www.python.org/ (2)    下载Python的基础工具包p ...

  10. [转]Have a query in Blue prism coding stage and collection stage.

    本文转自:https://www.rpaforum.net/threads/have-a-query-in-blueprism-coding-stage-and-collection-stage.48 ...