# QingTian Enclave日志转发工具
#### QingTian Enclave日志转发工具（qlog）概述
qlog（QingTian Enclave log）是QingTian Enclave的运维工具。QingTian Enclave是运行在QingTian架构虚拟机中完全隔离的子虚拟机，即使是root用户也不能直接通过ssh登入。因此，为了方便运维人员监控运行在QingTian Enclave中的业务和定位问题，我们推出了qlog工具。qlog可以收集QingTian Enclave虚拟机中指定的日志文件和资源使用情况，并将结果发送到父虚拟机中。目前qlog支持收集QingTian Enclave中的资源使用情况包括CPU使用率和内存使用率。
qlog是一个可执行二进制文件，需要在父虚拟机中和QingTian Enclave中通过不同的命令运行：
- 在父虚拟机中，通过执行"**/path/to/qlog receive-file \<cid\>/path/to/config_qlog.toml**"命令启用qlog。

- 在QingTian Enclave中，通过执行"**/path/to/qlog monitor /path/to/config_qlog.toml**"命令启用qlog。
传统虚拟机中业务的日志会直接存储在类似"/var/log/service.log"的目录文件当中。
在将业务移植到QingTian Enclave中之后，通过qlog工具，可以将上述日志文件（"/var/log/service.log"）导出到父虚拟机当中。
使用同一个qlog二进制文件，通过**qlog receive-file** 和**qlog monitor**命令，使其分别运行在父虚拟机和QingTian Enclave中，两者会建立基于local vsock的通信链路。运行在QingTian Enclave中的qlog组件会收集指定的业务日志或QingTian Enclave的资源使用情况，将收集到的数据发送给父虚拟机中的qlog组件。父虚拟机中的qlog组件再将接收到的数据储存到指定的文件中，如"/var/log/qlog/service.log"。
图1网络服务无感迁移至QingTian Enclave   
![](https://support.huaweicloud.com/usermanual-ecs/zh-cn_image_0000002154969793.png "点击放大")
本文介绍qlog的操作步骤。
#### 前提条件
1. 获取qlog程序。 克隆QingTian Enclave代码仓。
   ```
   git clone https://gitee.com/HuaweiCloudDeveloper/huawei-qingtian.git
   ```
   
2. 获取cargo工具链。
   1. 执行下述命令安装rustup
      ```
      curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
      ```
      
   
   2. 安装完成后执行下述命令加载rustup
      ```
      source $HOME/.cargo/env
      ```
      
   
   3. 执行下述命令验证rustc和cargo安装成功
      ```
      rustc -V
      cargo -V
      ```
      
    
3. qlog的前置依赖。
   表1前置依赖 
   | 依赖项     | 最低测试版本 |
   |:---|:---|
   | glibc | 2.34   |
   | cargo   | 1.77.0 |
      
   
4. QingTian Enclave的环境准备。
   1. 安装qt CLI工具和其他必要rpm包。
   
   2. 安装Docker。
   
   3. 安装python3以及几个必要的python module : docker和knack。
   
   
   详细内容，请参考[快速入门](https://support.huaweicloud.com/usermanual-ecs/ecs_03_1404.html)和[安装qt CLI](https://support.huaweicloud.com/usermanual-ecs/ecs_03_1417.html)。
   
 
#### 操作步骤
1. **构建qlog** 。
   
   进入qingtian-tools/qlog目录中，执行cargo命令：
   ```
   cargo build --release
   ```
   生成的qlog程序在目录qingtian-tools/qlog/target/release下。
   
   
2. **创建工作目录** 。
   
   新建工作目录workspace，将qlog程序拷贝到workspace下，后续创建的文件都放在workspace中。
   
   

3. **配置** **config_qlog.toml** 。
   
   在workspace目录中创建config_qlog.toml文件，内容如下：
   ```
   port: 6000
   workspace: /var/log/qlog 
   server_logfile: server.log 
   client_logfile: client.log 
   server_threads: 4
   client_threads: 1
   log_level: info 
   rotate_size: 65536
   rotate_num: 10
   monitor_items:  
     - name: service  #业务名    
       monitor_type: file     
       monitor_path: /var/log/service.log  #QingTian Enclave中业务日志的路径    
       outputfile: service.log  #同步到父虚拟机中的日志文件名  
     - name: resource     
       monitor_type: resource     
       monitor_internel: 15    
       outputfile: resource.log
   ```
   
   
4. **制作含qlog的QingTian Enclave镜像** 。
   
   1. 在workspace目录中创建start.sh脚本：
      ```
      #/bin/bash
      /root/qlog monitor /root/config_qlog.toml & 
      LOG_FILE="/var/log/service.log"
      LOG_MESSAGE="Hello, service." 
      while true; do    
          TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')    
          echo "$TIMESTAMP - $LOG_MESSAGE" >> "$LOG_FILE"    
          sleep 3
      done
      ```
      
   
   
   
   2. 赋予start.sh脚本执行权限，在workspace目录中执行下述命令：
      ```
      chmod +x start.sh
      ```
      
   
   3. 在workspace目录中创建Dockerfile文件，内容如下：
      ```
      FROM ubuntu:22.04 
      COPY ./qlog /root/qlog 
      COPY ./config_qlog.toml /root/config_qlog.toml 
      COPY ./start.sh /root/start.sh 
      CMD /root/start.sh
      ```
      
   
   4. 赋予start.sh执行权限，在workspace目录中执行以下命令：
      ```
      chmod +x start.sh
      ```
      
   
   5. 制作docker镜像，在workspace目录中运行以下命令：
      ```
      docker build -f Dockerfile -t test_qlog_enclave .
      ```
      
   
   6. 制作QingTian Enclave镜像，在workspace目录中运行以下命令：
      ```
      qt enclave make-img --docker-uri test_qlog_enclave --eif test_qlog_enclave.eif
      ```
      
   
   
   
   
5. **启动qlog** 。
   
   1. 启动一台QingTian Enclave，在workspace目录中运行下述命令：
      ```
      qt enclave start --cpus 2 --mem 1024 --cid 4 --eif test_qlog_enclave.eif
      ```
      
   
   2. 启动父虚拟机中的qlog，在workspace目录中运行下述命令：
      ```
      ./qlog receive-file 4 ./config_qlog.toml &
      ```
      
   
   3. 父虚拟机中执行下述命令，查看service日志：
      ```
      tail -F /var/log/qlog/service.log
      ```
      可以看到每3s，打印一行日志"Hello, service."。
      
   
   4. 父虚拟机中执行下述命令，查看QingTian Enclave中资源使用情况：
      ```
      tail -F /var/log/qlog/resource.log
      ```
      可以看到每15s，打印一次CPU使用率和内存使用率。
      
   
   
   
   
 
#### qlog帮助信息
**qlog help**
```
$ qlog --help
A tool to monitor logs and resource usage over a Vsock connection  
Usage: qlog <COMMAND> 
Commands:   
  monitor       Monitor resource usage   
  receive-file  Receive data from qlog monitor   
  help          Print this message or the help of the given subcommand(s) 
Options:   
  -h, --help  Print help
```
**qlog monitor help**
```
$ qlog help monitor 
Monitor logs and/or resource usage  
Usage: qlog monitor [OPTIONS] <CONFIG> 
Arguments:   
  <CONFIG>  A configuration file in yaml format, which defines items to be monitored  
Options:   
  -c, --cid <CID>  CID to listen on (defaults to VMADDR_CID_ANY) [default: 4294967295]  
  -h, --help       Print help
```
**qlog receive-file help**
```
$ qlog help receive-file 
Receive data from qlog monitor  
Usage: qlog receive-file [OPTIONS] <CID> <CONFIG> 
Arguments:   
  <CID>     Enclave VM's CID   
  <CONFIG>  A configuration file in yaml format, which defines items to be monitored  
Options:   
  -w, --workspace <WORKSPACE>  Set to workspace if specified, prior to configuration file  
  -h, --help                   Print help
```
#### 配置信息（Config）
表2配置参数解释 
| Variable        | Type    | Description                                                   |
|:---|:---|:---|
| port           | u32       | vsock端口                                                      |
| workspace     | String  | 写入进程日志和监控数据的工作空间                                              |
| server_logfile | String   | 将服务器端（qlog monitor）进程日志写入\<workspace\>/\<server_logfile\>   |
| client_logfile | String | 将客户端（qlog receive-file）进程日志写入\<workspace\>/\<client_logfile\> |
| server_threads  | u32       | 服务器端（qlog monitor）线程数量                                      |
| client_threads | u32       | 客户端（qlog receive-file）线程数量                                  |
| log_level     | String    | 日志等级（TRACE/DEBUG/INFO/WARN/ERROR/OFF）                        |
| rotate_size    | u32     | 可选参数：日志文件转储大小，默认是2MB                                        |
| rotate_num    | u32     | 可选参数：日志文件转储时，保留旧日志文件数量，默认是10                                 |
| monitor_items  | Vector   | 监控事物列表                                                       |
   
表3监控项参数解释 
| Variable         | Type    | Description                                          |
|:---|:---|:---|
| name             | String | 事物名称                                                  |
| monitor_type   | String  | 监控类型：file表示日志文件，resource表示资源使用                         |
| monitor_path   | String   | 可选参数，QingTian Enclave中要监控的日志文件路径，monitor_type只能是file |
| monitor_internel | u32    | 可选参数，资源监视间隔时间，单位是秒，默认值是15，monitor_type只能是resource       |
| outputfile       | String   | 监控数据文件名称，写入监控数据的路径是\<workspace\>/\<outputfile\>      |
   
**配置文件参考**
```
port: 6000
workspace: /var/log/qlog 
server_logfile: server.log 
client_logfile: client.log 
server_threads: 4
client_threads: 1
log_level: info 
rotate_size: 65536
rotate_num: 10
monitor_items:  
  - name: item1     
    monitor_type: file     
    monitor_path: /var/log/item1.log     
    outputfile: output1.log   
  - name: item2     
    monitor_type: file     
    monitor_path: /var/log/item2.log     
    outputfile: output2.log   
  - name: item3     
    monitor_type: file     
    monitor_path: /var/log/item3.log     
    outputfile: output3.log   
  - name: item4     
    monitor_type: file     
    monitor_path: /var/log/item4.log     
    outputfile: output4.log   
  - name: item5     
    monitor_type: resource     
    monitor_internel: 15    
    outputfile: output5.log
```
