오픈소스 프로젝트와 라이센스

오픈소스 프로젝트를 살펴보면, 각 코드 파일에 라이센스가 명시되어 있는 것을 볼 수 있습니다. 이 라이센스는 프로젝트에 사용된 코드의 사용 범위와 조건을 정의하여, 코드를 법적으로 보호하는 중요한 역할을 합니다. 라이센스를 각 코드 파일에 일일이 추가하는 작업은 번거로울 수 있습니다. 이러한 불편을 해소하기 위해 Google에서는 addlicense 도구를 제공하고 있으며, 이 도구를 사용하면 코드에 라이센스를 효율적으로 추가할 수 있습니다. 본 문서에서는 addlicense를 사용하여 Go 언어의 코드 파일에 라이센스를 추가하는 방법을 설명하겠습니다. 비록 예시는 Go 언어로 진행하지만, addlicense는 다양한 프로그래밍 언어에 적용 가능합니다.

 

이번 문서에서는 설치 방식의 사용법과 Docker Container 형식의 사용법에 대하여 정리하였습니다. 본인의 환경에 맞는 방법을 선택하여 진행하시면 됩니다.

 

addlicense 설치 방식의 사용법

Google에서 제공하는 addlicense 도구는 Go 언어로 개발되어 있습니다. 따라서 이 도구를 사용하기 전에는 Go 언어가 시스템에 설치되어 있어야 합니다. Go 언어가 이미 설치되어 있지 않다면, 사용하기 전에 반드시 Go 언어의 설치를 먼저 진행해야 합니다. Go 언어 설치는 공식 웹사이트에서 지원하는 안내에 따라 진행할 수 있습니다.

https://go.dev/doc/install

 

addlicense 설치

# addlicense 설치
go install github.com/google/addlicense@latest

 

addlicense 설치 확인

# 설치 확인
ls $(go env GOPATH)/bin
addlicense --help

 

addlicense 설치 확인 시 문제 발생한 경우

만약 command not found 발생 시 PATH를 추가합니다. (이미 추가되어있는 분은 수행하지 않습니다.)

# zsh: command not found: addlicense와 같은 문제가 발생할 경우 PATH에 go bin위치 추가
export PATH=$PATH:$(go env GOPATH)/bin

 

addlicense를 이용하여 라이센스 추가하기

프로젝트 디렉토리로 이동 후 실행

# addlicense 사용법 **로 모든 경로를 지정합니다.
addlicense -c '프로젝트명' -l apache ./**/*.go

 

addlicense 삭제

더 이상 addlicense가 필요 없을 경우 삭제하는 방법입니다.

# addlicense 삭제 방법
ls $(go env GOPATH)/bin
rm $(go env GOPATH)/bin/addlicense

 

Docker container 방식의 사용법

개발자로 근무하면서 다양한 도구와 라이브러리를 설치하고 관리하는 것은 종종 번거롭고 시간이 많이 소모되는 일입니다. 특히 설치한 프로그램을 나중에 제거할 때 발생하는 문제들로 인해 작업 효율이 떨어질 수 있습니다. 이러한 문제를 해결하기 위해 많은 개발자들이 설치와 설정, 실행을 간편화하는 방법으로 Container를 많이 사용하고 있습니다. Container를 사용하면 필요할 때만 특정 환경을 구성하고 작업이 끝나면 컨테이너를 간편하게 제거할 수 있습니다. 이번 섹션에서는 Docker 컨테이너를 사용하여 addlicense 도구를 실행하는 방법을 소개하겠습니다. 

 

도커 이미지 다운로드

docker pull ghcr.io/google/addlicense:latest

 

컨테이너로 실행

docker run -it -v ${PWD}:/src ghcr.io/google/addlicense -c "프로젝트명" **/*.go

 

결과  확인

아래 명령어로 수행한 결과 다음과 같이 라이센스가 추가되었습니다.

addlicense -c 'mytest' -l apache ./**/*.go

 

'Go언어' 카테고리의 다른 글

golang version upgrade (ubuntu)  (0) 2023.07.09
vscode golang debug  (0) 2023.07.07
go work 사용해보기  (0) 2023.07.06
Ubuntu(Linux)에서 Go 재설치  (0) 2022.10.30
Go언어 interface reflect  (0) 2021.08.15

ubuntu 환경에서 golang version upgrade를 하는 방법에 대하여 간단하게 정리하였습니다.

0. 작업 준비

# apt update를 진행합니다.
sudo apt-get update

# wget이 설치되었는지 확인합니다.
# 다음과 같은 결과가 나오면 wget이 설치된 것 입니다.
# /usr/bin/wget
which wget

# wget이 없다면 설치하여 줍니다.
sudo apt-get install wget

1. 기존 golang 제거

sudo rm -rf /usr/local/go

2. go 공식 사이트에서 새로운 go 버전 다운로드

아래 사이트로 접속하여 새로운 go 버전의 링크를 가져옵니다.

https://go.dev/dl/

 

All releases - The Go Programming Language

 

go.dev

 

사이트에 접속하여 아래 빨간 줄에 우클릭을 통하여 "링크 주소 복사"를 합니다.

 

wget을 통하여 새로운 go 버전은 다운로드합니다.

wget https://golang.org/dl/go1.XX.X.linux-amd64.tar.gz

3. 새로운 golang 설치

다운로드한 tar 파일 압축을 해제합니다.

sudo tar -C /usr/local -xzf go1.XX.X.linux-amd64.tar.gz

 

~/.profile에 다음과 같이 PATH를 추가합니다.

export PATH=$PATH:/usr/local/go/bin

 

~/.profile을 수정한 후 적용합니다.

source ~/.profile

 

정상적으로 설치 되었는지 확인합니다.

go version

 

'Go언어' 카테고리의 다른 글

[addlicense] golang 프로젝트에 라이센스 추가하기  (0) 2024.04.29
vscode golang debug  (0) 2023.07.07
go work 사용해보기  (0) 2023.07.06
Ubuntu(Linux)에서 Go 재설치  (0) 2022.10.30
Go언어 interface reflect  (0) 2021.08.15

요즘 code editor를 vscode로 변경하면서 debug환경에 대한 설정을 진행하였습니다. 이 글의 목적은 간단하게 go언어 디버깅 환경을 구축하며, vscode의 debug 단축키 및 사용법에 대한 내용을 정리하였습니다.

Extension 설치

환경 구성은 매우 간단합니다. vscode extension에서 "go"라고 검색하여 해당 extension을 설치합니다.

launch.json 구성

vscode에서 디버깅 환경을 구성하기 위해 launch.json 파일을 생성해야 됩니다. "ctrl + shift + d" 단축키를 통해 "Run and debug" 창을 띄울 수 있습니다. 해당 창에서 "create a launch.json file"을 클릭하여 launch.json 파일을 생성합니다. 파일을 생성하면 해당 경로에 "./.vscode/launch.json" 파일이 생성되며 저는 다음과 같이 내용을 구성했습니다.

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "my project",
            "type": "go",
            "request": "launch",
            "mode": "auto",
            "program": "${fileDirname}"
        }
    ]
}

디버깅 하기

내가 원하는 라인에 "F9"를 통해 브레이크 포인트를 지정하여 디버깅을 진행할 수 있습니다.

위 이미지를 보면 좌측에는 변수의 값을 확인할 수 있으며, 하단에는 콘솔로 출력되는 데이터를 확인할 수 있습니다. 이상 vscode에서 go언어 디버깅환경 만드는 과정에 대해 알아봤습니다.

브레이크 포인트에 expression 부여하기

브레이크 포인트에 특정 조건일 경우에만 디버깅을 하고 싶을 경우 해당 브레이크 포인트 우클릭에 "Edit breakpoint"를 클릭하여 다음과 같이 조건을 넣을 수 있습니다.

저는 i가 5일 경우에만 브레이크 포인트에 멈추도록 설정을 하여 많은 데이터를 분석할 때 유용하게 사용할 수 있습니다.

마지막으로

마지막으로 vscode의 디버깅 관련 단축키에 대해 알아보고 마치겠습니다.

  • F5 : 디버그 진행 / 디버그 중지
  • F10 : 다음 라인 실행
  • F11 : 메서드 내부로 진입
  • Shift + F11 : 메서드 빠져나오기
  • Ctrl + Shift + F5 : 재시작
  • Shift + F5 : 디버그 종료

더 자세한 내용은 다음 링크에서 확인하세요

https://github.com/golang/vscode-go/blob/master/docs/debugging.md

 

GitHub - golang/vscode-go: Go extension for Visual Studio Code

Go extension for Visual Studio Code. Contribute to golang/vscode-go development by creating an account on GitHub.

github.com

 

'Go언어' 카테고리의 다른 글

[addlicense] golang 프로젝트에 라이센스 추가하기  (0) 2024.04.29
golang version upgrade (ubuntu)  (0) 2023.07.09
go work 사용해보기  (0) 2023.07.06
Ubuntu(Linux)에서 Go 재설치  (0) 2022.10.30
Go언어 interface reflect  (0) 2021.08.15

go work를 사용하기 위해 반듯이 go1.18 이상의 go가 설치되어 있어야 합니다. go의 workspace는 회사에서 다른 개발자들과 협업을 하게 되면 모듈의 의존성에 대한 문제가 종종 발생하게 됩니다. 이럴 때 이러한 문제를 해결할 수 있는 것이 바로 go의 workspace입니다. 간단한 예시를 들자면 example이라는 모듈을 현재 회사에서 사용하고 있는데 example이라는 모듈에 기능을 추가하거나 기능을 변경할 경우 협업하고 있는 다른 개발자들에게 영향을 미치게 해서는 안 되는 경우가 있습니다. 이런 경우 "go work"를 통하여 다른 개발자들에게 영향을 미치지 않고 example 모듈을 수정하고 수정된 모듈을 이용하여 프로젝트 개발을 진행할 수 있습니다.

해당 글은 아래 링크 go document문서를 기반으로 똑같이 따라 하며 진행하였으며 개인적인 생각과 설명이 추가된 내용입니다. go work에 대한 원본 및 자세한 내용을 원하신다면 아래 공식 문서를 확인하거나 "$ go help work"를 통하여 보다 정확한 정보를 확인할 수 있습니다.

go workspace 링크 https://go.dev/doc/tutorial/workspaces

 

테스트 환경 구성하기

테스트를 진행할 수 있도록 환경을 구성합니다.

$ mkdir -r ~/workspace
$ cd ~/workspace

 

모듈 초기화하기
(hello라는 프로젝트를 생성합니다.)

$ mkdir hello
$ cd hello
$ go mod init example.com/hello

 

example 모듈 가져오기
(회사에서 사용하는 모듈이 example이라고 가정합니다.)

$ go get golang.org/x/example/hello/reverse

 

코드 작성하기

~/workspace/hello/hello.go 파일을 생성하고 다음과 같이 코드를 작성합니다.

package main

import (
    "fmt"

    "golang.org/x/example/hello/reverse"
)

func main() {
    fmt.Println(reverse.String("Hello"))
}

 

작성된 코드를 실행시켜 모듈이 잘 적용된 것을 확인해 봅시다.

$ cd ~/workspace/hello
$ go run example.com/hello

# 결과 #
olleH

 

workspace 생성하기

go work 명령어를 이용하여 workspace를 생성합니다. (작업 디렉토리는 ~/workspace입니다.)

$ cd ~/workspace
$ go work init ./hello

 

위 명령어를 수행하게 되면 다음과 같이 go.work파일이 생성됩니다. 참고로 저는 go1.20를 사용하고 있습니다.

go 1.20

use ./hello

 

모듈 다운받아 작업 진행하기

이제는 협업하는 다른 개발자들에게 모듈을 수정해도 영향을 미치지 않도록 모듈을 다운받아 모듈을 수정하는 작업을 진행할 예정입니다.
저장소 복제하기 (작업 디렉토리는 ~/workspace입니다.)

$ cd ~/workspace
$ git clone https://go.googlesource.com/example

 

workspace에 모듈 추가하기

$ go work use ./example/hello

 

위 작업을 진행하면 go.work파일이 다음과 같이 수정됩니다.

go 1.20

use (
    ./hello
    ./example/hello
)

 

모듈 수정 작업 진행하기

~/workspace/example/hello/reverse에 int.go라는 파일을 생성하여 다음과 같이 코드를 작성합니다.

package reverse

import "strconv"

// Int returns the decimal reversal of the integer i.
func Int(i int) int {
    i, _ = strconv.Atoi(String(strconv.Itoa(i)))
    return i
}

 

~/workspace/hello/hello.go 파일에 수정된 모듈을 적용합니다.

package main

import (
    "fmt"

    "golang.org/x/example/hello/reverse"
)

func main() {
    fmt.Println(reverse.String("Hello"), reverse.Int(24601))
}

 

수정된 코드를 실행하여 수정된 모듈이 적용된 것을 확인할 수 있습니다.

$ go run ./hello
olleH 10642

지금까지 같이 협업하는 개발자들에게 모듈 수정으로 영향을 미치지 않고 모듈을 수정하여 개발을 진행하도록 하는 workspace에 대하여 알아봤습니다.

 

마지막으로

개발을 완료하고 협업하고 있는 모든 개발자들이 github에 push 하고 merge 작업을 진행할 때 반듯이 go.work 파일이 있다면 버전을 확인 후 작업을 진행한 개발자들과 패키지 버전에 대한 논의를 진행 후 merge 작업을 진행해야 build 과정에서 패키지 버전에 대한 이슈를 예방할 수 있습니다.

'Go언어' 카테고리의 다른 글

golang version upgrade (ubuntu)  (0) 2023.07.09
vscode golang debug  (0) 2023.07.07
Ubuntu(Linux)에서 Go 재설치  (0) 2022.10.30
Go언어 interface reflect  (0) 2021.08.15
Go언어 Cron  (0) 2021.06.15

Go언어 처음 설치라면 2번부터 진행하시면 됩니다.

1. Go 제거하기

# go언어 제거 하기
sudo apt-get purge golang*
sudo rm -rf /usr/local/go
sudo rm -rf $(echo $GOPATH)

# ~/bashrc 또는 ~/.profile에서 go 관련된 항목 제거(기존에 설정한 파일에서 작업)
source ~/.profile
source ~/.bashrc

# 제거 확인
go version

 

2. apt-get 업데이트 하기

sudo apt-get update
sudo apt-get -y upgrade

 

3. wget 설치 확인 및 wget 설치

# wget 설치 확인 & wget 없을 경우 wget 설치
which wget
sudo apt-get install wget

 

4. Go 최신 버전 설치하기

https://go.dev/dl/

 

Downloads - The Go Programming Language

Downloads After downloading a binary release suitable for your system, please follow the installation instructions. If you are building from source, follow the source installation instructions. See the release history for more information about Go releases

go.dev

 

위 링크에서 최신 버전(현재 최신 버전은 1.19.2)의 linux-amd64.tar.gz에 우클릭하여 링크 주소를 복사하고 wget으로 다운로드합니다.

# go 다운로드
wget https://golang.org/dl/go1.19.2.linux-amd64.tar.gz

# 압축 풀기
sudo tar -C /usr/local -xvf go1.19.2.linux-amd64.tar.gz

# 환경변수 설정
mkdir ~/go
echo "export GOROOT=/usr/local/go" >> ~/.profile
echo "export PATH=$PATH:/usr/local/go/bin" >> ~/.profile
echo "export GOPATH=$HOME/go" >> ~/.profile
source ~/.profile
echo $GOPATH

# go version 확인하기
go version

 

 

 

 

 

'Go언어' 카테고리의 다른 글

vscode golang debug  (0) 2023.07.07
go work 사용해보기  (0) 2023.07.06
Go언어 interface reflect  (0) 2021.08.15
Go언어 Cron  (0) 2021.06.15
Prometheus Go언어 Metric label  (0) 2021.06.14

reflect 사용 이유

reflect는 여러 가지의 사용방법이 있겠지만 저는 종종 협업을 하면서 상대방이 보낸 데이터의 타입 및 종류에 대하여 구분이 필요한 경우 사용하였습니다. 

 

reflect를 이용하여 타입 가져오기

인터페이스 형식으로 데이터를 받아 받은 데이터의 타입을 구분할 수 있습니다.

package main

import (
	"fmt"
	"reflect"
)

func ShowType(i interface{}) {
	fmt.Println(reflect.ValueOf(i).Type())
}

func main() {
	num := 100
	ShowType(num)

	job := "student"
	ShowType(job)
}
/* 출력결과
int
string
*/

코드설명

reflect.ValueOf().Type()을 사용하여 해당 타입이 어떤 타입인지 알 수 있습니다.

 

reflect를 이용하여 구조체 멤버 변수 확인하기

reflect를 사용하여 인터페이스로 받은 구조체의 멤버 변수들을 확인하도록 하겠습니다. 여기서 중요한 건 멤버 변수가 없는 일반 변수의 인터페이스를 넘기면 panic이 발생합니다.

package main

import (
	"fmt"
	"reflect"
)

type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
	Job  string `json:"job"`
}

func (p Person) Print() {
	fmt.Println(p.Name, " is ", p.Job)
}

func ShowMetaData(i interface{}) {
	elements := reflect.ValueOf(i).Elem()

	for index := 0; index < elements.NumField(); index++ {
		typeField := elements.Type().Field(index)
		fmt.Println(typeField.Name, typeField.Type, typeField.Tag, elements.Field(index))
	}
}

func main() {
	p := &Person{
		Name: "Han",
		Age:  30,
		Job:  "Developer",
	}
	ShowMetaData(p)

	// panic 발생
	//num := 100
	//ShowMetaData(num)
}

/* 출력결과
Name string json:"name" Han
Age int json:"age" 30
Job string json:"job" Developer
*/

코드설명

ShowMetaData() 함수를 보면 interface의 value를 reflect.Value().Elem()을 통하여 elements들을 가져옵니다. 그리고 

elements.Type().Field()를 통하여 현재 필드의 데이터를 StructField형식으로 가져올 수 있습니다. StructField의 구조는 다음과 같습니다.

 

StructField의 구조

// A StructField describes a single field in a struct.
type StructField struct {
	// Name is the field name.
	Name string
	// PkgPath is the package path that qualifies a lower case (unexported)
	// field name. It is empty for upper case (exported) field names.
	// See https://golang.org/ref/spec#Uniqueness_of_identifiers
	PkgPath string

	Type      Type      // field type
	Tag       StructTag // field tag string
	Offset    uintptr   // offset within struct, in bytes
	Index     []int     // index sequence for Type.FieldByIndex
	Anonymous bool      // is an embedded field
}

Name : 구조체 멤버 변수의 이름

Type : 구조체 맴버변수의 타입

Tag : 구조체 맴버변수의 태그

Offset : 구조체 멤버 변수의 오프셋(맴버변수의 메모리 위치)

Index : 구조체 맴버변수의 선언 순서

 

reflect를 이용하여 멤버 변수 가져오기

package main

import (
	"fmt"
	"reflect"
)

type Person struct {
	Name   string `json:"name"`
	Age    int    `json:"age"`
	Job    string `json:"job"`
	Salary int    `json:"salary"`
}

func (p Person) Print() {
	fmt.Println(p.Name, " is ", p.Job)
}

func (p *Person) SetSalary(salary int) {
	p.Salary = salary
}

func (p Person) GetName() string {
	return p.Name
}

func ShowMethod(i interface{}) {
	value := reflect.ValueOf(i)

	for index := 0; index < value.NumMethod(); index++ {
		fmt.Printf("method name : %s\n", value.Type().Method(index).Name) // 1번
		fmt.Printf("method type : %v\n\n", value.Method(index).Type()) // 2번
	}
}

func main() {
	p := &Person{
		Name: "Han",
		Age:  30,
		Job:  "Developer",
	}
	ShowMethod(p)
}

/* 출력결과
method name : GetName
method type : func() string

method name : Print
method type : func()

method name : SetSalary
method type : func(int)
*/

코드설명

1번 주석을 보면 Type().Method()를 통하여 구조체의 메서드의 타입을 가져올 수 있습니다. 가져온 메서드 타입으로 메서드 명을 가져올 수 있습니다.

2번 주석을 보면 Method().Type()을 통해 실제 메서드의 구성을 알 수 있습니다.

 

 

'Go언어' 카테고리의 다른 글

go work 사용해보기  (0) 2023.07.06
Ubuntu(Linux)에서 Go 재설치  (0) 2022.10.30
Go언어 Cron  (0) 2021.06.15
Prometheus Go언어 Metric label  (0) 2021.06.14
Prometheus Go언어 Metric 생성  (0) 2021.06.13

Cron이란

우리는 살면서 종종 정해진 시간에 정해진 일이 자동으로 수행되었으면 하는 일들이 많이 있습니다. Go언어에서는 이러한 일을 cron이 해결해 줍니다.

 

먼저 프로젝트 디렉토리에서 다음 명령어로 모듈을 가져옵니다.

 > go get github.com/robfig/cron
package main

import (
    "fmt"
    "github.com/robfig/cron"
    "time"
)

const (
    CronSpec = "30 * * * * *"
)

var (
    Data int
)

func PrintData() {
    t := time.Now().Format(time.ANSIC)
    fmt.Println(t, " : ", Data)
    Data++
}

func main() {
    c := cron.New()
    c.AddFunc(CronSpec, PrintData)
    c.Start()

    time.Sleep(time.Minute * 10)
    c.Stop()
}
/* 출력결과
Tue Jun 15 15:15:30 2021  :  0
Tue Jun 15 15:16:30 2021  :  1
Tue Jun 15 15:17:30 2021  :  2
*/

코드설명

cron.New()를 통하여 cron을 생성하고 AddFunc()를 통해 동작할 시간대와 동작할 함수를 등록합니다. "30 * * * * *"을 cron 시간으로 등록하였습니다. 이것은 출력결과를 보면 알 수 있듯이 매시간 매분 30초 일때 마다 함수가 동작합니다.

 

Cron Spec 구조

CronSpec을 "30 * * * * *"로 설정하였습니다. 여기서 많이 착가할 수 있는 부분이 30초 마다 동작을 수행하는 것으로 오해할 수 있습니다. 그러나 이것은 매 시간 매분 30초가 되었을 경우 수행하는 것을 의미합니다. 이제 Cron spec에 구조에 대하여 알아보겠습니다.

가장 왼쪽 부터 초, 분, 시, 일, 월, 요일 로 구성되어 있습니다.

Seconds Minute Hour Day of month Month Week
0 ~ 59 0 ~ 59 0 ~ 23 1 ~ 31 1 ~ 12 0 ~ 6

예제

"0 0 0 * * *" : 매일 0시 0분 0초에 수행합니다.

"0 0 0 1 1 *" : 1월 1일 0시 0분 0초에 수행합니다.

 

Cron Spec에서 사용되는 문자

별표 *

별표는 눈치채셨겠지만 모든 값을 뜻합니다.

 

콤마 ,

콤마는 해당 spec에 여러개의 값을 설정하는데 사용합니다. "10,20,30 * * * * *" 이렇게 설정을 한다면 매시 매분 10초, 20초, 30초 일때 수행합니다.

 

마이너스 -

마이너스는 값의 범위를 지정합니다. "10-15 * * * * *"일 경우 매시 매분 10초 11초 12초 13초 14초 15초 에 수행합니다.

 

슬래쉬 /

슬래쉬의 경우 해당 범위에서 수행하는 간격을 의미 합니다. "10-50/5 * * * * *" 일 경우 매시 매분에서 10초에서 50초 사이에 5초에 한번씩 수행합니다.

 

'Go언어' 카테고리의 다른 글

go work 사용해보기  (0) 2023.07.06
Ubuntu(Linux)에서 Go 재설치  (0) 2022.10.30
Go언어 interface reflect  (0) 2021.08.15
Prometheus Go언어 Metric label  (0) 2021.06.14
Prometheus Go언어 Metric 생성  (0) 2021.06.13

Label이란

Label이란 메트릭에 Key-Value형식으로 Metric을 구분하는데 많이 사용된다. Kubernetes에서는 Pod, Node, Cluster, 또는 Application 등을 Metric에서 구분하는데 많이 사용된다.

 

Go언어 Metric에 Label 등록하기

package main

import (
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"net/http"
	"time"
)

const (
	LabelAppName = "application_name"
	LabelFuncName = "function_name"
)

var (
	MyCounter *prometheus.CounterVec
)

func Init() {
	MyCounter = promauto.NewCounterVec(prometheus.CounterOpts{
		Name: "my_test_count",
		Help: "my test count",
	},[]string{
		LabelAppName,
		LabelFuncName,
	})
}

func RunFunc1() {
	labels := prometheus.Labels{
		LabelAppName: "my_app",
		LabelFuncName: "run_func1",
	}

	for {
		MyCounter.With(labels).Inc()
		time.Sleep(time.Second * 2)
	}
}

func RunFunc2() {
	labels := prometheus.Labels{
		LabelAppName: "my_app",
		LabelFuncName: "run_func2",
	}

	for {
		MyCounter.With(labels).Inc()
		time.Sleep(time.Second * 5)
	}
}

func main() {
	Init()
	go RunFunc1()
	go RunFunc2()

	http.Handle("/metrics", promhttp.Handler())
	http.ListenAndServe(":30001", nil)
}

코드설명

기존 Metric의 코드와 크게 다르지 않다. prometheus.CounterVec를 통하여 메트릭을 생성하고 메트릭을 생성할 때 상수로 선언된 LabelAppName, LabelFuncName을 통하여 application_name, function_name이라는 Label을 등록하였습니다. 그리고 각각의 RunFunc1(), RunFunc2() 함수로 각각 별도의 function_name의 Label을 등록하였습니다.

Promql로 구분하여 검색하기

기존처럼 Metric 이름으로 검색하면 run_func1, run_func2가 모두 검색됩니다.

my_test_count

Label에 run_func1을 지정하여 특정 Label의 Metric을 검색하면 run_func1만 검색됩니다.

my_test_count{function_name="run_func1"}

 

결과 확인하기

 

'Go언어' 카테고리의 다른 글

go work 사용해보기  (0) 2023.07.06
Ubuntu(Linux)에서 Go 재설치  (0) 2022.10.30
Go언어 interface reflect  (0) 2021.08.15
Go언어 Cron  (0) 2021.06.15
Prometheus Go언어 Metric 생성  (0) 2021.06.13

Prometheus Metric Type

Counter 카운터

Counter는 개수를 측정하거나 증가하는 값을 측정할 때 사용합니다. 카운터는 0으로 초기화는 가능하지만 값을 감소할 수 없고 증가만 할 수 있습니다. 대표적으로 함수 호출 횟수 및 접속 요청 수, 실패 개수를 측정할 때 많이 사용할 수 있습니다.

 

Gauge 게이지

Gauge는 현재의 값을 나타내는 데 사용합니다. 값이 증가할 수 있으며 감소할 수도 있습니다. 증가 감소 모두 가능하다 보니 여러 방면에서 사용할 수 있습니다. 대표적으로 현재 메모리 사용량, CPU 사용 시간, 저장된 데이터의 수, 스레드 개수 등 여러 방면에서 사용합니다.

 

Summary 서머리

Summary는 _count, _sum을 제공하여 평균을 측정할 수 있으며, 슬라이딩 시간 윈도우를 측정할 때 사용합니다.

 

Histogram 히스토그램

Histogram은 시간 동안의 값을 측정하고 측정한 값을 통하여 quantile을 측정할 수 있습니다.

 

Go언어로 Metric 생성하기

먼저 다음 명령으로 모듈을 받습니다.

go get github.com/prometheus/client_golang/prometheus
go get github.com/prometheus/client_golang/prometheus/promauto
go get github.com/prometheus/client_golang/prometheus/promhttp

 

Counter 생성하기

package main

import (
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"net/http"
	"time"
)

var (
	MyCounter prometheus.Counter
)

func Init() {
	MyCounter = promauto.NewCounter(prometheus.CounterOpts{
		Name: "my_test_count",
		Help: "my test count",
	})
}

func RunCounter() {
	for i := 0; ; i++ {
		MyCounter.Inc()
		//MyCounter.Add(10)
		time.Sleep(time.Second * 2)
	}
}

func main() {
	Init()
	go RunCounter()

	http.Handle("/metrics", promhttp.Handler())
	http.ListenAndServe(":30001", nil)
}

코드설명

promauto.NewCounter를 통하여 카운터를 생성하고 카운터의 이름을 my_test_count로 만들었다. 카운터는 2초에 한 번씩 MyCounter.Inc()를 통하여 1씩 증가하고 있다. MyCounter.Add()를 이용하면 1 이상의 값을 증가시킬 수도 있다.

 

확인하기

Gauge 생성하기

package main

import (
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"net/http"
	"time"
)

var (
	MyGauge prometheus.Gauge
)

func Init() {
	MyGauge = promauto.NewGauge(prometheus.GaugeOpts{
		Name: "my_test_gauge",
		Help: "my test gauge",
	})
}

func RunGauge() {
	for i := 0; ; i++ {
		MyGauge.Set(float64(i))
		time.Sleep(time.Second * 2)
	}
}

func main() {
	Init()
	go RunGauge()

	http.Handle("/metrics", promhttp.Handler())
	http.ListenAndServe(":30001", nil)
}

코드설명

promauto.NewGauge를 통하여 my_test_gauge를 생성하였습니다. 2초마다 i의 값으로 gauge값을 세팅합니다.

 

 

Summary 생성하기

package main

import (
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"math/rand"
	"net/http"
	"time"
)

var (
	MySummary prometheus.Summary
)

func Init() {
	MySummary = promauto.NewSummary(prometheus.SummaryOpts{
		Name: "my_test_summary",
		Help: "my test summary",
	})
}

func RunSummary() {
	for {
		MySummary.Observe(float64(rand.Int63n(10)))
		time.Sleep(time.Second * 2)
	}
}

func main() {
	Init()
	go RunSummary()

	http.Handle("/metrics", promhttp.Handler())
	http.ListenAndServe(":30001", nil)
}

코드설명

promauto.NewSummary를 통하여 my_test_summary를 생성하고 2초마다 0 ~ 10까지의 난수로 Observe를 통하여 값을 등록합니다.

 

확인하기

 

Histogram 생성하기

package main

import (
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"math/rand"
	"net/http"
	"time"
)

var (
	MyHistogram prometheus.Histogram
)

func Init() {
	MyHistogram = promauto.NewHistogram(prometheus.HistogramOpts{
		Name: "my_test_histogram",
		Help: "my test histogram",
	})
}

func RunHistogram() {
	for {
		MyHistogram.Observe(rand.Float64())
		time.Sleep(time.Second * 2)
	}
}

func main() {
	Init()
	go RunHistogram()

	http.Handle("/metrics", promhttp.Handler())
	http.ListenAndServe(":30001", nil)
}

코드설명

역시나 promauto.NewHistogram을 통해 생성합니다. 2초마다 난수를 등록합니다.

 

확인하기

다른 방식의 Metric 생성

지금까지 promauto를 통하여 Metric을 생성했습니다. 그러나 promauto를 사용하지 않고 다른 방식으로 Metric을 생성하는 방법을 알아보겠습니다.

package main

import (
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"net/http"
	"time"
)

var (
	MyCounter prometheus.Counter
)

func Init() {
	MyCounter = prometheus.NewCounter(prometheus.CounterOpts{
		Name: "my_test_count",
		Help: "my test count",
	})
}

func RunFunc() {
	for {
		MyCounter.Inc()
		time.Sleep(time.Second * 2)
	}
}

func main() {
	Init()
	prometheus.MustRegister(MyCounter)

	go RunFunc()

	http.Handle("/metrics", promhttp.Handler())
	http.ListenAndServe(":30001", nil)
}

코드설명

promauto.NewCounter가 아닌 prometheus.NewCounter를 통하여 Metric을 생성했습니다. promauto를 사용하지 않으면 prometheus.MustRegister를 통하여 Collector를 등록해야 됩니다.

 

 

'Go언어' 카테고리의 다른 글

go work 사용해보기  (0) 2023.07.06
Ubuntu(Linux)에서 Go 재설치  (0) 2022.10.30
Go언어 interface reflect  (0) 2021.08.15
Go언어 Cron  (0) 2021.06.15
Prometheus Go언어 Metric label  (0) 2021.06.14

+ Recent posts