问题
application_name
is a PostgreSQL specific connection parameter which each client can (and should) set when connecting. It later on helps DBAs and operations staff correlate misbehaving queries with a particular bit of application code.
This SO question explains how to set application_name using SQLAlchemy, but unfortunately, it doesn't work on Heroku, because setting application_name
was added on the PostgreSQL 8.5
branch (which was only released as 9.0
) whereas the version of PostgreSQL client library (libpq
) installed on Heroku's dynos was built from PostgreSQL 8.4.9.
What, if anything, can be done to set application_name
on Heroku?
回答1:
To the best of my knowledge, the only solution is to vendor a newer version of libpq
into your slug.
The packages I'm targeting are libpq5 and libpq-dev, built from the source package postgresql-9.1. To save yourself a lot of work, and if you trust my binaries, you can just skip to step 8 and use the pre-built binary libpq which I made. No no, don't thank me.
- Spin up a new VM with vanilla 12.04
sudo apt-get update
apt-get source postgresql-9.1
(you will probably need tosudo apt-get install dpkg-src
first)- In the extracted sources, look at the rules file (
postgresql-9.1-9.1.8/debian/rules
, ifprecise-updates
is still at PostgreSQL 9.1.8). From the rules file, I believe the configuration options we should use for building our libpq are:
LDFLAGS="-Wl,--as-needed -Wl,-z,now" \ CFLAGS="-fPIC -DLINUX_OOM_ADJ=0" \ ./configure --prefix=/app/vendor \ --enable-integer-datetimes \ --enable-thread-safety \ --enable-debug \ --disable-rpath \ --with-gnu-ld \ --with-pgport=5432 \ --with-system-tzdata=/usr/share/zoneinfo \ --without-tcl \ --without-perl \ --without-python \ --with-krb5 \ --with-gssapi \ --with-openssl \ --with-libxml \ --with-libxslt \ --with-ldap
Note that I removed/negated
--enable-nls --with-ossp-uuid --with-tcl --with-perl --without-python --with-pam
, because on the Heroku dyno they lead to configuration/build failure. I don't need any of them, I'm not sure if they affectlibpq5
at all, I doubt they're very needed on a dyno, and if you feel otherwise, have fun fixing that and my hat's off to you good sir.make && make install
Now all of postgresql is installed to
/vendor
. The files we need to take are specified inpostgresql-9.1-9.1.8/debian/libpq5.install
andpostgresql-9.1-9.1.8/debian/libpq-dev.install
. Alas, because we aren't following debian's installation layout, we'll need to adapt these lists to find the files we really need. I came up with this list:tar c \ include/postgresql/internal/* \ include/libpq-fe.h \ include/libpq-events.h \ include/libpq/libpq-fs.h \ include/pg_config*.h \ include/postgres_ext.h \ include/postgresql/9.1/server/catalog/pg_type.h \ include/postgresql/9.1/server/catalog/genbki.h \ include/postgresql/9.1/server/nodes/nodes.h \ include/postgresql/9.1/server/utils/elog.h \ include/postgresql/9.1/server/utils/errcodes.h \ include/postgresql/9.1/server/utils/palloc.h \ include/postgresql/9.1/server/c.h \ include/postgresql/9.1/server/pg_config.h \ include/postgresql/9.1/server/pg_config_manual.h \ include/postgresql/9.1/server/pg_config_os.h \ include/postgresql/9.1/server/port.h \ include/postgresql/9.1/server/pg_trace.h \ include/postgresql/9.1/server/postgres.h \ include/postgresql/9.1/server/postgres_fe.h \ include/postgresql/9.1/server/postgres_ext.h \ include/postgresql/9.1/server/mb/pg_wchar.h \ lib/libpq.so \ bin/pg_config \ lib/libpq.so.5* \ | gzip --best > /tmp/libpq-5.4_9.1.8.tar.gz
Note that I had to remove the manpage (
pg_config.1.gz
) and localization messages (LC_MESSAGES/pg_config-9.1.mo LC_MESSAGES/libpq*.mo
undershare/locale
), which, for some reason, weren't built on my dyno. I managed to link Python'spsycopg2
against this list of files and use it successfully, but you can figure this out and fix it as well if you feel it's important.Our troubles are practically over now. You should take the resulting
libpq-5.4_9.1.8.tar.gz
file and put it somewhere that will be accessibly to your dyno's buildpack (like S3), then vendor it into the slug. If you're not sure how to do that, my suggestion (for the current Python buildpack), is that you create the file 'bin/pre_compile' in your slug, and put this into it:#!/bin/sh vendor() { printf " " echo -n "$1 " curl --location --fail --silent $1 | tar -zx -C vendor && echo OK } echo " (lines by the app will be prefixed with ---->>)" echo "---->> Fetching vendored binaries" mkdir -p vendor vendor "http://fusic.s3.amazonaws.com/executables/heroku/libpq-5.4_9.1.8.tar.gz" echo "---->> Injecting shell environment" # Even though Heroku's Python buildback has a hook mechanism, hooks can't # change the buildpack's process environment (they are spawned, not # sourced). This makes it possible to write hooks in any language, but # makes vendoring stuff that should be linked against libraries installed # during the rest of the build process harder. The kludge below hijacks # $BIN_DIR/steps/pylibmc, which is sourced after this code and before pip # is ran. Puked a little in my mouth. # See also: https://twitter.com/aknin/status/290832546260979712 cat > $BIN_DIR/steps/pylibmc << EOF echo "---->> Injected environment hook executing" source .profile.d/activate_vendor_tree.sh EOF
and also create
.profile.d/activate_vendor_tree.sh
and put this into it:#!sh export PATH="/app/vendor/bin:$PATH" export CFLAGS="-I/app/vendor/include" export LDFLAGS="-L/app/vendor/lib -R/app/vendor/lib" export LD_LIBRARY_PATH="/app/vendor/lib:$LD_LIBRARY_PATH"
When compiling your slug, the pre-hook we installed kicks in, downloads our backported libpq and vendors it into the slug. If you're using the Python buildpack or a similarly limited buildpack (see detailed comment above), the ugly but necessary environment injection hook kicks in, and your requirements will be compiled against the new libpq. When you run your app, Heroku conveniently source everything in
.profile.d
before executing your code, again activating the new libpq. Oh yeah.At long last, you're done. Deploy your app to Heroku, and your dependencies should link against the new libpq. If your app was already deployed, you'll probably need to clear your slug's cache dir before Heroku's slug compiler will try to reinstall these requirements (so they can be linked to your new libpq; this is a thorny topic, which is outside the scope of this tutorial; the only method I know is to stick something in the
pre_compile
that will delete the cache). Ugh.
来源:https://stackoverflow.com/questions/15725974/setting-postgresql-application-name-on-heroku