cmake引用jansson库

2024年1月09日 14:50

描述

 
在ubuntun系统上使用clion开发c程序, cmake如何引入jansson库.
 

下载jansson

 
wget http://digip.org/jansson/releases/jansson-2.13.tar.gz

tar -xvf
 

编译jansson

cd jansson-2.13
mkidr build
cd build
cmake ../
make
 

查看编译结果

 
├── include
│      ├── jansson_config.h
│      └── jansson.h
├── lib
│     └── libjansson.a
 
 

clion创建C程序

File->New->Project->选中"C Executable"
 

CMakeLists.txt引用jansson

 
cmake_minimum_required(VERSION 3.22)
project(demo_task C)

set(CMAKE_C_STANDARD 11)

#自定义库, jansson放在了source目录下
set(LIBHOME "/home/xxx/workspace/source/")

# jansson
include_directories(${LIBHOME}/jansson-2.13/build/include)
link_directories(${LIBHOME}/jansson-2.13/build/lib)
link_libraries(jansson)

add_executable(demo_task main.c)
 

main.c使用jansson

 
创建demo.json并放入任意json数据, jansson读取demo.json,并打印结果
 
#include <stdio.h>
#include <jansson.h>

int main() {
    json_t *json;
    json_error_t error;

    json = json_load_file("../demo.json", 0, &error);
    if(!json) {
        /* the error variable contains error information */
    }
    char *result = json_dumps(json, 0);
    printf("%s\n", result);
    free(result);

    return 0;
}
 
 

运行

 
clion运行并查看结果
 
 
 
 
 

Tags: json jansson c
评论(52) 阅读(1284)

traefik如何使用文件发现服务02

2023年5月15日 17:58

 

问题

 
traefik如何使用配置文件发现服务? 
 
使用docker启动traefik, traefik使用配置文件, 并且服务也使用配置文件
 
通过docker-compose.yaml引用traefik.yml, config.yml
 
 

docker-compose.yaml

 
version: "3"
services:
  reverse-proxy:
    #image: traefik:v2.10
    image: traefik:latest
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - ./traefik.yml:/etc/traefik/traefik.yml
      - ./config.yml:/etc/traefik/config.yml
  whoami:
    image: containous/whoami
    ports:
      - "5000:80"
 

traefik配置文件traefik.yml

 
api:
    insecure: true
...
providers:
    file:
        filename: /etc/traefik/config.yml
 

服务发现配置config.yml

 
 
http:
    routers:
      my-router:
        rule: "Path(`/whoami/`)"
        service: whoami
    services:
      whoami:
        loadBalancer:
          servers:
            - url: "http://xxxx:5000/"
 
 
 
 
 

Tags: traefik
评论(110) 阅读(1752)

traefik入门示例解析01

2023年5月15日 16:45

 

traefik是什么

 
微服务架构产生了大量的服务, 借助etcd之类的注册中心,找服务还需要接入etcd,还是比较麻烦,有没有统一的网关入口?
 
下面借助简单例子, 试用并理解traefik。
 

官方示例

 
官网提供了docker-compose示例, 我改了几个端口方便理解.
 
* docker-compose.yaml
 
version: "3"
services:
  reverse-proxy:
    #image: traefik:v2.10
    image: traefik:latest
    ports:
      # 提供http入口
      - "81:80"
      # web界面服务
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    command: --api.insecure=true  --providers.docker
  whoami:
    image: containous/whoami
    ports:
      - "82:80"
    labels:
      - "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"
      #- "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`) || PathPrefix(`/whoami/`)"
      #- "traefik.http.routers.whoami.rule=PathPrefix(`/whoami/`)"
 
* reverse-proxy是traefik服务, 提供了两个接口 http://127.0.0.1:81, http://127.0.0.1:8080
 
* --api.insecure=true开启api
 
* --providers.docker表示traefik使用docker接口找服务
 
* lables属于容器标签, traefik找到容器后,会读取标签,进行路由配置
 
* whoami是一个http服务 http://127.0.0.1:82
 

访问whoami

 
# 方法1: 直接访问whoami服务(此处是82端口)
http://127.0.0.1:82

# 方法2: 通过traefik代理访问whoami的http服务(此处是82端口)
# -H设置http请求header中的Host
# http://127.0.0.1:81访问traefik端口
curl -H Host:whoami.docker.localhost  http://127.0.0.1:81

# 方法3: 通过http前缀访问(此处是82端口)
# 打开whoami容器labels的第二行, 支持Host和PathPrefix两种方式
http://127.0.0.1:81/whoami/
 

代理规则

 
* 代理规则: Host
 
Host(`whoami.docker.localhost`)   # 发送http请求的Header中的Host改为whoami.docker.localhost
 
* 代理规则: url前缀
 
http://ip:port/whoami/     # 类似nginx的location
 
 

问题列表

 
* 问题1: traefik如何找到服务whoami?
 
--providers.docker指定了服务来源于docker, traefix会调用docker接口找服务,并解析labels获取匹配规则
 
* 问题2: host规则如何使用
 
有两种方式, 第一种,发送请求前修改header中的host参数; 第二种,使用域名访问
 
 
 
 
 
 

Tags: traefik
评论(356) 阅读(3203)

全局gin对象如何在子模块中修改Logger

2022年12月11日 17:24

 

说明

 
gin是通过中间件写日志, 日志对象是中间件的闭包变量。在use加载中间件完成之后,无法修改日志对象。 该如何办呢?
 

一般设置方法

 
以下是设置gin日志的方法
 
#方法一
gin.DefaultWriter = xxx
gin.DefaultErrorWriter = xxx 
app := gin.Default()
app.Use(xxx)

#方法二
app := gin.Default()
app.Use(gin.LoggerWithWriter(xxx))
 

当情况发生变化

 
1. app := gin.Default()被放在了顶层模块,并且加载了默认中间件
 
2. 程序真正的log在子模块中初始化
 
3. 在子模块中如何修改gin的日志?
 

解决办法

 
借助zapio.Writer对象,通过修改它的Log属性实现
 
# 顶层模块gin.go
gin.DefaultWriter =&zapio.Writer{Log:zap.L()}
gin.DefaultErrorWriter = gin.DefaultWriter
app := gin.Default()
app.use(xxx)


#子模块xxx/sim/http.go
if gl, ok := gin.DefaultWriter.(*zapio.Writer);ok{
    gl.Log = gs.log.Desugar()   #修改Log属性
}
 
 
 
 
 
 

Tags: gin
评论(221) 阅读(3775)

不见他过: 职场经验

2022年9月20日 22:39

 

一、什么是不见他过

 
1. 见如不见,视而不见,保护自己的心念,不被污染。
 
2. 好坏、善恶都是过眼云烟,不断在变化。
 
3. 好坏、善恶同样因人而异。一个对你很好,对另一个人可能会很坏。
 
“过”是无常的、相对的。而心灵至少会跟着自己几十年,污染了它,让生活过得不愉快,不值得。
 

二、个人看法

 
1. 上面的看法很对,没什么毛病
 
2. 真的所有情况都适合吗?一直存有疑问。
 

三、职场案例

 
1. 当我是个管理者,带着一个团队,达成某个目标。
 
2. 依据价值交换的原则管理团队
 
3. 当遇到了,有人甩锅、出工不出力,占着茅坑了。
 
4. 他违反了基本原则,已经从心理上把他排除团队了。另需要造势,把他从茅坑上弄走。
 
5. 这个时候,就不得不讲人过失了。
 
6. 这个做法对不对?会造成什么后果?
 

四、造成的后果

 
1. 虽然是按照原则处理的。然后事情传递后,会变味,影响个人前途。
 
2. 当事人也会用自己的影响力,以他的逻辑讲你的过失,会让你丢掉部分人心。
 
 

五、最佳做法

 
1. 只做不说,该排除就排除。
2. 缺少资源,直接找领导要。
 

六、总结

 
1. 底层员工。讲人过失,无非是受气了。人微言轻,很容易惹麻烦。
2. 中层管理。讲人过失,是为了造势,达成目的。同样有副作用。
3. 高层管理。讲人过失。容易让团队离心。
4. 是不是不能讲人过失,其实也不是
 
把每一次讲人过失,都当着要惹一次大祸。
有什么值得我冒这个大的险,我才会讲。
一般情况都不讲。
坚持这种心态N年之后,也许才会领会到“不见他过”更深层次的含义

评论(75) 阅读(4144)

viper监控文件变化出现两次事件

2022年9月17日 20:03

 
问题描述
 
监控配置文件变化,如果内容发生了修改,需要及时加载. 使用viper监控文件变化发现了, 对文件修改一次,会出发两次事件.
 

示例代码

 
viper.OnConfigChange(func(e fsnotify.Event) {
    if e.Op & fsnotify.Write != 0 {
        fmt.Println("Config file changed:", e.Name)
    }
})
viper.WatchConfig()
 

推测原因

 
* 检查viper的源码是否存在bug?
 
未发现异常
 
* 两次变化viper读到的内容返回值是否不一样? 
 
发现viper.AllKeys()返回值不一样, 一次为空, 一次正常.
 
* 换一个电脑试试?
 
发现了在公司办公电脑出现,家里电脑不会出现。
 

解决办法

 
//使用AllKeys进行过滤
viper.OnConfigChange(func(e fsnotify.Event) {
	if e.Op & fsnotify.Write != 0 && viper.AllKeys()>0{
		fmt.Println("Config file changed:", e.Name)
	}
})
viper.WatchConfig()
 
 

总结

 
公司的办公电脑安装了文件加密软件。我估摸着是它搞了个什么鬼.
 
 
 
 
 

Tags: viper golang
评论(233) 阅读(3623)

tomli支持数组混合类型

2022年8月05日 13:57

起因

    
    使用python的toml包解析toml配置文件。配置文件中使用了混合类型数组,结果程序报错。
 

原因与解决方法

 
1. toml0.5规范不支持数组混合类型, toml1.0规范才支持数组混合类型。
 
2. python的toml解析包有多种,toml包不支持1.0,所以不支持混合类型
 
3. 建议使用rtoml, tomli等
 

混合类型示例

 
a=[1, 2.1]
b=["a", ["b", "c"]]
c=["a", {"b": 1}]
 

rtoml用法

obj = rtoml.load("""
a=[1, 2.1]
""")
print(obj)
 

Tags: toml
评论(178) 阅读(3359)

gin支持prometheus

2022年8月03日 15:25

 

起因

 
gin使用了微服务架构, 如何将自己的服务都监控起来?
 

疑问列表

 
 
1. grafana是什么, 能做什么?
 
grafana是一个监控平台,支持不同数据源的可视化。也就是说支持从prometheuse,influxdb等数据源, 并将他们的数据形式可视化的图表.
 
2. prometheus能做什么?
prometheuse是一个监控系统,通过定时http pull采集数据. 并且支持http push.
 
3. prometheus和grafana是什么关系?
prometheuse是监控系统, 界面展示比较粗糙, grafana主要是可视化, 并且支持多种类型数据源。
 
4. gin如何与prometheuse结合?
见后面
 
5. gin如何与grafana?
grafana不支持直接接入gin服务。需要gin先接入prometheuse,再将prometheus接入grafana。
 
6. gin服务的metrics数据格式如何解析?
暂时未找到
 
7. gin自定义监控项
略. 不是本文主题
 
 

下载安装

 
grafana
https://github.com/grafana/grafana

prometheus
https://github.com/prometheus/prometheus
 

gin支持prometheuse

 
1. 修改gin服务代码
 
import (
    ...
"github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus/promhttp"
    ...
)


//metrics, promhttp默认可以查看cpu,mem,线程等信息
router.GET("/metrics", gin.WrapH(promhttp.Handler()))
 
2.修改prometheuse配置(prometheuse.yml)
 
scrape_configs:
  - job_name: "prometheus-demo"
    static_configs:
      - targets: ["192.168.28.26:8011"]
 
3. 启动服务
 
a. 启动gin和prometheuse服务后, 访问localhost:9090
 
b. 在"Expression"输入框选择"go_goroutines", 点击"Execute"
 
c. 刚开始数据比较少,可以过一段时间后再刷新页面
 
净土大经科注2014-doc
此生必看的科学实验-水知道答案
印光大师十念法(胡小林主讲第1集)
 

Tags: go prometheus
评论(21) 阅读(1153)

wikijs使用docker安装

2022年7月25日 11:32

 

描述

 
wikijs文档有docker-compose安装说明, 实际中会遇到几个问题
 

wikij官网

 
 

遇到问题

 
1. wikijs上传之后的问题如何备份?  需要将本地目录挂入docker, 并在wikijs存储中配置为上传路径.
 
2. docker volume如何备份与还原?  需要借助busybox镜像。如果直接从/var/lib/docker/volume目录拷贝会遇到很多问题.
 

修改之后的docker-compose.yaml

version: "3"
services:

  wikidb:
    image: postgres:11-alpine
    environment:
      POSTGRES_DB: wiki
      POSTGRES_PASSWORD: wikijsrocks
      POSTGRES_USER: wikijs
    logging:
      driver: "none"
    restart: unless-stopped
    volumes:
      - db-data:/var/lib/postgresql/data

  wiki:
    image: ghcr.io/requarks/wiki:2
    depends_on:
      - wikidb
    environment:
      DB_TYPE: postgres
      DB_HOST: wikidb
      DB_PORT: 5432
      DB_USER: wikijs
      DB_PASS: wikijsrocks
      DB_NAME: wiki
    restart: unless-stopped
    volumes:
      - ./backup:/opt/backup
    ports:
      - "80:3000"

volumes:
  db-data:
 

备份与还原

 
//备份
docker run --rm -it -v ~/volume-backup:/backup -v /var/lib/docker:/docker busybox tar cfz /backup/volume.tgz /docker/volumes/wikijs_db-data
//还原
docker run --rm -it -v /var/lib/docker:/docker -v ~/volume-backup/docker/volumes:/volume-backup busybox cp -rp /volume-backup/wikijs_db-data /docker/volumes
 

Tags: docker
评论(56) 阅读(1267)

golang实现枚举类型

2022年7月25日 10:50

描述

 
golang无枚举类型, 但可以借助自定义类型实现
 

什么是枚举类型

 
枚举类型是一种类型, 它的值只有有限个. 换而言之, 枚举类型=一个类型+N个离散值
 
go的实现, 可以自定义一个类型, 把它作为枚举类型, 然后使用该类型定义N个常量.
 
 

示例

 
type FormatType int

const (
    FTByte FormatType = iota
    FTArray
    FTDefine
)

func (ft FormatType) String() string {
    switch ft{
    case FTByte:
        return "byte"
    case FTArray:
        return "array"
    case FTDefine:
        return "define"
    }
    return ""
}
 
 

Tags: golang
评论(27) 阅读(952)