├── t.gif
├── README
├── pixelog.go
└── LICENSE
/t.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudhead/pixelog/HEAD/t.gif
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | pixelog is a simple way to track visits to a web page,
2 | which doesn't require javascript.
3 |
4 | RATIONALE
5 |
6 | When you need something simple to track static HTML
7 | page visits and don't want to pollute your site with
8 | javascript.
9 |
10 | USAGE
11 |
12 | On the page we want to track, we include an
tag
13 | pointing to the tracking pixel on the pixelog server:
14 |
15 |
16 |
17 | If we want to include additional information, we simply
18 | add it to the url query string:
19 |
20 |
21 |
22 | We then start the pixelog server on pixelog.local:
23 |
24 | $ pixelog -l :80 -file "t.gif"
25 |
26 | When our page is loaded, pixelog outputs a log entry:
27 |
28 | 2013/09/01 15:38:40 184.96.4.32 /t.gif?page=home "Mozilla/5.0" http://ref.co
29 |
30 | The fields in order of appearance: date, time, remote ip, request url, user-agent,
31 | referer.
32 |
33 | COPYRIGHT
34 |
35 | (C) 2013 Alexis Sellier
36 |
--------------------------------------------------------------------------------
/pixelog.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "io/ioutil"
6 | "log"
7 | "net"
8 | "net/http"
9 | "strconv"
10 | )
11 |
12 | func main() {
13 | l := flag.String("l", ":8080", "listen addr")
14 | file := flag.String("file", "t.gif", "tracking pixel filename")
15 |
16 | flag.Parse()
17 |
18 | pixel, err := ioutil.ReadFile(*file)
19 | if err != nil {
20 | log.Fatal(err)
21 | }
22 |
23 | http.HandleFunc("/"+*file, handlePixel(pixel))
24 | http.ListenAndServe(*l, nil)
25 | }
26 |
27 | func handlePixel(pixel []byte) http.HandlerFunc {
28 | return func(w http.ResponseWriter, r *http.Request) {
29 | referer := r.Header.Get("Referer")
30 | if referer == "" {
31 | referer = "-"
32 | }
33 | agent := r.Header.Get("User-Agent")
34 | if agent == "" {
35 | agent = "-"
36 | }
37 | remote, _, err := net.SplitHostPort(r.RemoteAddr)
38 | if err != nil {
39 | remote = "-"
40 | }
41 | log.Println(remote, r.URL.String(), strconv.QuoteToASCII(agent), referer)
42 |
43 | w.Header().Set("Cache-Control", "private, max-age=0")
44 | w.WriteHeader(http.StatusOK)
45 | w.Write(pixel)
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2013 Alexis Sellier
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------