// printVersionInfo prints the version information about this application func printVersionInfo(f *os.File) { const versionTempl = ` {{.AppName}} version {{.AppVersion}} ({{.Os}},{{.Arch}}) Built on: {{.Sp3}}{{.BuildTime}} Author: {{.Sp3}}Fabio Hernandez {{.Sp3}}IN2P3/CNRS computing center, Lyon (France) Source code and documentation: {{.Sp3}}https://github.com/airnandez/{{.AppName}} ` fields := map[string]string{ "AppName": programName, "AppVersion": version, "BuildTime": buildTime, "Os": runtime.GOOS, "Arch": runtime.GOARCH, "Sp3": " ", } minWidth, tabWidth, padding := 8, 4, 0 tabwriter := tabwriter.NewWriter(f, minWidth, tabWidth, padding, byte(' '), 0) templ := template.Must(template.New("").Parse(versionTempl)) templ.Execute(tabwriter, fields) tabwriter.Flush() }
func (infos InfoSet) String() string { //no error checking, none of this should fail buffer := bytes.NewBuffer(make([]byte, 0, 1024)) tabwriter := tabwriter.NewWriter(buffer, 4, 4, 2, ' ', 0) first := true for _, info := range infos { if first { writeLine(tabwriter, true, info) } first = false writeLine(tabwriter, false, info) } tabwriter.Flush() return buffer.String() }
// printUsage prints how to use this application func printUsage(f *os.File, kind HelpType) { const usageTempl = ` USAGE: {{.Sp3}}{{.AppName}} --mount=<directory> --shadow=<directory> [--out=<file>] {{.Sp3}}{{.AppNameFiller}} [(--csv | --json)] [--ro] {{.Sp3}}{{.AppName}} --help {{.Sp3}}{{.AppName}} --version {{if eq .UsageVersion "short"}} Use '{{.AppName}} --help' to get detailed information about options and examples of usage.{{else}} DESCRIPTION: {{.Sp3}}{{.AppName}} mounts a synthesized file system which purpose is to generate {{.Sp3}}trace events for each low level file I/O operation executed on any file {{.Sp3}}or directory under its control. Examples of such operations are open(2), {{.Sp3}}read(2), write(2), close(2), access(2), etc. {{.Sp3}}{{.AppName}} exposes the contents of the directory specified by the {{.Sp3}}option '--shadow' via the path specified by the option '--mount'. {{.AppName}} {{.Sp3}}generates a trace event for each I/O operation and forwards the operation {{.Sp3}}to the target file system, that is, the one which actually hosts the shadow {{.Sp3}}directory. See the EXAMPLES section below. {{.Sp3}}Individual trace events generated by {{.AppName}} are written to the specified {{.Sp3}}output file (option --out) in the specified format. OPTIONS: {{.Sp3}}--mount=<directory> {{.Tab1}}This is the top directory through which the files and directories residing {{.Tab1}}under the shadow directory will be exposed. See the EXAMPLES section below. {{.Tab1}}The specified directory must exist and must be empty. {{.Sp3}}--shadow=<directory> {{.Tab1}}This is a directory where the files and directories you want to trace {{.Tab1}}actually reside. {{.Tab1}}The specified directory must exist but may be empty. {{.Sp3}}--out=<file> {{.Tab1}}Path of the text file to write the trace events to. If this file {{.Tab1}}does not exist it will be created, otherwise new events will be appended. {{.Tab1}}Note that this file cannot be located under the shadow directory. {{.Tab1}}Use '-' (dash) to write the trace events to the standard output. {{.Tab1}}In addition, you can specify a file name with extension '.csv' or '.json' {{.Tab1}}to instruct {{.AppName}} to emit records in the corresponding format, {{.Tab1}}as if you had used the '--csv' or '--json' options (see below). {{.Tab1}}Default: write trace records to standard output. {{.Sp3}}--csv {{.Tab1}}Format each individual trace event generated by {{.AppName}} as a set of {{.Tab1}}comma-separated values in a single line. {{.Tab1}}Note that not all events contain the same information since each {{.Tab1}}low level I/O operation requires specific arguments. Please refer to {{.Tab1}}the documentation at 'https://github.com/airnandez/{{.AppName}}' for {{.Tab1}}details on the format of each event. {{.Tab1}}CSV is the default output format unless the output file name (see option {{.Tab1}}'--out' above) has a '.json' extension. {{.Sp3}}--json {{.Tab1}}Format each individual trace event generated by {{.AppName}} as {{.Tab1}}a JSON object. Events in this format are self-described but not all {{.Tab1}}events contain the same information since each low level I/O operation {{.Tab1}}requires specific arguments. Please refer to the documentation {{.Tab1}}at 'https://github.com/airnandez/{{.AppName}}' for details on the format {{.Tab1}}of each event. {{.Sp3}}--ro {{.Tab1}}Expose the shadow file system as a read-only file system. {{.Tab1}}Default: if this option is not specified, the file system is mounted in {{.Tab1}}read-write mode. {{.Sp3}}--help {{.Tab1}}Show this help {{.Sp3}}--version {{.Tab1}}Show version information and source repository location EXAMPLES: {{.Sp3}}To trace file I/O operations on files under $HOME/data use: {{.Tab1}}{{.AppName}} --mount=/tmp/trace --shadow=$HOME/data {{.Sp3}}After a successfull mount, the contents under $HOME/data are also {{.Sp3}}accessible by using the path /tmp/trace. For instance, if the {{.Sp3}}file $HOME/data/hello.txt exists, {{.AppName}} traces all the file I/O {{.Sp3}}operations induced by the command: {{.Tab1}}cat /tmp/trace/hello.txt {{.Sp3}}Trace events for each one of the low level operations induced by the {{.Sp3}}'cat' command above will be written to the output file, the standard {{.Sp3}}output in this particular example. {{.Sp3}}You can also create new files under /tmp/trace. For instance, the file {{.Sp3}}I/O operations induced by the shell command: {{.Tab1}}echo "This is a new file" > /tmp/trace/newfile.txt {{.Sp3}}will be traced and the file will actually be created in {{.Sp3}}$HOME/data/newfile.txt. This file will persist even after unmounting {{.Sp3}}{{.AppName}} (see below on how to unmount the synthetized file system). {{.Sp3}}Please note that any destructive action, such as removing or modifying {{.Sp3}}the contents of a file or directory using the path /tmp/trace will {{.Sp3}}affect the corresponding file or directory under $HOME/data. {{.Sp3}}For example, the command: {{.Tab1}}rm /tmp/trace/notes.txt {{.Sp3}}will have the same destructive effect as if you had executed {{.Tab1}}rm $HOME/data/notes.txt {{.Sp3}}To unmount the file system exposed by {{.AppName}} use: {{.Tab1}}umount /tmp/trace {{.Sp3}}Alternatively, on MacOS X you can also use the diskutil(8) command: {{.Tab1}}/usr/sbin/diskutil unmount /tmp/trace {{end}} ` fields := map[string]string{ "AppName": programName, "AppNameFiller": strings.Repeat(" ", len(programName)), "Sp2": " ", "Sp3": " ", "Sp4": " ", "Sp5": " ", "Sp6": " ", "Tab1": "\t", "Tab2": "\t\t", "Tab3": "\t\t\t", "Tab4": "\t\t\t\t", "Tab5": "\t\t\t\t\t", "Tab6": "\t\t\t\t\t\t", "UsageVersion": "short", } if kind == HelpLong { fields["UsageVersion"] = "long" } minWidth, tabWidth, padding := 8, 4, 0 tabwriter := tabwriter.NewWriter(f, minWidth, tabWidth, padding, byte(' '), 0) templ := template.Must(template.New("").Parse(usageTempl)) templ.Execute(tabwriter, fields) tabwriter.Flush() }