Log SVN Access to a Central Location
Today I was searching the web for ways to log access to our Subversion repositories. It turns out, that there is no built-in straightforward way to do that. Most of the posts on the Web suggest using the Apache’s access log. This could work only if you have set-up WebDAV on your Apache server. We prefer to use SSH tunnels to access our repositories for many reasons, overhead being one of them.
So I took another run and ended up reading Kintoandar’s blog. He explains a rather simple way of making SVN log every access to the repository. It is based on svnserve, which is called every time a connection to the repository is made. The command itself supports logging, but the optional parameter for using log files is rarely used.
So the main idea is to replace the svnserve with a script, that calls svnserve and adds the optional log file parameters. The first part is from Kintoandar’s blog:
root@svn-server:~# mkdir /var/log/svn root@svn-server:~# whereis svnserve svnserve: /usr/bin/svnserve root@svn-server:~# mv /usr/bin/svnserve /usr/bin/svnserve.bin root@svn-server:~# vi /usr/bin/svnserve /usr/bin/svnserve.bin --log-file /var/log/svn/svnserve_`id -u`.log $1
So this will basically create an individual log file for every user that accesses the repository. The files are called svnserve_1001.log where 1001 is the Unix user ID.
Note 1: This will only work if the location /var/log/svn is writable for the system user who accesses the Subversion repository. In my case this is a group of users. I changed the ownership of the log directory to match the group:
root@svn-server:~# chown -R root:subversion /var/log/svn root@svn-server:~# chmod -R 660 /var/log/svn
Note 2: If there are different users who access the repository (as in my case) one log file per user is created. The log files are owned and writable only for the respective user.
Note 3: If the log directory is not writable for some reason, the connection to the repository will fail. The svnserve script will report an error writing to the log file. This in turn is interpreted as a connection error. Different Subversion clients will report different errors, but all will fail to connect.
A Single Log File
The problem with this setup in my case is, that I would prefer everything in a single log file. Then I would like to use a tool like Fluentd to ship the contents of this log file to GrayLog. To make a single log file, I removed the user ID from the file name:
root@svn-server:~# vi /usr/bin/svnserve /usr/bin/svnserve.bin --log-file /var/log/svn/svn.access.log $1
The problem with this setup are the individual user rights. The first user that connects to the repository will create the log file and take ownership of it. Subsequent connections to the repository from different users will fail. The solution is to enable the sticky tag for the svn log directory:
root@svn-server:~# chmod -R g+s /var/log/svn
This way, all files that are created in the directory will have the group owner of the parent directory. You can now create an empty file and set the permissions so that the whole group can write:
root@svn-server:~# touch /var/log/svn/svn.access.log root@svn-server:~# chown root:subversion /var/log/svn/svn.access.log root@svn-server:~# chmod 660 /var/log/svn/svn.access.log
Shipping the Logs to GrayLog
My ultimate goal was to store everything in a central location, where I can easily monitor the access. For this purpose I use GrayLog and a very handy tool called Fluentd. To setup Fluentd so that it constantly reads the Subversion log file and post its newly appended contents to GrayLog you can use the following input setup:
<source> type tail path /var/log/svn/svn.access.log tag svn.access format /^(?<pid>[0-9]+)\s(?<time>[^ ]*)\s-\s(?<user>[^ ]*)\s(?<repo>[^ ]*)\s(?<message>.*)$/ read_from_head true refresh_interval 10 pos_file /var/log/fluent.log.pos </source>
Restarting Fluentd will ship all contents of /var/log/svn/svn.access.log to GrayLog using ‘svn.access’ as a tag. You can proceed by creating your Stream definitions and Dashboard.