04-MySQL运维常用脚本

一: mysql 命令行连接

  • 安装并启动 mysql 服务;

002-CMakeLists.txt说明

CMakeLists.txt说明

CMakeLists.txt

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# cmake最小版本要求3.21.0
cmake_minimum_required(VERSION 3.21.0)

# 指定project名称为client
project(client)

# set 定义变量
set(PROJ_VERSION v1.0.0)

set(CMAKE_CXX_STANDARD 17)
# 设置编译器编译模式
set(cmake_build_type "Debug")

# include 指令用来载入并运行来自于文件或模块的 CMake 代码
#include()

# 将/usr/include/myincludefolder 和./include添加到头文件搜索路径
#include_directories(/usr/include/myincludefolder ./include)
include_directories(include)

# 将/usr/lib/myincludefolder ./lib添加到库文件搜索路径
#link_directories(/usr/lib/myincludefolder ./lib)

# 设置源文件path
aux_source_directory(src DIR_SRCS)
#aux_source_directory(src/entity DIR_ENTITY)
#source_group(src src/entity)

# 生成共享库,这儿不需要.hpp
#add_library(calculate SHARED hello.cpp)

#添加编译参数 -Wall -std=c++11
add_compile_options(-Wall -std=c++17 -O2) # 注意是大写的O

# 链接共享库,将calculate.so动态库链接到可执行文件main
#target_link_libraries(main calculate)


# 添加需要的所有的执行文件
add_executable(client ${DIR_SRCS})

# ---------------CMake常用变量----------------
# CMAKE_C_FLAGS #gcc编译选项
# CMAKE_CXX_FLAGS #g++编译选项
# set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") #这表明不会覆盖CMAKE_CXX_FLAGS,而是在它后面追加-std=c++11这个编译选项
#
##设定编译类型为debug,调试时需要选择debug
# set(CMAEK_BUILE_TYPE Debug)
##设定编译类型为release,发布时需要选择release
# set(CMAKE_BUILE_TYPE Release)
#
# CMAKE_BINARY_DIR
# CMAKE_SOURCE_DIR #指定CMakeList.txt所在的路径
# CMAKE_C_COMPILER #指定C编译器
# CMAKE_CXX_COMPILER #指定C++编译器
# EXECUTABLE_OUTPUT_PATH #可执行文件输出的存放路径
# LIBRARY_OUTPUT_PATH #库文件输出的存放路径

037-Linux配置环境变量的6种方法

Linux配置环境变量的6种方法

1: Linux 读取环境变量

  • 在自定义安装软件的时候,经常需要配置环境变量,下面列举出各种对环境变量的配置方法。

035-Linux高效运维工具

[toc]

Linux高效运维工具

1: 系统性能,资源

1.1 top

1.2 htop

  • yum -y install htop

1.3 btop/gotop

1.4 系统资源监控-NMON

NMON 是一种在 AIX 与各种 Linux 操作系统上广泛使用的监控与分析工具.

go zap日志库

go zap日志库笔记

1: 概述

  • go zap 高性能日志库;

2: 创建实例

  • 通过调用 zap.NewProduction()/zap.NewDevelopment()或者 zap.Example()创建一个 Logger。这三个方法的区别在于它将记录的信息不同,参数只能是 string 类型
  • 三种创建方式对比:
  • Example 和 Production 使用的是 json 格式输出,Development 使用行的形式输出;
  • Development:
    • 从警告级别向上打印到堆栈中来跟踪
    • 始终打印包/文件/行(方法)
    • 在行尾添加任何额外字段作为 json 字符串
    • 以大写形式打印级别名称
    • 以毫秒为单位打印 ISO8601 格式的时间戳
  • Development
    • 从警告级别向上打印到堆栈中来跟踪
    • 始终打印包/文件/行(方法)
    • 在行尾添加任何额外字段作为 json 字符串
    • 以大写形式打印级别名称
    • 以毫秒为单位打印 ISO8601 格式的时间戳
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
//代码
var log *zap.Logger
log = zap.NewExample()
log, _ := zap.NewDevelopment()
log, _ := zap.NewProduction()
log.Debug("This is a DEBUG message")
log.Info("This is an INFO message")

//Example 输出
{"level":"debug","msg":"This is a DEBUG message"}
{"level":"info","msg":"This is an INFO message"}

//Development 输出
2018-10-30T17:14:22.459+0800 DEBUG development/main.go:7 This is a DEBUG message
2018-10-30T17:14:22.459+0800 INFO development/main.go:8 This is an INFO message

//Production 输出
{"level":"info","ts":1540891173.3190675,"caller":"production/main.go:8","msg":"This is an INFO message"}
{"level":"info","ts":1540891173.3191047,"caller":"production/main.go:9","msg":"This is an INFO message with fields","region":["us-west"],"id":2}
}

3: 格式化输出

  • zap 有两种类型,分别是zap.Loggerzap.SugaredLogger,它们惟一的区别是,我们通过调用主 logger 的. Sugar()方法来获取一个 SugaredLogger,然后使用 SugaredLogger 以 printf 格式记录语句,例如:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
var sugarLogger *zap.SugaredLogger

func InitLogger() {
logger, _ := zap.NewProduction()
sugarLogger = logger.Sugar()
}

func main() {
InitLogger()
defer sugarLogger.Sync()
sugarLogger.Errorf("Error fetching URL %s : Error = %s", url, err)
}

4: 写入文件

  • 默认情况下日志都会打印到应用程序的 console 界面,但是为了方便查询,可以将日志写入文件,但是我们不能再使用前面创建实例的 3 个方法,而是使用zap.New()
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
	"os"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

var log *zap.Logger

func main() {
	writeSyncer, _ := os.Create("./info.log")         //日志文件存放目录
	encoderConfig := zap.NewProductionEncoderConfig() //指定时间格式
	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
	encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
	encoder := zapcore.NewConsoleEncoder(encoderConfig)               //获取编码器,NewJSONEncoder()输出json格式,NewConsoleEncoder()输出普通文本格式
	core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel) //第三个及之后的参数为写入文件的日志级别,ErrorLevel模式只记录error级别的日志
	log = zap.New(core, zap.AddCaller())                              //AddCaller()为显示文件名和行号
	log.Info("hello world")
	log.Error("hello world")
}


// log输出结果:
2020-12-16T17:53:30.466+0800 INFO geth/main.go:18 hello world
2020-12-16T17:53:30.486+0800 ERROR geth/main.go:19 hello world

5: 同时输出控制台和文件

  • 如果需要同时输出控制台和文件,只需要改造一下 zapcore.NewCore 即可,示例:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package main

import (
	"os"

	"github.com/natefinch/lumberjack"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

var log *zap.Logger

func main() {
	// 获取编码器,NewJSONEncoder()输出json格式,NewConsoleEncoder()输出普通文本格式
	encoderConfig := zap.NewProductionEncoderConfig()
	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder //指定时间格式
	encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
	encoder := zapcore.NewConsoleEncoder(encoderConfig)

	// 文件writeSyncer
	fileWriteSyncer := zapcore.AddSync(&lumberjack.Logger{
		Filename:   "./info.log", //日志文件存放目录
		MaxSize:    1,            //文件大小限制,单位MB
		MaxBackups: 5,            //最大保留日志文件数量
		MaxAge:     30,           //日志文件保留天数
		Compress:   false,        //是否压缩处理
	})
	fileCore := zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(fileWriteSyncer, zapcore.AddSync(os.Stdout)), zapcore.DebugLevel) //第三个及之后的参数为写入文件的日志级别,ErrorLevel模式只记录error级别的日志

	log = zap.New(fileCore, zap.AddCaller()) //AddCaller()为显示文件名和行号

	log.Info("hello world")
	log.Error("hello world")
}

6: 文件切割

  • 日志文件会随时间越来越大,为了避免日志文件把硬盘空间占满,需要按条件对日志文件进行切割,zap 包本身不提供文件切割的功能,但是可以用 zap 官方推荐的lumberjack包处理
1
2
3
4
5
6
7
8
//文件writeSyncer
fileWriteSyncer := zapcore.AddSync(&lumberjack.Logger{
Filename: "./info.log", //日志文件存放目录,如果文件夹不存在会自动创建
MaxSize: 1, //文件大小限制,单位MB
MaxBackups: 5, //最大保留日志文件数量
MaxAge: 30, //日志文件保留天数
Compress: false, //是否压缩处理
})

7: 按级别写入文件

  • 为了管理人员的查询方便,一般我们需要将低于 error 级别的放到 info.log,error 及以上严重级别日志存放到 error.log 文件中,我们只需要改造一下 zapcore.NewCore 方法的第 3 个参数,然后将文件 WriteSyncer 拆成 info 和 error 两个即可,示例:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package main

import (
	"os"

	"github.com/natefinch/lumberjack"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

var log *zap.Logger

func main() {
	var coreArr []zapcore.Core

	// 获取编码器
	encoderConfig := zap.NewProductionEncoderConfig()            //NewJSONEncoder()输出json格式,NewConsoleEncoder()输出普通文本格式
	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder        //指定时间格式
	encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder //按级别显示不同颜色,不需要的话取值zapcore.CapitalLevelEncoder就可以了
	// encoderConfig.EncodeCaller = zapcore.FullCallerEncoder //显示完整文件路径
	encoder := zapcore.NewConsoleEncoder(encoderConfig)

	// 日志级别
	highPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool { //error级别
		return lev >= zap.ErrorLevel
	})
	lowPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool { //info和debug级别,debug级别是最低的
		return lev < zap.ErrorLevel && lev >= zap.DebugLevel
	})

	// info文件writeSyncer
	infoFileWriteSyncer := zapcore.AddSync(&lumberjack.Logger{
		Filename:   "./log/info.log", //日志文件存放目录,如果文件夹不存在会自动创建
		MaxSize:    1,                //文件大小限制,单位MB
		MaxBackups: 5,                //最大保留日志文件数量
		MaxAge:     30,               //日志文件保留天数
		Compress:   false,            //是否压缩处理
	})
	infoFileCore := zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(infoFileWriteSyncer, zapcore.AddSync(os.Stdout)), lowPriority) //第三个及之后的参数为写入文件的日志级别,ErrorLevel模式只记录error级别的日志

	// error文件writeSyncer
	errorFileWriteSyncer := zapcore.AddSync(&lumberjack.Logger{
		Filename:   "./log/error.log", //日志文件存放目录
		MaxSize:    1,                 //文件大小限制,单位MB
		MaxBackups: 5,                 //最大保留日志文件数量
		MaxAge:     30,                //日志文件保留天数
		Compress:   false,             //是否压缩处理
	})
	errorFileCore := zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(errorFileWriteSyncer, zapcore.AddSync(os.Stdout)), highPriority) //第三个及之后的参数为写入文件的日志级别,ErrorLevel模式只记录error级别的日志

	coreArr = append(coreArr, infoFileCore)
	coreArr = append(coreArr, errorFileCore)
	log = zap.New(zapcore.NewTee(coreArr...), zap.AddCaller()) //zap.AddCaller()为显示文件名和行号,可省略

	log.Info("hello info")
	log.Debug("hello debug")
	log.Error("hello error")
}
  • 这样修改之后,info 和 debug 级别的日志就存放到 info.log,error 级别的日志单独放到 error.log 文件中了

8: 控制台按级别显示颜色

  • 指定编码器的 EncodeLevel 即可
1
2
3
4
5
//获取编码器
encoderConfig := zap.NewProductionEncoderConfig() //NewJSONEncoder()输出json格式,NewConsoleEncoder()输出普通文本格式
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder //指定时间格式
encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder //按级别显示不同颜色,不需要的话取值zapcore.CapitalLevelEncoder就可以了
encoder := zapcore.NewConsoleEncoder(encoderConfig)

9: 显示文件路径和行号

  • 前面说到要显示文件路径和行号,只需要 zap.New 方法添加参数 zap.AddCaller()即可,如果要显示完整的路径,需要在编码器配置中指定
1
2
3
4
5
6
//获取编码器
encoderConfig := zap.NewProductionEncoderConfig() //NewJSONEncoder()输出json格式,NewConsoleEncoder()输出普通文本格式
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder //指定时间格式
encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder //按级别显示不同颜色,不需要的话取值zapcore.CapitalLevelEncoder就可以了
encoderConfig.EncodeCaller = zapcore.FullCallerEncoder //显示完整文件路径
encoder := zapcore.NewConsoleEncoder(encoderConfig)

10: 完整代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package main

import (
	"os"

	"github.com/natefinch/lumberjack"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

var log *zap.Logger

func main() {
	var coreArr []zapcore.Core

	// 获取编码器
	encoderConfig := zap.NewProductionEncoderConfig()            //NewJSONEncoder()输出json格式,NewConsoleEncoder()输出普通文本格式
	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder        //指定时间格式
	encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder //按级别显示不同颜色,不需要的话取值zapcore.CapitalLevelEncoder就可以了
	// encoderConfig.EncodeCaller = zapcore.FullCallerEncoder //显示完整文件路径
	encoder := zapcore.NewConsoleEncoder(encoderConfig)

	// 日志级别
	highPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool { //error级别
		return lev >= zap.ErrorLevel
	})
	lowPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool { //info和debug级别,debug级别是最低的
		return lev < zap.ErrorLevel && lev >= zap.DebugLevel
	})

	// info文件writeSyncer
	infoFileWriteSyncer := zapcore.AddSync(&lumberjack.Logger{
		Filename:   "./log/info.log", //日志文件存放目录,如果文件夹不存在会自动创建
		MaxSize:    2,                //文件大小限制,单位MB
		MaxBackups: 100,              //最大保留日志文件数量
		MaxAge:     30,               //日志文件保留天数
		Compress:   false,            //是否压缩处理
	})
	infoFileCore := zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(infoFileWriteSyncer, zapcore.AddSync(os.Stdout)), lowPriority) //第三个及之后的参数为写入文件的日志级别,ErrorLevel模式只记录error级别的日志
	// error文件writeSyncer
	errorFileWriteSyncer := zapcore.AddSync(&lumberjack.Logger{
		Filename:   "./log/error.log", //日志文件存放目录
		MaxSize:    1,                 //文件大小限制,单位MB
		MaxBackups: 5,                 //最大保留日志文件数量
		MaxAge:     30,                //日志文件保留天数
		Compress:   false,             //是否压缩处理
	})
	errorFileCore := zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(errorFileWriteSyncer, zapcore.AddSync(os.Stdout)), highPriority) //第三个及之后的参数为写入文件的日志级别,ErrorLevel模式只记录error级别的日志

	coreArr = append(coreArr, infoFileCore)
	coreArr = append(coreArr, errorFileCore)
	log = zap.New(zapcore.NewTee(coreArr...), zap.AddCaller()) //zap.AddCaller()为显示文件名和行号,可省略

	log.Info("hello info")
	log.Debug("hello debug")
	log.Error("hello error")
}

git初始化新仓库

1: 使用 docker 安装配置 gitlab

  • 设置默认分支。默认是main,更改为master

2: 初始化新仓库

  • 在 gitlab 创建新仓库
  • 把本地目录上传到这个仓库
1
2
3
4
5
6
7
cd xxx
git init
git add -A
git commit -m "init"
git remote add origin http://47.115.218.14:9980/ms/oems-test-v3.git
git branch -M master
git push -uf origin master
  • You are not allowed to force push code to a protected branch on this project.主要原因是因为向一个受保护的分支强制提交了代码,可以在仓库里面进行设置来解决这个问题.

使用 docker 安装配置 gitlab

使用 docker 安装配置 gitlab

1: 下载 gitlab images

  • Gitlab是一个开源的版本管理系统,实现一个自托管的 Git 项目仓库,可通过 Web 界面进行访问公开的或者私人项目。它拥有与 Github 类似的功能,能够浏览源码,管理缺陷和注释,可以管理团队对仓库的访问,它非常易于浏览提交的版本并提供一个文件历史库。团队成员可以利用内置的简单的聊天程序进行交流。它还提供一个代码片段收集功能可以实现代码复用。

005-10分钟搞定pandas+实例

1:什么是 pandas

先看-> 10 分钟搞定 pandas+实例

转自: https://pyzh.readthedocs.io/en/latest/python-pandas.html 本文是 pandas 官网 10 Minutes to pandas 的翻译 。

go实现并发文件传输,断点续传

go实现并发文件传输,断点续传

1: 概述

很多文件基本都是多协程下载文件要么就只有单协程的断点续传,这里给大家写一个支持有进度条的多协程下载文件,也支持断点续传

2: 使用示例代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package main

import (
	"fmt"
	"io"
	"os"
	"regexp"
	"strconv"
	"sync"

	"github.com/qianlnk/pgbar"
)

/**
* 需求:
1. 多协程并发下载文件
2. 断点续连
**/
func main() {
	//获取要下载文件
	DownloadFileName := "./Charles.4.5.6.zip"
	//copy的文件
	copyFileName := "./test.zip"
	storgeFileName := "./downloadRate.txt"
	//打开文件
	sfile, err := os.Open(DownloadFileName)
	if err != nil {
		panic(err)
	}
	defer sfile.Close()
	//获取文件大小
	info, _ := sfile.Stat()
	downloadSize := info.Size()
	var scount int64 = 1
	if downloadSize%5 == 0 {
		scount *= 5
	} else {
		scount *= 10
	}
	//分给每个协程的大小
	si := downloadSize / scount
	fmt.Printf("文件总大小:%v, 分片数:%v,每个分片大小:%v\n", downloadSize, scount, si)
	//open copy file
	copyFile, err := os.OpenFile(copyFileName, os.O_CREATE|os.O_WRONLY, os.ModePerm)
	if err != nil {
		panic(err)
	}
	storgeFile, err := os.OpenFile(storgeFileName, os.O_CREATE|os.O_RDWR, os.ModePerm)
	if err != nil {
		panic(err)
	}
	defer copyFile.Close()

	var currentIndex int64 = 0
	wg := sync.WaitGroup{}
	fmt.Println("文件下载进度条...")
	pgb := pgbar.New("")
	for ; currentIndex < scount; currentIndex++ {
		wg.Add(1)
		go func(current int64) {
			p := pgb.NewBar(fmt.Sprintf("%02d", (current+1))+"st", int(si))
			p.SetSpeedSection(900, 100)
			b := make([]byte, 10240)
			bs := make([]byte, 16)
			currentIndex, _ := storgeFile.ReadAt(bs, current*16)
			//取出所有整数
			reg := regexp.MustCompile(`\d+`)
			countStr := reg.FindString(string(bs[:currentIndex]))
			total, _ := strconv.ParseInt(countStr, 10, 0)
			progressBar := 1
			for {
				if total >= si {
					wg.Done()
					break
				}
				//从指定位置开始读
				n, err := sfile.ReadAt(b, current*si+total)
				if err == io.EOF {
					wg.Done()
					break
				}
				//从指定位置开始写
				copyFile.WriteAt(b, current*si+total)
				storgeFile.WriteAt([]byte(strconv.FormatInt(total, 10)+" "), current*16)
				total += int64(n)
				if total >= si/10*int64(progressBar) {
					progressBar += 1
					p.Add(int(si / 10))
				}
			}

		}(currentIndex)
	}
	wg.Wait()
	storgeFile.Close()
	os.Remove(storgeFileName)
	fmt.Printf("\n下载完成...\n")
}