├── .gitignore ├── CHANGELOG ├── LICENSE ├── Makefile ├── README.md ├── main.go └── vendor └── vendor.json /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.zip 3 | cloudwatch-logger 4 | vendor/*/* 5 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | * 2017-03-09 Initial release. 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2017 Zendesk Inc. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BIN := cloudwatch-logger 2 | 3 | $(BIN): vendor main.go 4 | go build -o $(BIN) main.go 5 | 6 | .PHONY: vendor 7 | vendor: govendor vendor/vendor.json 8 | govendor sync 9 | 10 | .PHONY: govendor 11 | govendor: 12 | go get github.com/kardianos/govendor 13 | 14 | .PHONY: clean 15 | clean: 16 | rm -f $(BIN) 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | cloudwatch-logger 2 | ================= 3 | A simple tool to connect the standard input stream to Amazon CloudWatch. 4 | 5 | Usage 6 | ----- 7 | ``` 8 | cloudwatch-logger [-t] LOG-GROUP-NAME LOG-STREAM-NAME 9 | ``` 10 | 11 | If the `-t` option is specified, the input will also be copied to standard 12 | output. 13 | 14 | The log group and log stream will automatically be created if necessary. 15 | 16 | **NOTE:** The named log stream must not exist prior to running this program. 17 | 18 | Build instructions 19 | ------------------ 20 | ``` 21 | $ make 22 | ``` 23 | 24 | If you want to cross-compile, set the `GOOS` and `GOARCH` environment variables 25 | first. See https://golang.org/doc/install/source for details on the possible 26 | values. 27 | 28 | Author 29 | ------ 30 | Michael S. Fischer, 31 | 32 | Thanks 33 | ------ 34 | * [Eric Holmes](https://github.com/ejholmes) for his dead-simple [CloudWatch 35 | Logs stream library](https://github.com/ejholmes/cloudwatch). 36 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "log" 7 | "os" 8 | 9 | "github.com/aws/aws-sdk-go/aws" 10 | "github.com/aws/aws-sdk-go/aws/awserr" 11 | "github.com/aws/aws-sdk-go/aws/session" 12 | "github.com/aws/aws-sdk-go/service/cloudwatchlogs" 13 | "github.com/ejholmes/cloudwatch" 14 | ) 15 | 16 | func main() { 17 | var echoInput = false 18 | var groupName, streamName string 19 | 20 | if len(os.Args) < 3 { 21 | fmt.Fprintf(os.Stderr, "USAGE: %s [-t] log-group-name log-stream-name\n", os.Args[0]) 22 | os.Exit(1) 23 | } 24 | 25 | // This should really be cleaned up, but since there's only one optional 26 | // argument, it's "good enough" for now 27 | if os.Args[1] == "-t" { 28 | echoInput = true 29 | groupName = os.Args[2] 30 | streamName = os.Args[3] 31 | } else { 32 | groupName = os.Args[1] 33 | streamName = os.Args[2] 34 | } 35 | 36 | sess, err := session.NewSession() 37 | if err != nil { 38 | log.Fatal(err) 39 | } 40 | client := cloudwatchlogs.New(sess) 41 | if _, err := client.CreateLogGroup(&cloudwatchlogs.CreateLogGroupInput{LogGroupName: aws.String(groupName)}); err != nil { 42 | if awsErr, ok := err.(awserr.Error); ok { 43 | // It's OK if the log group exists already 44 | if awsErr.Code() != "ResourceAlreadyExistsException" { 45 | log.Fatal(awsErr) 46 | } 47 | } else { 48 | log.Fatal(err) 49 | } 50 | } 51 | 52 | group := cloudwatch.NewGroup(groupName, client) 53 | w, err := group.Create(streamName) 54 | if err != nil { 55 | log.Fatal(err) 56 | } 57 | 58 | defer func(w io.Writer) { 59 | // Ensure we flush any remaining buffered logs to stream 60 | if writer, ok := w.(*cloudwatch.Writer); ok { 61 | if err := writer.Flush(); err != nil { 62 | log.Fatal(err) 63 | } 64 | } 65 | }(w) 66 | 67 | var r io.Reader 68 | 69 | if echoInput { 70 | r = io.TeeReader(os.Stdin, os.Stdout) 71 | } else { 72 | r = os.Stdin 73 | } 74 | 75 | if _, err := io.Copy(w, r); err != nil { 76 | log.Fatal(err) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /vendor/vendor.json: -------------------------------------------------------------------------------- 1 | { 2 | "comment": "", 3 | "ignore": "test", 4 | "package": [ 5 | { 6 | "checksumSHA1": "ZEZ4PBsI1pw2HLKmajnpyvNQpRA=", 7 | "path": "github.com/aws/aws-sdk-go/aws", 8 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 9 | "revisionTime": "2017-03-09T01:38:40Z" 10 | }, 11 | { 12 | "checksumSHA1": "Y9W+4GimK4Fuxq+vyIskVYFRnX4=", 13 | "path": "github.com/aws/aws-sdk-go/aws/awserr", 14 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 15 | "revisionTime": "2017-03-09T01:38:40Z" 16 | }, 17 | { 18 | "checksumSHA1": "yyYr41HZ1Aq0hWc3J5ijXwYEcac=", 19 | "path": "github.com/aws/aws-sdk-go/aws/awsutil", 20 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 21 | "revisionTime": "2017-03-09T01:38:40Z" 22 | }, 23 | { 24 | "checksumSHA1": "iThCyNRL/oQFD9CF2SYgBGl+aww=", 25 | "path": "github.com/aws/aws-sdk-go/aws/client", 26 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 27 | "revisionTime": "2017-03-09T01:38:40Z" 28 | }, 29 | { 30 | "checksumSHA1": "ieAJ+Cvp/PKv1LpUEnUXpc3OI6E=", 31 | "path": "github.com/aws/aws-sdk-go/aws/client/metadata", 32 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 33 | "revisionTime": "2017-03-09T01:38:40Z" 34 | }, 35 | { 36 | "checksumSHA1": "Fl8vRSCY0MbM04cmiz/0MID+goA=", 37 | "path": "github.com/aws/aws-sdk-go/aws/corehandlers", 38 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 39 | "revisionTime": "2017-03-09T01:38:40Z" 40 | }, 41 | { 42 | "checksumSHA1": "zu5C95rmCZff6NYZb62lEaT5ibE=", 43 | "path": "github.com/aws/aws-sdk-go/aws/credentials", 44 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 45 | "revisionTime": "2017-03-09T01:38:40Z" 46 | }, 47 | { 48 | "checksumSHA1": "u3GOAJLmdvbuNUeUEcZSEAOeL/0=", 49 | "path": "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds", 50 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 51 | "revisionTime": "2017-03-09T01:38:40Z" 52 | }, 53 | { 54 | "checksumSHA1": "NUJUTWlc1sV8b7WjfiYc4JZbXl0=", 55 | "path": "github.com/aws/aws-sdk-go/aws/credentials/endpointcreds", 56 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 57 | "revisionTime": "2017-03-09T01:38:40Z" 58 | }, 59 | { 60 | "checksumSHA1": "6cj/zsRmcxkE1TLS+v910GbQYg0=", 61 | "path": "github.com/aws/aws-sdk-go/aws/credentials/stscreds", 62 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 63 | "revisionTime": "2017-03-09T01:38:40Z" 64 | }, 65 | { 66 | "checksumSHA1": "lqh3fG7wCochvB4iHAZJuhhEJW0=", 67 | "path": "github.com/aws/aws-sdk-go/aws/defaults", 68 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 69 | "revisionTime": "2017-03-09T01:38:40Z" 70 | }, 71 | { 72 | "checksumSHA1": "/EXbk/z2TWjWc1Hvb4QYs3Wmhb8=", 73 | "path": "github.com/aws/aws-sdk-go/aws/ec2metadata", 74 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 75 | "revisionTime": "2017-03-09T01:38:40Z" 76 | }, 77 | { 78 | "checksumSHA1": "RTIgFaXgsZqDSq9lyZrY9E7q83E=", 79 | "path": "github.com/aws/aws-sdk-go/aws/endpoints", 80 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 81 | "revisionTime": "2017-03-09T01:38:40Z" 82 | }, 83 | { 84 | "checksumSHA1": "M78rTxU55Qagqr3MYj91im2031E=", 85 | "path": "github.com/aws/aws-sdk-go/aws/request", 86 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 87 | "revisionTime": "2017-03-09T01:38:40Z" 88 | }, 89 | { 90 | "checksumSHA1": "u6tKvFGcRQ1xtby1ONjgyUTgcpg=", 91 | "path": "github.com/aws/aws-sdk-go/aws/session", 92 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 93 | "revisionTime": "2017-03-09T01:38:40Z" 94 | }, 95 | { 96 | "checksumSHA1": "0FvPLvkBUpTElfUc/FZtPsJfuV0=", 97 | "path": "github.com/aws/aws-sdk-go/aws/signer/v4", 98 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 99 | "revisionTime": "2017-03-09T01:38:40Z" 100 | }, 101 | { 102 | "checksumSHA1": "Bm6UrYb2QCzpYseLwwgw6aetgRc=", 103 | "path": "github.com/aws/aws-sdk-go/private/endpoints", 104 | "revision": "e39222bf4583af667250cfd83a41388937ba56d4", 105 | "revisionTime": "2016-08-24T23:07:50Z" 106 | }, 107 | { 108 | "checksumSHA1": "wk7EyvDaHwb5qqoOP/4d3cV0708=", 109 | "path": "github.com/aws/aws-sdk-go/private/protocol", 110 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 111 | "revisionTime": "2017-03-09T01:38:40Z" 112 | }, 113 | { 114 | "checksumSHA1": "O6hcK24yI6w7FA+g4Pbr+eQ7pys=", 115 | "path": "github.com/aws/aws-sdk-go/private/protocol/json/jsonutil", 116 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 117 | "revisionTime": "2017-03-09T01:38:40Z" 118 | }, 119 | { 120 | "checksumSHA1": "R00RL5jJXRYq1iiK1+PGvMfvXyM=", 121 | "path": "github.com/aws/aws-sdk-go/private/protocol/jsonrpc", 122 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 123 | "revisionTime": "2017-03-09T01:38:40Z" 124 | }, 125 | { 126 | "checksumSHA1": "ZqY5RWavBLWTo6j9xqdyBEaNFRk=", 127 | "path": "github.com/aws/aws-sdk-go/private/protocol/query", 128 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 129 | "revisionTime": "2017-03-09T01:38:40Z" 130 | }, 131 | { 132 | "checksumSHA1": "Drt1JfLMa0DQEZLWrnMlTWaIcC8=", 133 | "path": "github.com/aws/aws-sdk-go/private/protocol/query/queryutil", 134 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 135 | "revisionTime": "2017-03-09T01:38:40Z" 136 | }, 137 | { 138 | "checksumSHA1": "szZSLm3BlYkL3vqlZhNAlYk8iwM=", 139 | "path": "github.com/aws/aws-sdk-go/private/protocol/rest", 140 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 141 | "revisionTime": "2017-03-09T01:38:40Z" 142 | }, 143 | { 144 | "checksumSHA1": "lZ1z4xAbT8euCzKoAsnEYic60VE=", 145 | "path": "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil", 146 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 147 | "revisionTime": "2017-03-09T01:38:40Z" 148 | }, 149 | { 150 | "checksumSHA1": "TMRiIJYbg0/5naYSnYk3DQnaDkk=", 151 | "path": "github.com/aws/aws-sdk-go/service/cloudwatchlogs", 152 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 153 | "revisionTime": "2017-03-09T01:38:40Z" 154 | }, 155 | { 156 | "checksumSHA1": "Knj17ZMPWkGYTm2hZxEgnuboMM4=", 157 | "path": "github.com/aws/aws-sdk-go/service/sts", 158 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 159 | "revisionTime": "2017-03-09T01:38:40Z" 160 | }, 161 | { 162 | "checksumSHA1": "VyuPUqnRsnsDqx69bMOJqZwGFo8=", 163 | "path": "github.com/ejholmes/cloudwatch", 164 | "revision": "39382b2f7b5f1aab560fab4b400775f41bee7613", 165 | "revisionTime": "2016-03-31T23:53:17Z" 166 | }, 167 | { 168 | "checksumSHA1": "FCeEm2BWZV/n4oTy+SGd/k0Ab5c=", 169 | "origin": "github.com/aws/aws-sdk-go/vendor/github.com/go-ini/ini", 170 | "path": "github.com/go-ini/ini", 171 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 172 | "revisionTime": "2017-03-09T01:38:40Z" 173 | }, 174 | { 175 | "checksumSHA1": "0ZrwvB6KoGPj2PoDNSEJwxQ6Mog=", 176 | "origin": "github.com/aws/aws-sdk-go/vendor/github.com/jmespath/go-jmespath", 177 | "path": "github.com/jmespath/go-jmespath", 178 | "revision": "37f127c188d13d8cbdd1abc6969ab33a79ecaa38", 179 | "revisionTime": "2017-03-09T01:38:40Z" 180 | } 181 | ], 182 | "rootPath": "github.com/zendesk/cloudwatch-logger" 183 | } 184 | --------------------------------------------------------------------------------