github.com/igggame/nebulas-go@v2.1.0+incompatible/cmd/crashreporter/main.go (about)

     1  // Copyright (C) 2017 go-nebulas authors
     2  //
     3  // This file is part of the go-nebulas library.
     4  //
     5  // the go-nebulas library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // the go-nebulas library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU General Public License
    16  // along with the go-nebulas library.  If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  
    19  package main
    20  
    21  import (
    22  	"flag"
    23  	"fmt"
    24  	"io/ioutil"
    25  	"net"
    26  	"os"
    27  	"os/user"
    28  	"strconv"
    29  	"strings"
    30  	"syscall"
    31  	"time"
    32  
    33  	"bytes"
    34  	"crypto/md5"
    35  	"mime/multipart"
    36  	"net/http"
    37  
    38  	"path/filepath"
    39  
    40  	"github.com/VividCortex/godaemon"
    41  )
    42  
    43  func checkCrashFileAndUpload(fp string, url string) error {
    44  	if _, ferr := os.Stat(fp); ferr == nil {
    45  		bytes, err := ioutil.ReadFile(fp)
    46  		if err != nil {
    47  			return nil
    48  		}
    49  		lines := strings.Split(string(bytes), "\n")
    50  		current, err := user.Current()
    51  		for i, line := range lines {
    52  			line = strings.Replace(line, current.HomeDir, "HomeDir", -1)
    53  			line = strings.Replace(line, current.Name, "Name", -1)
    54  			line = strings.Replace(line, current.Username, "Username", -1)
    55  			lines[i] = line
    56  		}
    57  		output := strings.Join(lines, "\n")
    58  
    59  		// write crash log to file
    60  		dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
    61  		ioutil.WriteFile(fmt.Sprintf("%v/crash.log", dir), []byte(output), 0644)
    62  
    63  		// upload crash file content
    64  		return postFile([]byte(output), url)
    65  	}
    66  	fmt.Println("no crash yet")
    67  	return nil
    68  }
    69  
    70  func postFile(content []byte, targetURL string) error {
    71  	bodyBuf := &bytes.Buffer{}
    72  	bodyWriter := multipart.NewWriter(bodyBuf)
    73  
    74  	hash := md5.Sum(content)
    75  	filename := fmt.Sprintf("UTC-%d-%s.log", time.Now().UTC().Unix(), hash)
    76  
    77  	fileWriter, err := bodyWriter.CreateFormFile("uploadfile", filename)
    78  	if err != nil {
    79  		fmt.Println("error writing to buffer")
    80  		return err
    81  	}
    82  
    83  	_, err = fileWriter.Write(content)
    84  	if err != nil {
    85  		fmt.Println("error write content")
    86  		return err
    87  	}
    88  
    89  	contentType := bodyWriter.FormDataContentType()
    90  	bodyWriter.Close()
    91  
    92  	resp, err := http.Post(targetURL, contentType, bodyBuf)
    93  	if err != nil {
    94  		return err
    95  	}
    96  	defer resp.Body.Close()
    97  	_, err = ioutil.ReadAll(resp.Body)
    98  	if err != nil {
    99  		return err
   100  	}
   101  	return nil
   102  }
   103  
   104  func main() {
   105  	godaemon.MakeDaemon(&godaemon.DaemonAttr{})
   106  	logfp := flag.String("logfile", "", "log file path")
   107  	port := flag.Int("port", 0, "tcp port for notification")
   108  	code := flag.Int("code", 0, "verification code")
   109  	pid := flag.Int("pid", 0, "verification pid")
   110  	url := flag.String("url", "", "upload url")
   111  	flag.Parse()
   112  	s, err := net.Dial("tcp", fmt.Sprintf(":%d", *port))
   113  	if err != nil {
   114  		return
   115  	}
   116  
   117  	defer s.Close()
   118  
   119  	s.Write([]byte(strconv.Itoa(*code)))
   120  
   121  	ticker := time.NewTicker(1 * time.Second)
   122  	for _ = range ticker.C {
   123  		process, err := os.FindProcess(*pid)
   124  		if err != nil {
   125  			fmt.Printf("Failed to find process: %s\n", err)
   126  			checkCrashFileAndUpload(*logfp, *url)
   127  			return
   128  		}
   129  		err = process.Signal(syscall.Signal(0))
   130  		if err == nil {
   131  			continue
   132  		} else {
   133  			checkCrashFileAndUpload(*logfp, *url)
   134  			return
   135  		}
   136  	}
   137  }