func (prod *AwsS3) getFinalFileName(baseFileName string) string {
	fileExt := filepath.Ext(baseFileName)
	fileName := baseFileName[:len(baseFileName)-len(fileExt)]
	timestamp := time.Now().Format(prod.Rotate.Timestamp)
	signature := fmt.Sprintf("%s_%s", fileName, timestamp)
	return fmt.Sprintf("%s%s", signature, fileExt)
}
todo: introduce padding functionality (get list from aws)
package producer
import (
	"fmt"
	"path/filepath"
	"strings"
	"sync"
	"time"
	"gollum/core"
	"gollum/core/components"
	"gollum/producer/awss3"
	"github.com/aws/aws-sdk-go/service/s3"
)
const defaultAwsEndpoint = "s3.amazonaws.com"
type AwsS3 struct {
	core.DirectProducer `gollumdoc:"embed_type"`
	Rotate         components.RotateConfig        `gollumdoc:"embed_type"`
	AwsMultiClient components.AwsMultiClient      `gollumdoc:"embed_type"`
	BatchConfig    components.BatchedWriterConfig `gollumdoc:"embed_type"`
	bucket          string `config:"Bucket" default:""`
	fileNamePattern string `config:"File" default:"gollum_*.log"`
	filesByStream    map[core.MessageStreamID]*components.BatchedWriterAssembly
	files            map[string]*components.BatchedWriterAssembly
	hasWildcard      bool
	batchedFileGuard *sync.RWMutex
	s3Client         *s3.S3
}
func init() {
	core.TypeRegistry.Register(AwsS3{})
}
func (prod *AwsS3) Configure(conf core.PluginConfigReader) {
	prod.SetRollCallback(prod.rotateTargetFiles)
	prod.SetStopCallback(prod.close)
	prod.filesByStream = make(map[core.MessageStreamID]*components.BatchedWriterAssembly)
	prod.files = make(map[string]*components.BatchedWriterAssembly)
	prod.hasWildcard = strings.IndexByte(prod.fileNamePattern, '*') != -1
	prod.Rotate.Enabled = true  
	prod.batchedFileGuard = new(sync.RWMutex)
}
func (prod *AwsS3) Produce(workers *sync.WaitGroup) {
	prod.initS3Client()
	prod.AddMainWorker(workers)
	prod.TickerMessageControlLoop(prod.writeMessage, prod.BatchConfig.BatchTimeout, prod.writeBatchOnTimeOut)
}
func (prod *AwsS3) initS3Client() {
	sess, err := prod.AwsMultiClient.NewSessionWithOptions()
	if err != nil {
		prod.Logger.WithError(err).Error("Can't get proper aws config")
	}
	awsConfig := prod.AwsMultiClient.GetConfig()
	if awsConfig.Endpoint == nil || *awsConfig.Endpoint == "" {
		if *awsConfig.Region != components.DefaultAwsRegion {
			awsConfig.WithEndpoint(fmt.Sprintf("s3-%s.amazonaws.com", *awsConfig.Region))
		} else {
			awsConfig.WithEndpoint(defaultAwsEndpoint)
		}
	}
	prod.s3Client = s3.New(sess, awsConfig)
}
func (prod *AwsS3) getBatchedFile(streamID core.MessageStreamID, forceRotate bool) (*components.BatchedWriterAssembly, error) {
	prod.batchedFileGuard.RLock()
	batchedFile, fileExists := prod.filesByStream[streamID]
	prod.batchedFileGuard.RUnlock()
	if fileExists {
		if rotate, err := prod.needsRotate(batchedFile, forceRotate); !rotate {
			return batchedFile, err  
		}
	}
	prod.batchedFileGuard.Lock()
	defer prod.batchedFileGuard.Unlock()
	if batchedFile, fileExists = prod.filesByStream[streamID]; fileExists {
		if rotate, err := prod.needsRotate(batchedFile, forceRotate); !rotate {
			return batchedFile, err  
		}
	}
	baseFileName := prod.getBaseFileName(streamID)
	batchedFile, fileExists = prod.files[baseFileName]
	if !fileExists {
		batchedFile = components.NewBatchedWriterAssembly(
			prod.BatchConfig,
			prod,
			prod.TryFallback,
			prod.Logger,
		)
		prod.filesByStream[streamID] = batchedFile
		prod.files[baseFileName] = batchedFile
	}
	if batchedFile.HasWriter() {
		oldAwsWriter := batchedFile.GetWriterAndUnset()
		prod.Logger.Info("Rotated ", oldAwsWriter.Name(), " -> ", baseFileName)
		go oldAwsWriter.Close()  
	}
	writer := awss3.NewBatchedFileWriter(prod.s3Client, prod.bucket, prod.getFinalFileName(baseFileName), prod.Logger)
	batchedFile.SetWriter(&writer)
	return batchedFile, nil
}
func (prod *AwsS3) needsRotate(batchedFile *components.BatchedWriterAssembly, forceRotate bool) (bool, error) {
	if needUpload, err := batchedFile.NeedsRotate(prod.Rotate, forceRotate); needUpload {
		return true, err
	}
	writer, ok := batchedFile.GetWriter().(awss3.BatchedFileWriterInterface)
	if ok && writer.GetUploadCount() > 995 {
		prod.Logger.Debug("Rotate true: ", "upload count reached limit of 1000")
		return true, nil
	}
	return false, nil
}
func (prod *AwsS3) getBaseFileName(streamID core.MessageStreamID) string {
	if prod.hasWildcard {
		streamName := core.StreamRegistry.GetStreamName(streamID)
		return strings.Replace(prod.fileNamePattern, "*", streamName, -1)
	}
	return prod.fileNamePattern
}