You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							157 lines
						
					
					
						
							3.9 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							157 lines
						
					
					
						
							3.9 KiB
						
					
					
				
								// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/
							 | 
						|
								//
							 | 
						|
								// Copyright 2013 Google Inc. All Rights Reserved.
							 | 
						|
								//
							 | 
						|
								// Licensed under the Apache License, Version 2.0 (the "License");
							 | 
						|
								// you may not use this file except in compliance with the License.
							 | 
						|
								// You may obtain a copy of the License at
							 | 
						|
								//
							 | 
						|
								//     http://www.apache.org/licenses/LICENSE-2.0
							 | 
						|
								//
							 | 
						|
								// Unless required by applicable law or agreed to in writing, software
							 | 
						|
								// distributed under the License is distributed on an "AS IS" BASIS,
							 | 
						|
								// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
							 | 
						|
								// See the License for the specific language governing permissions and
							 | 
						|
								// limitations under the License.
							 | 
						|
								
							 | 
						|
								// File I/O for logs.
							 | 
						|
								
							 | 
						|
								package glog
							 | 
						|
								
							 | 
						|
								import (
							 | 
						|
									"errors"
							 | 
						|
									"fmt"
							 | 
						|
									flag "github.com/seaweedfs/seaweedfs/weed/util/fla9"
							 | 
						|
									"os"
							 | 
						|
									"os/user"
							 | 
						|
									"path/filepath"
							 | 
						|
									"sort"
							 | 
						|
									"strings"
							 | 
						|
									"sync"
							 | 
						|
									"time"
							 | 
						|
								)
							 | 
						|
								
							 | 
						|
								// MaxSize is the maximum size of a log file in bytes.
							 | 
						|
								var MaxSize uint64 = 1024 * 1024 * 1800
							 | 
						|
								var MaxFileCount = 5
							 | 
						|
								
							 | 
						|
								// logDirs lists the candidate directories for new log files.
							 | 
						|
								var logDirs []string
							 | 
						|
								
							 | 
						|
								// If non-empty, overrides the choice of directory in which to write logs.
							 | 
						|
								// See createLogDirs for the full list of possible destinations.
							 | 
						|
								var logDir = flag.String("logdir", "", "If non-empty, write log files in this directory")
							 | 
						|
								
							 | 
						|
								func createLogDirs() {
							 | 
						|
									if *logDir != "" {
							 | 
						|
										logDirs = append(logDirs, *logDir)
							 | 
						|
									} else {
							 | 
						|
										logDirs = append(logDirs, os.TempDir())
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								var (
							 | 
						|
									pid      = os.Getpid()
							 | 
						|
									program  = filepath.Base(os.Args[0])
							 | 
						|
									host     = "unknownhost"
							 | 
						|
									userName = "unknownuser"
							 | 
						|
								)
							 | 
						|
								
							 | 
						|
								func init() {
							 | 
						|
									h, err := os.Hostname()
							 | 
						|
									if err == nil {
							 | 
						|
										host = shortHostname(h)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									current, err := user.Current()
							 | 
						|
									if err == nil {
							 | 
						|
										userName = current.Username
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Sanitize userName since it may contain filepath separators on Windows.
							 | 
						|
									userName = strings.Replace(userName, `\`, "_", -1)
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// shortHostname returns its argument, truncating at the first period.
							 | 
						|
								// For instance, given "www.google.com" it returns "www".
							 | 
						|
								func shortHostname(hostname string) string {
							 | 
						|
									if i := strings.Index(hostname, "."); i >= 0 {
							 | 
						|
										return hostname[:i]
							 | 
						|
									}
							 | 
						|
									return hostname
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// logName returns a new log file name containing tag, with start time t, and
							 | 
						|
								// the name for the symlink for tag.
							 | 
						|
								func logName(tag string, t time.Time) (name, link string) {
							 | 
						|
									name = fmt.Sprintf("%s.%s.%s.log.%s.%04d%02d%02d-%02d%02d%02d.%d",
							 | 
						|
										program,
							 | 
						|
										host,
							 | 
						|
										userName,
							 | 
						|
										tag,
							 | 
						|
										t.Year(),
							 | 
						|
										t.Month(),
							 | 
						|
										t.Day(),
							 | 
						|
										t.Hour(),
							 | 
						|
										t.Minute(),
							 | 
						|
										t.Second(),
							 | 
						|
										pid)
							 | 
						|
									return name, program + "." + tag
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func prefix(tag string) string {
							 | 
						|
									return fmt.Sprintf("%s.%s.%s.log.%s.",
							 | 
						|
										program,
							 | 
						|
										host,
							 | 
						|
										userName,
							 | 
						|
										tag,
							 | 
						|
									)
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								var onceLogDirs sync.Once
							 | 
						|
								
							 | 
						|
								// create creates a new log file and returns the file and its filename, which
							 | 
						|
								// contains tag ("INFO", "FATAL", etc.) and t.  If the file is created
							 | 
						|
								// successfully, create also attempts to update the symlink for that tag, ignoring
							 | 
						|
								// errors.
							 | 
						|
								func create(tag string, t time.Time) (f *os.File, filename string, err error) {
							 | 
						|
									onceLogDirs.Do(createLogDirs)
							 | 
						|
									if len(logDirs) == 0 {
							 | 
						|
										return nil, "", errors.New("log: no log dirs")
							 | 
						|
									}
							 | 
						|
									name, link := logName(tag, t)
							 | 
						|
									logPrefix := prefix(tag)
							 | 
						|
									var lastErr error
							 | 
						|
									for _, dir := range logDirs {
							 | 
						|
								
							 | 
						|
										// remove old logs
							 | 
						|
										entries, _ := os.ReadDir(dir)
							 | 
						|
										var previousLogs []string
							 | 
						|
										for _, entry := range entries {
							 | 
						|
											if strings.HasPrefix(entry.Name(), logPrefix) {
							 | 
						|
												previousLogs = append(previousLogs, entry.Name())
							 | 
						|
											}
							 | 
						|
										}
							 | 
						|
										if len(previousLogs) >= MaxFileCount {
							 | 
						|
											sort.Strings(previousLogs)
							 | 
						|
											for i, entry := range previousLogs {
							 | 
						|
												if i > len(previousLogs)-MaxFileCount {
							 | 
						|
													break
							 | 
						|
												}
							 | 
						|
												os.Remove(filepath.Join(dir, entry))
							 | 
						|
											}
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// create new log file
							 | 
						|
										fname := filepath.Join(dir, name)
							 | 
						|
										f, err := os.Create(fname)
							 | 
						|
										if err == nil {
							 | 
						|
											symlink := filepath.Join(dir, link)
							 | 
						|
											os.Remove(symlink)        // ignore err
							 | 
						|
											os.Symlink(name, symlink) // ignore err
							 | 
						|
											return f, fname, nil
							 | 
						|
										}
							 | 
						|
										lastErr = err
							 | 
						|
									}
							 | 
						|
									return nil, "", fmt.Errorf("log: cannot create log: %w", lastErr)
							 | 
						|
								}
							 |