Example #1
0
func (spool *spoolFile) getFileNumbering() (min int, max int) {
	min, max = maxSpoolFileNumber+1, 0
	files, _ := ioutil.ReadDir(spool.basePath)
	for _, file := range files {
		base := filepath.Base(file.Name())
		number, _ := shared.Btoi([]byte(base)) // Because we need leading zero support
		min = shared.MinI(min, int(number))
		max = shared.MaxI(max, int(number))
	}
	return min, max
}
Example #2
0
func (prod *File) getFileState(streamID core.MessageStreamID, forceRotate bool) (*fileState, error) {
	if state, stateExists := prod.filesByStream[streamID]; stateExists {
		if rotate, err := state.needsRotate(prod.rotate, forceRotate); !rotate {
			return state, err // ### return, already open or error ###
		}
	}

	var logFileName, fileDir, fileName, fileExt string

	if prod.wildcardPath {
		// Get state from filename (without timestamp, etc.)
		var streamName string
		switch streamID {
		case core.WildcardStreamID:
			streamName = "ALL"
		default:
			streamName = core.StreamRegistry.GetStreamName(streamID)
		}

		fileDir = strings.Replace(prod.fileDir, "*", streamName, -1)
		fileName = strings.Replace(prod.fileName, "*", streamName, -1)
		fileExt = strings.Replace(prod.fileExt, "*", streamName, -1)
	} else {
		// Simple case: only one file used
		fileDir = prod.fileDir
		fileName = prod.fileName
		fileExt = prod.fileExt
	}

	logFileBasePath := fmt.Sprintf("%s/%s%s", fileDir, fileName, fileExt)

	// Assure the file is correctly mapped
	state, stateExists := prod.files[logFileBasePath]
	if !stateExists {
		// state does not yet exist: create and map it
		state = newFileState(prod.batchMaxCount, prod.GetFormatter(), prod.Drop, prod.flushTimeout)
		prod.files[logFileBasePath] = state
		prod.filesByStream[streamID] = state
	} else if _, mappingExists := prod.filesByStream[streamID]; !mappingExists {
		// state exists but is not mapped: map it and see if we need to rotate
		prod.filesByStream[streamID] = state
		if rotate, err := state.needsRotate(prod.rotate, forceRotate); !rotate {
			return state, err // ### return, already open or error ###
		}
	}

	// Assure path is existing
	if err := os.MkdirAll(fileDir, 0755); err != nil {
		return nil, fmt.Errorf("Failed to create %s because of %s", fileDir, err.Error()) // ### return, missing directory ###
	}

	// Generate the log filename based on rotation, existing files, etc.
	if !prod.rotate.enabled {
		logFileName = fmt.Sprintf("%s%s", fileName, fileExt)
	} else {
		timestamp := time.Now().Format(prod.timestamp)
		signature := fmt.Sprintf("%s_%s", fileName, timestamp)
		maxSuffix := uint64(0)

		files, _ := ioutil.ReadDir(fileDir)
		for _, file := range files {
			if strings.HasPrefix(file.Name(), signature) {
				counter, _ := shared.Btoi([]byte(file.Name()[len(signature)+1:]))
				if maxSuffix <= counter {
					maxSuffix = counter + 1
				}
			}
		}

		if maxSuffix == 0 {
			logFileName = fmt.Sprintf("%s%s", signature, fileExt)
		} else {
			logFileName = fmt.Sprintf("%s_%d%s", signature, int(maxSuffix), fileExt)
		}
	}

	logFilePath := fmt.Sprintf("%s/%s", fileDir, logFileName)

	// Close existing log
	if state.file != nil {
		currentLog := state.file
		state.file = nil

		if prod.rotate.compress {
			go state.compressAndCloseLog(currentLog)
		} else {
			Log.Note.Print("Rotated ", currentLog.Name(), " -> ", logFilePath)
			currentLog.Close()
		}
	}

	// (Re)open logfile
	var err error
	openFlags := os.O_WRONLY | os.O_CREATE | os.O_APPEND
	if prod.overwriteFile {
		openFlags |= os.O_TRUNC
	} else {
		openFlags |= os.O_APPEND
	}

	state.file, err = os.OpenFile(logFilePath, openFlags, prod.permissions)
	if err != nil {
		return state, err // ### return error ###
	}

	// Create "current" symlink
	state.fileCreated = time.Now()
	if prod.rotate.enabled {
		symLinkName := fmt.Sprintf("%s/%s_current%s", fileDir, fileName, fileExt)
		os.Remove(symLinkName)
		os.Symlink(logFileName, symLinkName)
	}

	// Prune old logs if requested
	switch {
	case prod.pruneCount > 0 && prod.pruneSize > 0:
		go func() {
			state.pruneByCount(logFileBasePath, prod.pruneCount)
			state.pruneToSize(logFileBasePath, prod.pruneSize)
		}()

	case prod.pruneCount > 0:
		go state.pruneByCount(logFileBasePath, prod.pruneCount)

	case prod.pruneSize > 0:
		go state.pruneToSize(logFileBasePath, prod.pruneSize)
	}

	return state, err
}