Go Web编程(十二——部署与维护)

原文作者:Go 技术论坛文档:《Go Web 编程()》
转自链接:https://learnku.com/docs/build-web-application-with-golang/4-form/3173

应用日志

GO语言中提供了一个简易的log包,我们使用该包可以方便的实现日志记录的功能。

这些日志都是基于fmt包的打印再结合panic之类的函数来进行一般的打印、抛出错误处理。

第三方开发的日志系统:logrus和seelog。

  • logrus

logrus是用Go语言实现的一个日志系统,与标准库log完全兼容并且核心API很稳定,是Go语言目前最活跃的日志库

安装logrus:

go get -u github.com/sirupsen/logrus

例:

package main
import (
	log "github.com/Sirupsen/logrus"
)
func main(){
    log.WithFields(logFields{
        "animal" : "walrus",
    }).Info("A walrus appears")
}

自定义日志处理:

package main

import (
    "os"

    log "github.com/Sirupsen/logrus"
)

func init() {
    // 日志格式化为 JSON 而不是默认的 ASCII
    log.SetFormatter(&log.JSONFormatter{})

    // 输出 stdout 而不是默认的 stderr,也可以是一个文件
    log.SetOutput(os.Stdout)

    // 只记录严重或以上警告
    log.SetLevel(log.WarnLevel)
}

func main() {
    log.WithFields(log.Fields{
        "animal": "walrus",
        "size":   10,
    }).Info("A group of walrus emerges from the ocean")

    log.WithFields(log.Fields{
        "omg":    true,
        "number": 122,
    }).Warn("The group's number increased tremendously!")

    log.WithFields(log.Fields{
        "omg":    true,
        "number": 100,
    }).Fatal("The ice breaks!")

    // 通过日志语句重用字段
    // logrus.Entry 返回自 WithFields()
    contextLogger := log.WithFields(log.Fields{
        "common": "this is a common field",
        "other":  "I also should be logged always",
    })

    contextLogger.Info("I'll be logged with common and other field")
    contextLogger.Info("Me too")
}
  • seelog介绍

seelog 是用 Go 语言实现的一个日志系统,它提供了一些简单的函数来实现复杂的日志分配、过滤和格式化。

安装seelog

go get -u github.com/cihub/seelog

例:

package main
import log "github.com/cihub/seelog"
func main(){
    defer log.Flush()
    log.Info("Hello from Seelog!")
}

编译后如果出现了hello from seelog,说明seelog日志系统以及成功安装并且可以正常运行了。

自定义日志处理:

package logs

import (
    // "errors"
    "fmt"
    // "io"

    seelog "github.com/cihub/seelog"
)

var Logger seelog.LoggerInterface

func loadAppConfig() {
    appConfig := `
<seelog minlevel="warn">
    <outputs formatid="common">
        <rollingfile type="size" filename="/data/logs/roll.log" maxsize="100000" maxrolls="5"/>
        <filter levels="critical">
            <file path="/data/logs/critical.log" formatid="critical"/>
            <smtp formatid="criticalemail" senderaddress="astaxie@gmail.com" sendername="ShortUrl API" hostname="smtp.gmail.com" hostport="587" username="mailusername" password="mailpassword">
                <recipient address="xiemengjun@gmail.com"/>
            </smtp>
        </filter>
    </outputs>
    <formats>
        <format id="common" format="%Date/%Time [%LEV] %Msg%n" />
        <format id="critical" format="%File %FullPath %Func %Msg%n" />
        <format id="criticalemail" format="Critical error on our server!\n    %Time %Date %RelFile %Func %Msg \nSent by Seelog"/>
    </formats>
</seelog>
`
    logger, err := seelog.LoggerFromConfigAsBytes([]byte(appConfig))
    if err != nil {
        fmt.Println(err)
        return
    }
    UseLogger(logger)
}

func init() {
    DisableLog()
    loadAppConfig()
}

// DisableLog disables all library log output
func DisableLog() {
    Logger = seelog.Disabled
}

// UseLogger uses a specified seelog.LoggerInterface to output library log.
// Use this func if you are using Seelog logging system in your app.
func UseLogger(newLogger seelog.LoggerInterface) {
    Logger = newLogger
}

网站错误处理

数据库错误:

​ 连接错误:可能是与数据库服务器网络断开、用户名密码不正确

​ 查询错误:SQL非法导致的错误

数据错误:数据库中的约束冲突,如一个唯一字段中插入一条重复主键的值就会报错

​ 应用运行时错误:

​ 文件系统和权限:应用读取不存在的文件或者没有权限的文件。应用读取的文件格式不正确。

​ 第三方应用:调用的第三方接口程序必须正常巡行

HTTP错误:这些错误是根据用户的请求出现的错,最常见的是404错误。

​ 操作系统出错:操作系统的资源被分配完了,导致死机,磁盘满了导致无法写入

​ 网络出错:网络连接断开

  • 错误处理的目标

通知访问用户出现错误、记录错误、回滚当前的请求操作、保证现有程序可运行可服务。

  • 如何处理错误

通知用户在访问页面时候我们可以有两种错误:404.html和error.html

    func (p *MyMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        if r.URL.Path == "/" {
            sayhelloName(w, r)
            return
        }
        NotFound404(w, r)
        return
    }

    func NotFound404(w http.ResponseWriter, r *http.Request) {
        log.Error("页面找不到")   // 记录错误日志
        t, _ = t.ParseFiles("tmpl/404.html", nil)  // 解析模板文件
        ErrorInfo := "文件找不到" // 获取当前用户信息
        t.Execute(w, ErrorInfo)  // 执行模板的 merger 操作
    }

    func SystemError(w http.ResponseWriter, r *http.Request) {
        log.Critical("系统错误")   // 系统错误触发了 Critical,那么不仅会记录日志还会发送邮件
        t, _ = t.ParseFiles("tmpl/error.html", nil)  // 解析模板文件
        ErrorInfo := "系统暂时不可用" // 获取当前用户信息
        t.Execute(w, ErrorInfo)  // 执行模板的 merger 操作
    }
  • 异常

程序的健壮性,在一些地方需要建立recover机制:

func GetUser(uid id)(username string){
    defer func(){
        if x:=recover();x!=nil {
            username=""
        }
    }()
    username = User[uid]
    return
}

如果你定义的函数有可能失败,它就应该返回一个错误。当我调用其他 package 的函数时,如果这个函数实现的很好,我不需要担心它会 panic,除非有真正的异常情况发生,即使那样也不应该是我去处理它。而 panic 和 recover 是针对自己开发 package 里面实现的逻辑,针对一些特殊情况来设计。

应用部署

针对Go的应用程序部署,我们可以利用第三方工具来管理,第三方的工具有很多,例如Supervisord、upstart、daemontools等。

  • Supervisord

安装:sudo easy_install supervisor安装。

Supervisord默认的配置文件路径为/etc/supervisord.conf

管理:supervisord,初始启动Supervisord

supervisorctl stop 停止某一个进程

supervisorctl start 启动某一个进程

supervisorctl stop all 停止全部进程

supervisorctl reload 载入最新的配置文件,并按新的配置启动、管理所有的进程。

备份和恢复

  • rsync
$ yum insall rsync

配置文就:rsyncd.conf(主配置文件)、rsyncd.secrets(密码文件)、rsyncd.motd(rsync服务器信息)。

服务端开启:

#/usr/bin/rsync --daemon  --config=/etc/rsyncd.conf
  • Mysql备份

主从复制:https://www.cnblogs.com/Gumi-o/p/14469529.html

mysql恢复(冷备):

mysql -u username -p databse < backup.sql
  • redis备份

分为两种:热备份和了备份,也支持master/slave模式。

冷备:定时把缓存数据保存到数据库文件里面。

  • redis恢复

redis的恢复分为热备份恢复和冷备份恢复,热备份只需要修改应用的相应的数据库连接即可。

冷备份只需要把保存的数据copy到redis的工作目录就可以了。

posted @ 2021-05-19 22:31  Gumi-21  阅读(180)  评论(0)    收藏  举报