亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SpringBoot?Loki安裝簡(jiǎn)介及實(shí)戰(zhàn)思路

 更新時(shí)間:2022年11月03日 14:59:27   作者:怒放吧德德  
這篇文章主要為大家介紹了SpringBoot?Loki安裝簡(jiǎn)介及實(shí)戰(zhàn)思路詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪的相關(guān)資料

前言

因?yàn)榫W(wǎng)上好多都沒有通過Loki的API自己實(shí)現(xiàn)對(duì)日志監(jiān)控系統(tǒng),所以我就下定決心自己出一版關(guān)于loki與springboot的博文供大家參考,這個(gè)可以說是比較實(shí)用,很適合中小型企業(yè)。因此我醞釀了挺久了,對(duì)于loki的研究也比較久,希望各位讀者能有新的收獲。

簡(jiǎn)介

Loki是Grafana Labs團(tuán)隊(duì)的開源項(xiàng)目,可以組成一個(gè)功能齊全的日志堆棧。Loki是一個(gè)水平可擴(kuò)展,高可用性,多租戶的日志聚合系統(tǒng)。它的設(shè)計(jì)非常經(jīng)濟(jì)高效且易于操作,因?yàn)樗粫?huì)為日志內(nèi)容編制索引,而是為每個(gè)日志流編制一組標(biāo)簽。Loki是用來存儲(chǔ)日志和處理查詢,需要通過promtail來收集日志,也可是通過后端的logback等日志框架來收集日志,通過grafana提供的loki可視化查看日志,當(dāng)然了loki也提供了API,可以根據(jù)自己的需求來自己實(shí)現(xiàn)可視化界面,能夠減少三方插件的使用。

安裝

上一篇文章已經(jīng)介紹了如何安裝以及使用Grafana+loki+promtail進(jìn)行搭建日志系統(tǒng),http://chabaoo.cn/article/248318.htm可以看看這篇文章。接下來筆者要介紹的是通過Loki的API編寫自己可視化界面,并且通過logback來實(shí)現(xiàn)收集日志。 大致的結(jié)構(gòu)如圖

簡(jiǎn)單介紹一下,主要就是通過springboot后端的logback日志框架來收集日志,在推送到loki中存儲(chǔ),loki執(zhí)行對(duì)日志的查詢,通過API根據(jù)標(biāo)簽等信息去查詢?nèi)罩静⑶以谧远x的前端界面中展示。

整體思路

其實(shí)宏觀來看,要達(dá)成這個(gè)需求說起來是十分簡(jiǎn)單的,只需配置logback配置,在通過MDC寫入、收集日志,這里可以好多的寫法,可以是通過反射寫入日志,也可以是在需要打印的地方寫入日志,并且是將日志區(qū)分為不同的標(biāo)簽。在前端就可以根據(jù)所定義的標(biāo)簽來查看相應(yīng)的日志。前端獲取日志信息邏輯也很簡(jiǎn)單,就只是通過Loki提供的API獲取每行的日志。接下來我就一一詳細(xì)的介紹SpringBoot與Loki的那些事。 可以查看此圖便于理解:

Loki實(shí)戰(zhàn)開發(fā)

接下來就詳細(xì)講解筆者在實(shí)戰(zhàn)開發(fā)中是如何編寫的,本次介紹只是對(duì)編寫的代碼進(jìn)行詳講,對(duì)于代碼可能不會(huì)全部粘貼,不然冗余起來效果不好,各位讀者可以各自發(fā)揮,更加完善。其實(shí)整個(gè)業(yè)務(wù)也不難,基本都是loki自身提供的API,讀者可以通過Loki官方網(wǎng)站grafana.com/docs/loki/l… 去進(jìn)一步對(duì)Loki的API進(jìn)行查閱,后面筆者可能也會(huì)出一篇來專門對(duì)Loki的API以及配置進(jìn)行介紹。好了,廢話不多說,馬上進(jìn)入正題。

springboot中的配置

首先需要配置向Loki推送日志,也就是需要通過Loki的API:POST /loki/api/v1/push ,可以直接將地址通過appender寫死在logback日志框架中,但是在項(xiàng)目開發(fā)中,要考慮到環(huán)境的不同,應(yīng)該是能夠根據(jù)需要來修改loki服務(wù)器的地址,因此將loki的服務(wù)器地址配置在application-dev.yml中。

loki:
  url: http://localhost:3100/loki/api/v1

配置logback日志框架

先獲取yml配置的地址,通過appender添加到日志框架中,當(dāng)然,配置客戶端也不一定是LogBack框架,還有Log4j2框架也是能夠使用的,具體配置可以看官網(wǎng)github.com/loki4j/loki…github.com/tkowalcz/tj… ,本章只對(duì)loki進(jìn)行講解,對(duì)于日志框架,后期也會(huì)一一列出,各位讀者有什么不了解的,可以先到網(wǎng)上查閱資料。因?yàn)楣P者不是部署多臺(tái)Loki服務(wù)器,不同的系統(tǒng)采用system這個(gè)標(biāo)簽來進(jìn)行區(qū)分。

<springProperty scope="context" name="lokiUrl" source="loki.url"/>
<property name="LOKI_URL" value="${lokiUrl}"/>
<!--添加loki-->
<appender name="lokiAppender" class="com.github.loki4j.logback.Loki4jAppender">
    <batchTimeoutMs>1000</batchTimeoutMs>
    <http class="com.github.loki4j.logback.ApacheHttpSender">
        <url>${LOKI_URL}/push</url>
    </http>
    <format>
        <label>
            <pattern>system=${SYSTEM_NAME},level=%level,logType=%X{log_file_type:-logType}</pattern>
        </label>
        <message>
            <pattern>${log.pattern}</pattern>
        </message>
        <sortByTime>true</sortByTime>
    </format>
</appender>

注解與切面寫入日志

自定義注解,并且設(shè)置日志標(biāo)簽值。

/**
 * @author: lyd
 * @description: 自定義日志注解,用作LOKI日志分類
 * @Date: 2022/10/10
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD})
@Documented
public @interface LokiLog {
    LokiLogType type() default LokiLogType.DEFAULT;
}

通過枚舉的方式來定義日志類型的標(biāo)簽值

/**
 * @author: lyd
 * @description: 枚舉便簽值 - 類型自己定義
 * @Date: 2022/10/11
 */
public enum LokiLogType {
    DEFAULT("默認(rèn)"),
    A("A"),
    B("B"),
    C("C");
    private String desc;
    LokiLogType(String desc) {
     this.desc=desc;
    }
    public String getDesc() {
        return desc;
    }
}

編寫切面,寫入日志(詳情可以參照這篇文章http://chabaoo.cn/article/230135.htm,內(nèi)部通過MDC.put("log_file_type", logType.getDesc());(MDC ( Mapped Diagnostic Contexts ),它是一個(gè)線程安全的存放診斷日志的容器。可以參照 http://chabaoo.cn/article/232986.htm可以理解為log_file_type是標(biāo)簽名,logType.getDesc()是標(biāo)簽值。

/**
 * @author: lyd
 * @description: 自定義日志切面:https://cloud.tencent.com/developer/article/1655923
 * @Date: 2022/10/10
 */
@Aspect
@Slf4j
@Component
public class LokiLogAspect {
    /**
     * 切到所有OperatorLog注解修飾的方法
     */
    @Pointcut("@annotation(org.nl.wms.log.LokiLog)")
    public void operatorLog() {
        // 空方法
    }
    /**
     * 利用@Around環(huán)繞增強(qiáng)
     *
     * @return
     */
    @Around("operatorLog()")
    public synchronized Object around(ProceedingJoinPoint pjp) throws Throwable {
//        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//        HttpServletRequest request = attributes.getRequest();
//        HttpServletResponse response = attributes.getResponse();
        Signature signature = pjp.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        LokiLog lokiLog = method.getAnnotation(LokiLog.class);
        // 獲取描述信息
        LokiLogType logType = lokiLog.type();
        MDC.put("log_file_type", logType.getDesc());
        log.info("輸入?yún)?shù):" + JSONObject.toJSONString(pjp.getArgs()));
        Object proceed = pjp.proceed();
        log.info("返回參數(shù):" + JSONObject.toJSONString(proceed));
        MDC.remove("log_file_type");
        return proceed;
    }
}

使用注解,在方法中引用注解即可

@LokiLog(type = LokiLogType.A)

前端界面與后端接口

前端界面介紹起來可能比較麻煩,畢竟寫的代碼也比較多,這里就選取講解,代碼量比較多,也不會(huì)是全部代碼粘貼,樣式之類的,我相信讀者會(huì)根據(jù)自己的需求去實(shí)現(xiàn),這里主要的是記錄開發(fā)的思路。

日志的初步獲取

前端的界面就如圖,本次是以el-admin這個(gè)為基礎(chǔ)制作的demo。

查找日志是需要通過標(biāo)簽與標(biāo)簽值來獲取日志信息,因此首先需要的是攜帶標(biāo)簽對(duì)到后端訪問Loki的API拿到數(shù)據(jù),讀者可以查閱官網(wǎng)的API,結(jié)合著學(xué)習(xí)。

一開始當(dāng)vue視圖渲染的時(shí)候,就會(huì)從后端獲取loki日志標(biāo)簽,具體后端接口的業(yè)務(wù)代碼如下:

/**
 * 獲取labels和values樹
 *
 * @return
 */
@Override
public JSONArray getLabelsValues() {
    JSONArray result = new JSONArray();
    // 獲取所有標(biāo)簽
    String labelString = HttpUtil.get(lokiUrl + "/labels", CharsetUtil.CHARSET_UTF_8);
    JSONObject parse = (JSONObject) JSONObject.parse(labelString);
    JSONArray labels = parse.getJSONArray("data");
    for (int i=0; i<labels.size(); i++) {
        // 獲取標(biāo)簽下的所有值
        String valueString = HttpUtil.get(lokiUrl + "/label/" + labels.getString(i) + "/values", CharsetUtil.CHARSET_UTF_8);
        JSONObject parse2 = (JSONObject) JSONObject.parse(valueString);
        JSONArray values = parse2.getJSONArray("data");
        JSONArray children = new JSONArray();
        // 組成樹形狀態(tài) 兩級(jí)
        for (int j=0; j<values.size(); j++) {
            JSONObject leaf = new JSONObject();
            leaf.put("label", values.getString(j));
            leaf.put("value", values.getString(j));
            children.add(leaf);
        }
        JSONObject node = new JSONObject();
        node.put("label", labels.getString(i));
        node.put("value", labels.getString(i));
        node.put("children", children);
        result.add(node);
    }
    return result;
}

核心代碼就只有通過Hutool工具包去訪問API獲取標(biāo)簽HttpUtil.get(lokiUrl + "/labels", CharsetUtil.CHARSET_UTF_8); 以及 獲取標(biāo)簽值HttpUtil.get(lokiUrl + "/label/" + labels.getString(i) + "/values", CharsetUtil.CHARSET_UTF_8); 因?yàn)槲业那岸耸怯胑lment-ui的樹來接收的,因此我就將返回的數(shù)據(jù)設(shè)計(jì)成相應(yīng)的形式。

<el-form-item label="日志標(biāo)簽">
  <el-cascader
    v-model="labelAndValue"
    :options="labelsOptions"
    placeholder="請(qǐng)選擇標(biāo)簽"
    @change="queryData"
  />
</el-form-item>

模糊查找與更多參數(shù)

loki提供了相應(yīng)的API來進(jìn)行模糊查找日志,無非就是通過loki的API攜帶關(guān)鍵字進(jìn)行模糊查找日志,筆者的做法是獲取含有關(guān)鍵字的日志內(nèi)容。

"/query_range?query={system=\"" + systemName + "\", " + logLabel + "=\"" + logLabelValue + "\"} |= `" + text + "`"

并且還能夠通過時(shí)間段來查詢,筆者實(shí)現(xiàn)了的效果如圖

不僅可以通過關(guān)鍵字,還有時(shí)間段時(shí)間范圍以及查找的方向和一次性顯示的條數(shù),最好是建議不要超過1000條數(shù)據(jù),滾動(dòng)步數(shù)是實(shí)現(xiàn)滾動(dòng)下拉的時(shí)候獲取新的日志數(shù)據(jù)的條目數(shù)。 后端代碼如下,簡(jiǎn)單介紹一下,就是提供所需要的查詢條件來對(duì)日志進(jìn)行篩選。不管是獲取日志數(shù)據(jù)還是滾動(dòng)下拉獲取的日志數(shù)據(jù)都可以通用這個(gè)接口,然而主要的參數(shù)設(shè)置可以在前端進(jìn)行打磨,以下代碼還有優(yōu)化的空間,畢竟當(dāng)時(shí)剛開始寫的時(shí)候沒考慮這么多。

@Override
    public JSONObject getLogData(JSONObject json) {
        String logLabel = "";
        String logLabelValue = "";
        Long start = 0L;
        Long end = 0L;
        String text = "";
        String limit = "100";
        String direction = "backward";
        if (json.get("logLabel") != null) logLabel = json.getString("logLabel");
        if (json.get("logLabelValue") != null) logLabelValue = json.getString("logLabelValue");
        if (json.get("text") != null) text = json.getString("text");
        if (json.get("start") != null) start = json.getLong("start");
        if (json.get("end") != null) end = json.getLong("end");
        if (json.get("limits") != null) limit = json.getString("limits");
        if (json.get("direction") != null) direction = json.getString("direction");
        /**
         * 組織參數(shù)
         * 納秒數(shù)
         * 1660037391880000000
         * 1641453208415000000
         * http://localhost:3100/loki/api/v1/query_range?query={host="localhost"} |= ``&limit=1500&start=1641453208415000000&end=1660027623419419002
         */
        JSONObject parse = null;
        String query = lokiUrl + "/query_range?query={system=\"" + systemName + "\", " + logLabel + "=\"" + logLabelValue + "\"} |= `" + text + "`";
        String result = "";
        if (start==0L) {
            result = HttpUtil.get(query + "&limit=" + limit + "&direction=" + direction, CharsetUtil.CHARSET_UTF_8);
        } else {
            result = HttpUtil.get(query + "&limit=" + limit + "&start=" + start + "&end=" + end + "&direction=" + direction, CharsetUtil.CHARSET_UTF_8);
        }
        try {
            parse = (JSONObject) JSONObject.parse(result);
        } catch (Exception e) {
//            reslut的值可能為:too many outstanding requests,無法轉(zhuǎn)化成Json
            System.out.println("reslut:" + result);
//            e.printStackTrace();
        }
        return parse;
    }

前端的邏輯是比較復(fù)雜的,因?yàn)樾枰龃罅康馁x值與設(shè)置。 前端js方法代碼,主要是對(duì)參數(shù)數(shù)據(jù)的組織,這里需要注意的是,因?yàn)閘oki需要的是納秒級(jí)別的時(shí)間戳,這里就需要十分注意前端js的精度。還有一點(diǎn)就是,如果后端日志是有顏色標(biāo)簽的,那么前端直接渲染就會(huì)顯示標(biāo)簽,所以這里需要進(jìn)行相應(yīng)的處理,就是用過AnsiUp插件進(jìn)行操作,詳細(xì)看此篇文章:http://chabaoo.cn/article/266641.htm

queryData() {
  console.log(this.labelAndValue)
  // 清空查詢數(shù)據(jù)
  this.clearParam()
  if (this.labelAndValue.length > 0) {
    queryParam.logLabel = this.labelAndValue[0]
    queryParam.logLabelValue = this.labelAndValue[1]
  }
  if (queryParam.logLabelValue === null) { // 判空
    this.$message({
      showClose: true,
      message: '請(qǐng)選擇標(biāo)簽',
      type: 'warning'
    })
    this.showEmpty = true
    this.emptyText = '請(qǐng)選擇標(biāo)簽'
    return
  }
  if (this.timeRange.length !== 0) { // 如果是輸入時(shí)間范圍
    queryParam.start = (new Date(this.timeRange[0]).getTime() * 1000000).toString()
    queryParam.end = (new Date(this.timeRange[1]).getTime() * 1000000).toString()
  }
  if (this.timeZoneValue) {
    const time = new Date()
    queryParam.start = ((time.getTime() - this.timeZoneValue) * 1000000).toString()
    queryParam.end = (time.getTime() * 1000000).toString()
  }
  if (this.text) {
    queryParam.text = this.text.replace(/^\s*|\s*$/g, '') // 去空
  }
  if (this.limits) {
    queryParam.limits = this.limits
  }
  queryParam.direction = this.direction
  var ansi_up = new AnsiUp()
  logOperation.getLogData(queryParam).then(res => {
    this.showEmpty = false
    if (res.data.result.length === 1) {
      this.logs = res.data.result[0].values
      for (const i in res.data.result[0].values) {
        this.logs[i][1] = ansi_up.ansi_to_html(res.data.result[0].values[i][1])
      }
    } else if (res.data.result.length > 1) {
      // 清空
      this.logs = []
      for (const j in res.data.result) { // 用push的方式將所有日志數(shù)組添加進(jìn)去
        for (const values_index in res.data.result[j].values) {
          this.logs.push(res.data.result[j].values[values_index])
        }
      }
      for (const k in this.logs) {
        this.logs[k][1] = ansi_up.ansi_to_html(this.logs[k][1])
      }
      if (this.direction === 'backward') { // 由于使用公共標(biāo)簽會(huì)導(dǎo)致時(shí)間順序錯(cuò)亂,因此對(duì)二維數(shù)組進(jìn)行排序
        this.logs.sort((a, b) => b[0] - a[0])
      } else {
        this.logs.sort((a, b) => a[0] - b[0])
      }
    } else {
      this.showEmpty = true
      this.emptyText = '暫無日志信息,請(qǐng)選擇時(shí)間段試試'
    }
  })
},

通過AnsiUp插件可以將帶有顏色標(biāo)簽的日志以顏色展示,代碼如下:

<div style="margin: 3px; min-height: 80vh;">
  <!--數(shù)據(jù)判空-->
  <el-empty v-if="showEmpty" :description="emptyText" />
  <!--數(shù)據(jù)加載-->
  <el-card v-else shadow="hover" style="width: 100%" class="log-warpper">
    <div style="width: 100%">
      <div v-for="(log, index) in logs" :key="index">
        <div style="margin-bottom: 5px; font-size: 12px;" v-html="log[1]" />
      </div>
    </div>
  </el-card>
</div>

向后端請(qǐng)求日志返回的結(jié)果是如下圖所示

滾動(dòng)追加日志

其實(shí)下拉滾動(dòng)的代碼與上面直接獲取日志的是差不多的,只是在數(shù)據(jù)的追加是不一樣的做法,這里需要注意的是要考慮日志的展示是正序還是逆序,不同的順序計(jì)算時(shí)間范圍是不一樣的,就如下代碼

if (this.direction === 'backward') { // 設(shè)置時(shí)間區(qū)間
  queryParam.start = (this.logs[this.logs.length - 1][0] - zone).toString()
  queryParam.end = this.logs[this.logs.length - 1][0]
} else {
  queryParam.start = this.logs[this.logs.length - 1][0]
  queryParam.end = (parseFloat(this.logs[this.logs.length - 1][0]) + parseFloat(zone.toString())).toString()
}

在滾動(dòng)獲取日志的思路是獲取最后一條數(shù)據(jù)的時(shí)間,往后推一定的時(shí)間差,所以需要考慮是正序還是倒序,默認(rèn)是6小時(shí)。

mounted() {
  window.addEventListener('scroll', this.handleScroll)
}
methods: {
    handleScroll() { // 滾動(dòng)事件
      const scrollTop = document.documentElement.scrollTop// 滾動(dòng)高度
      const clientHeight = document.documentElement.clientHeight// 可視高度
      const scrollHeight = document.documentElement.scrollHeight// 內(nèi)容高度
      const bottomest = Math.ceil(scrollTop + clientHeight)
      if (bottomest >= scrollHeight) {
        // 加載新數(shù)據(jù)
        queryParam.limits = this.scrollStep
        queryParam.direction = this.direction
        // 獲取時(shí)間差
        let zone = queryParam.end - queryParam.start
        if (this.timeRange.length) { // 如果是輸入時(shí)間范圍
          zone = ((new Date(this.timeRange[1]).getTime() - new Date(this.timeRange[0]).getTime()) * 1000000).toString()
        }
        if (this.timeZoneValue) {
          zone = this.timeZoneValue * 1000000
        }
        if (zone === 0) {
          zone = 3600 * 1000 * 6
        }
        if (this.direction === 'backward') { // 設(shè)置時(shí)間區(qū)間
          queryParam.start = (this.logs[this.logs.length - 1][0] - zone).toString()
          queryParam.end = this.logs[this.logs.length - 1][0]
        } else {
          queryParam.start = this.logs[this.logs.length - 1][0]
          queryParam.end = (parseFloat(this.logs[this.logs.length - 1][0]) + parseFloat(zone.toString())).toString()
        }
        var ansi_up = new AnsiUp()
        logOperation.getLogData(queryParam).then(res => {
          console.log(res)
          this.showEmpty = false
          if (res.data.result.length === 1) {
            // 如果返回的日志是一樣的就不顯示
            if (res.data.result[0].values.length === 1 && ansi_up.ansi_to_html(res.data.result[0].values[0][1]) === this.logs[this.logs.length - 1][1]) {
              this.$notify({
                title: '警告',
                duration: 1000,
                message: '當(dāng)前時(shí)間段日志已最新!',
                type: 'warning'
              })
              return
            }
            const log = res.data.result[0].values
            for (const i in res.data.result[0].values) {
              log[i][1] = ansi_up.ansi_to_html(res.data.result[0].values[i][1])
              this.logs.push(log[i])
            }
          } else if (res.data.result.length > 1) {
            const tempArray = [] // 數(shù)據(jù)需要處理,由于是追加數(shù)組,所以需要用額外變量來存放
            // 刷新就是添加,不清空原數(shù)組
            for (const j in res.data.result) { // 用push的方式將所有日志數(shù)組添加進(jìn)去
              for (const values_index in res.data.result[j].values) {
                tempArray.push(res.data.result[j].values[values_index])
              }
            }
            if (this.direction === 'backward') { // 由于使用公共標(biāo)簽會(huì)導(dǎo)致時(shí)間順序錯(cuò)亂,因此對(duì)二維數(shù)組進(jìn)行排序
              tempArray.sort((a, b) => b[0] - a[0])
            } else {
              tempArray.sort((a, b) => a[0] - b[0])
            }
            for (const k in tempArray) {
              tempArray[k][1] = ansi_up.ansi_to_html(tempArray[k][1]) // 數(shù)據(jù)轉(zhuǎn)換
              this.logs.push(tempArray[k]) // 追加數(shù)據(jù)
            }
          } else {
            this.$notify({
              title: '警告',
              duration: 1000,
              message: '暫無以往日志數(shù)據(jù)!',
              type: 'warning'
            })
          }
        })
      }
    }
}

定時(shí)刷新日志

當(dāng)然,日志的獲取也是需要實(shí)時(shí)刷新的,這種不僅可以使用定時(shí)器還能夠使用websocket,筆者使用的是定時(shí)器,因?yàn)檫@個(gè)寫起來比較簡(jiǎn)單。相關(guān)的代碼以及解析如下: 視圖

<el-form-item>
  <el-dropdown split-button type="primary" size="mini" @click="queryData">
    查詢{{ runStatu }}
    <el-dropdown-menu slot="dropdown">
      <el-dropdown-item v-for="(item, index) in runStatuOptions" :key="index" @click.native="startInterval(item)">{{ item.label }}</el-dropdown-item>
    </el-dropdown-menu>
  </el-dropdown>
</el-form-item>

方法代碼 代碼大致也和上面兩種情況是類似的,思路是獲取當(dāng)前時(shí)間前(時(shí)間差)的時(shí)間到當(dāng)前時(shí)間的日志信息。這里不需要管日志的時(shí)序方向,只需要做好始終時(shí)間,注意納秒級(jí)別,還有定時(shí)器不要忘記銷毀。

startInterval(item) {
  this.runStatu = item.label
  console.log(item.value)
  if (item.value !== 0) {
    this.timer = setInterval(() => { // 定時(shí)刷新
      this.intervalLogs()
    }, item.value)
  } else {
    console.log('銷毀了')
    clearInterval(this.timer)
  }
},
intervalLogs() { // 定時(shí)器的方法
  // 組織參數(shù)
  // 設(shè)置開始時(shí)間和結(jié)束時(shí)間
  // 開始為現(xiàn)在時(shí)間
  const start = new Date()
  const end = new Date()
  // 時(shí)差判斷
  let zone = queryParam.end - queryParam.start
  if (this.timeRange.length) { // 如果是輸入時(shí)間范圍
    zone = ((new Date(this.timeRange[1]).getTime() - new Date(this.timeRange[0]).getTime()) * 1000000).toString()
  }
  if (this.timeZoneValue) {
    zone = this.timeZoneValue * 1000000
  }
  if (zone === 0) { // 防止空指針
    start.setTime(start.getTime() - 3600 * 1000 * 6)
    queryParam.start = (start.getTime() * 1000000).toString()
  } else {
    queryParam.start = (start.getTime() * 1000000 - zone).toString()
  }
  queryParam.end = (end.getTime() * 1000000).toString()
  queryParam.limits = this.limits
  console.log('定時(shí)器最后參數(shù):', queryParam)
  var ansi_up = new AnsiUp() // 后端日志格式轉(zhuǎn)化
  logOperation.getLogData(queryParam).then(res => {
    console.log('res', res)
    this.showEmpty = false
    debugger
    if (res.data.result.length === 1) {
      this.logs = res.data.result[0].values
      for (const i in res.data.result[0].values) { // 格式轉(zhuǎn)換
        this.logs[i][1] = ansi_up.ansi_to_html(res.data.result[0].values[i][1])
      }
    } else if (res.data.result.length > 1) {
      // 清空
      this.logs = []
      for (const j in res.data.result) { // 用push的方式將所有日志數(shù)組添加進(jìn)去
        for (const values_index in res.data.result[j].values) {
          this.logs.push(res.data.result[j].values[values_index])
        }
      }
      for (const k in this.logs) {
        this.logs[k][1] = ansi_up.ansi_to_html(this.logs[k][1])
      }
      if (this.direction === 'backward') { // 由于使用公共標(biāo)簽會(huì)導(dǎo)致時(shí)間順序錯(cuò)亂,因此對(duì)二維數(shù)組進(jìn)行排序
        this.logs.sort((a, b) => b[0] - a[0])
      } else {
        this.logs.sort((a, b) => a[0] - b[0])
      }
    } else {
      this.showEmpty = true
      this.emptyText = '暫無日志信息,請(qǐng)選擇時(shí)間段試試'
    }
  })
},

最后粘一小段展示的界面

總結(jié)

loki是輕量級(jí)的分布式日志查詢框架,特別適合中小型企業(yè),尤其是工業(yè)項(xiàng)目,在項(xiàng)目上線的時(shí)候可以通過這樣的一個(gè)界面來觀察日志,確實(shí)能夠得到很大的幫助,但是這個(gè)loki不是特別的穩(wěn)定,最為常見的是會(huì)出現(xiàn)ERP ERROR,這種錯(cuò)誤是最頭疼的,個(gè)人感覺可能是計(jì)算機(jī)或者網(wǎng)絡(luò)的因素造成。

以上就是SpringBoot Loki安裝簡(jiǎn)介及實(shí)戰(zhàn)思路的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot Loki安裝的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • RocketMQ4.5.2 修改mqnamesrv 和 mqbroker的日志路徑操作

    RocketMQ4.5.2 修改mqnamesrv 和 mqbroker的日志路徑操作

    這篇文章主要介紹了RocketMQ 4.5.2 修改mqnamesrv 和 mqbroker的日志路徑操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • java基礎(chǔ)學(xué)習(xí)筆記之泛型

    java基礎(chǔ)學(xué)習(xí)筆記之泛型

    所謂泛型,就是變量類型的參數(shù)化。泛型是JDK1.5中一個(gè)最重要的特征。通過引入泛型,我們將獲得編譯時(shí)類型的安全和運(yùn)行時(shí)更小的拋出ClassCastException的可能。在JDK1.5中,你可以聲明一個(gè)集合將接收/返回的對(duì)象的類型。
    2016-02-02
  • java學(xué)習(xí)教程之常量折疊詳解

    java學(xué)習(xí)教程之常量折疊詳解

    這篇文章主要給大家介紹了關(guān)于java學(xué)習(xí)教程之常量折疊的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-09-09
  • Java獲取堆棧信息的三種方法小結(jié)

    Java獲取堆棧信息的三種方法小結(jié)

    在Java編程中,獲取堆棧信息對(duì)于調(diào)試和故障排除非常重要,Java提供了多種方式來獲取當(dāng)前線程的堆棧信息,下面就跟隨小編一起學(xué)習(xí)一下常用的三種吧
    2024-03-03
  • Java實(shí)現(xiàn)每日給女友微信發(fā)送早安信息

    Java實(shí)現(xiàn)每日給女友微信發(fā)送早安信息

    這篇文章主要為大家詳細(xì)介紹了Java如何實(shí)現(xiàn)每日給女友微信發(fā)送早安等微信信息,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以了解一下
    2022-12-12
  • Java中使用BigDecimal進(jìn)行精確運(yùn)算

    Java中使用BigDecimal進(jìn)行精確運(yùn)算

    這篇文章主要介紹了Java中使用BigDecimal進(jìn)行精確運(yùn)算的方法,非常不錯(cuò),需要的朋友參考下
    2017-02-02
  • redis實(shí)現(xiàn)隊(duì)列的阻塞、延時(shí)、發(fā)布和訂閱

    redis實(shí)現(xiàn)隊(duì)列的阻塞、延時(shí)、發(fā)布和訂閱

    本文主要介紹了redis實(shí)現(xiàn)隊(duì)列的阻塞、延時(shí)、發(fā)布和訂閱,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • Spring boot熱部署devtools過程解析

    Spring boot熱部署devtools過程解析

    這篇文章主要介紹了Spring boot熱部署devtools過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • org.apache.zookeeper.KeeperException.BadVersionException異常的解決

    org.apache.zookeeper.KeeperException.BadVersionException異常的解

    在使用Apache ZooKeeper進(jìn)行分布式協(xié)調(diào)時(shí),你可能會(huì)遇到org.apache.zookeeper.KeeperException.BadVersionException異常,本文就來介紹一下解決方法,感興趣的可以了解一下
    2024-03-03
  • SpringCloud Zuul在何種情況下使用Hystrix及問題小結(jié)

    SpringCloud Zuul在何種情況下使用Hystrix及問題小結(jié)

    這篇文章主要介紹了SpringCloud Zuul在何種情況下使用Hystrix 及問題小結(jié),感興趣的朋友跟隨小編一起看看吧
    2018-11-11

最新評(píng)論