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.
		
		
		
		
		
			
		
			
				
					
					
						
							138 lines
						
					
					
						
							4.4 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							138 lines
						
					
					
						
							4.4 KiB
						
					
					
				| package command | |
| 
 | |
| import ( | |
| 	"fmt" | |
| 	"github.com/seaweedfs/seaweedfs/weed/filer" | |
| 	"github.com/seaweedfs/seaweedfs/weed/pb" | |
| 	"os" | |
| 	"path/filepath" | |
| 	"strings" | |
| 	"time" | |
| 
 | |
| 	"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb" | |
| 	"github.com/seaweedfs/seaweedfs/weed/security" | |
| 	"github.com/seaweedfs/seaweedfs/weed/util" | |
| ) | |
| 
 | |
| func init() { | |
| 	cmdFilerMetaTail.Run = runFilerMetaTail // break init cycle | |
| } | |
| 
 | |
| var cmdFilerMetaTail = &Command{ | |
| 	UsageLine: "filer.meta.tail [-filer=localhost:8888] [-pathPrefix=/]", | |
| 	Short:     "see continuous changes on a filer", | |
| 	Long: `See continuous changes on a filer. | |
|  | |
| 	weed filer.meta.tail -timeAgo=30h | grep truncate | |
| 	weed filer.meta.tail -timeAgo=30h | jq . | |
| 	weed filer.meta.tail -timeAgo=30h -untilTimeAgo=20h | jq . | |
| 	weed filer.meta.tail -timeAgo=30h | jq .eventNotification.newEntry.name | |
|  | |
| 	weed filer.meta.tail -timeAgo=30h -es=http://<elasticSearchServerHost>:<port> -es.index=seaweedfs | |
|  | |
|   `, | |
| } | |
| 
 | |
| var ( | |
| 	tailFiler   = cmdFilerMetaTail.Flag.String("filer", "localhost:8888", "filer hostname:port") | |
| 	tailTarget  = cmdFilerMetaTail.Flag.String("pathPrefix", "/", "path to a folder or common prefix for the folders or files on filer") | |
| 	tailStart   = cmdFilerMetaTail.Flag.Duration("timeAgo", 0, "start time before now. \"300ms\", \"1.5h\" or \"2h45m\". Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\"") | |
| 	tailStop    = cmdFilerMetaTail.Flag.Duration("untilTimeAgo", 0, "read until this time ago. \"300ms\", \"1.5h\" or \"2h45m\". Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\"") | |
| 	tailPattern = cmdFilerMetaTail.Flag.String("pattern", "", "full path or just filename pattern, ex: \"/home/?opher\", \"*.pdf\", see https://golang.org/pkg/path/filepath/#Match ") | |
| 	esServers   = cmdFilerMetaTail.Flag.String("es", "", "comma-separated elastic servers http://<host:port>") | |
| 	esIndex     = cmdFilerMetaTail.Flag.String("es.index", "seaweedfs", "ES index name") | |
| ) | |
| 
 | |
| func runFilerMetaTail(cmd *Command, args []string) bool { | |
| 
 | |
| 	util.LoadSecurityConfiguration() | |
| 	grpcDialOption := security.LoadClientTLS(util.GetViper(), "grpc.client") | |
| 	clientId := util.RandomInt32() | |
| 
 | |
| 	var filterFunc func(dir, fname string) bool | |
| 	if *tailPattern != "" { | |
| 		if strings.Contains(*tailPattern, "/") { | |
| 			println("watch path pattern", *tailPattern) | |
| 			filterFunc = func(dir, fname string) bool { | |
| 				matched, err := filepath.Match(*tailPattern, dir+"/"+fname) | |
| 				if err != nil { | |
| 					fmt.Printf("error: %v", err) | |
| 				} | |
| 				return matched | |
| 			} | |
| 		} else { | |
| 			println("watch file pattern", *tailPattern) | |
| 			filterFunc = func(dir, fname string) bool { | |
| 				matched, err := filepath.Match(*tailPattern, fname) | |
| 				if err != nil { | |
| 					fmt.Printf("error: %v", err) | |
| 				} | |
| 				return matched | |
| 			} | |
| 		} | |
| 	} | |
| 
 | |
| 	shouldPrint := func(resp *filer_pb.SubscribeMetadataResponse) bool { | |
| 		if filer_pb.IsEmpty(resp) { | |
| 			return false | |
| 		} | |
| 		if filterFunc == nil { | |
| 			return true | |
| 		} | |
| 		if resp.EventNotification.OldEntry != nil && filterFunc(resp.Directory, resp.EventNotification.OldEntry.Name) { | |
| 			return true | |
| 		} | |
| 		if resp.EventNotification.NewEntry != nil && filterFunc(resp.EventNotification.NewParentPath, resp.EventNotification.NewEntry.Name) { | |
| 			return true | |
| 		} | |
| 		return false | |
| 	} | |
| 
 | |
| 	eachEntryFunc := func(resp *filer_pb.SubscribeMetadataResponse) error { | |
| 		filer.ProtoToText(os.Stdout, resp) | |
| 		fmt.Fprintln(os.Stdout) | |
| 		return nil | |
| 	} | |
| 	if *esServers != "" { | |
| 		var err error | |
| 		eachEntryFunc, err = sendToElasticSearchFunc(*esServers, *esIndex) | |
| 		if err != nil { | |
| 			fmt.Printf("create elastic search client to %s: %+v\n", *esServers, err) | |
| 			return false | |
| 		} | |
| 	} | |
| 
 | |
| 	var untilTsNs int64 | |
| 	if *tailStop != 0 { | |
| 		untilTsNs = time.Now().Add(-*tailStop).UnixNano() | |
| 	} | |
| 
 | |
| 	metadataFollowOption := &pb.MetadataFollowOption{ | |
| 		ClientName:             "tail", | |
| 		ClientId:               clientId, | |
| 		ClientEpoch:            0, | |
| 		SelfSignature:          0, | |
| 		PathPrefix:             *tailTarget, | |
| 		AdditionalPathPrefixes: nil, | |
| 		DirectoriesToWatch:     nil, | |
| 		StartTsNs:              time.Now().Add(-*tailStart).UnixNano(), | |
| 		StopTsNs:               untilTsNs, | |
| 		EventErrorType:         pb.TrivialOnError, | |
| 	} | |
| 
 | |
| 	tailErr := pb.FollowMetadata(pb.ServerAddress(*tailFiler), grpcDialOption, metadataFollowOption, func(resp *filer_pb.SubscribeMetadataResponse) error { | |
| 		if !shouldPrint(resp) { | |
| 			return nil | |
| 		} | |
| 		if err := eachEntryFunc(resp); err != nil { | |
| 			return err | |
| 		} | |
| 		return nil | |
| 	}) | |
| 
 | |
| 	if tailErr != nil { | |
| 		fmt.Printf("tail %s: %v\n", *tailFiler, tailErr) | |
| 	} | |
| 
 | |
| 	return true | |
| }
 |