Categories
Mac Software Unix

PostgreSQL auf Mac OS X, diesmal mit Syslog-Logging

Ich hatte vor einer Weile geschrieben, wie man PostgreSQL auf Mac OS X sauber installiert. Das klappt zwar prima, doch die Logfiles waren ein wenig chaotisch. Bei der Installation von PostgreSQL 8.2 habe ich also beschlossen, via Syslog zu loggen. Die eigentliche Installation läuft wie im letzten Artikel beschrieben ab. Erst bei Punkt 10 mußte ich von der alten Anleitung abweichen.

In der /Users/Shared/PostgreSQL/data/postgresql.conf habe ich folgende Änderungen durchgeführt:

--- postgresql.conf.orig  2006-12-08 13:29:39.000000000 +0100
+++ postgresql.conf 2006-12-08 13:31:28.000000000 +0100
@@ -221,6 +221,7 @@

 # - Where to Log -

+log_destination = "syslog"
 #log_destination = 'stderr'    # Valid values are combinations of
          # stderr, syslog and eventlog,
          # depending on platform.
@@ -252,6 +253,7 @@

 # These are relevant when logging to syslog:
 #syslog_facility = 'LOCAL0'
+syslog_facility = 'LOCAL1'
 #syslog_ident = 'postgres'

@@ -313,6 +315,7 @@
 #log_connections = off
 #log_disconnections = off
 #log_duration = off
+log_line_prefix = '%u@%h:/%d '
 #log_line_prefix = ''      # Special values:
          #   %u = user name
          #   %d = database name
@@ -331,6 +334,7 @@
          #   %% = '%'
          # e.g. '<%u%%%d> '
 #log_statement = 'none'      # none, ddl, mod, all
+log_statement = 'all'
 #log_hostname = off

Damit habe ich PostgreSQL gesagt, es möge seine Nachrichten an den Syslog senden. Nun muß der Syslog noch wissen, was er damit anstellen soll. Das steht in der /etc/syslog.conf.

--- syslog.conf.orig  2006-12-08 13:34:26.000000000 +0100
+++ syslog.conf 2006-12-08 13:34:11.000000000 +0100
@@ -17,5 +17,6 @@
 install.*            /var/log/install.log
 install.*            @127.0.0.1:32376
 local0.*           /var/log/ipfw.log
+local1.*           /var/log/pgsql/pgsql.log

 *.emerg              *

Fast geschafft. Jetzt mußte ich nur noch aus dem Launchd-Skript die Zeilen entfernen, die dem PostgreSQL-Server gesagt haben, daß er sich selbst um die Logfiles kümmern soll.

--- org.postgresql.postmaster.plist.orig  2006-12-08 13:37:13.000000000 +0100
+++ org.postgresql.postmaster.plist 2006-12-08 13:37:25.000000000 +0100
@@ -15,10 +15,6 @@
    <string>redirect_stderr=YES</string>
    <string>-c</string>
    <string>log_connections=YES</string>
-   <string>-c</string>
-   <string>log_directory=/var/log/pgsql</string>
-   <string>-c</string>
-   <string>log_filename=postgres_log</string>
  </array>
  <key>ServiceDescription</key>
  <string>PostgreSQL Server</string>

Dann habe ich nur noch ein leeres Logfile für den Syslog mit sudo touch /var/log/pgsql/pgsql.log angelegt. (Es könnte nötig sein, vorher das dazugehörige Verzeichnis mit sudo mkdir /var/log/pgsql anzulegen). Damit der Syslog nun seine Konfigurationsdatei neu einliest, habe ich ihn mit sudo killall -HUP syslogd angeregt, sich zu restarten.

Nun kann der PostgreSQL wie in der alten Anleitung gestartet werden.

Categories
Software

ActiveRecord ohne Rails

ActiveRecord ist einer der Gründe, wieso Ruby on Rails so einfach und flexibel ist. Es ist ein sogenannter objektrelationaler Mapper. Damit lassen sich Daten aus einer Datenbank wie Objekte behandeln. Aber auch ohne Rails läßt sich ActiveRecord recht einfach einsetzen.

Als Beispiel habe ich hier 2 Tabellen in PostgreSQL, in denen ich eine Auswahl an Artikeln speichern möchte. Die Tabelle selections enthält den Namen der Auswahl von Artikeln und in selectionitems befinden sich die Artikel aus Auswahllisten. Die Tabellen haben folgendes Schema:

CREATE TABLE selections (
  id                SERIAL PRIMARY KEY,
  name              VARCHAR(30)
);

CREATE TABLE selectionitems (
  id                SERIAL PRIMARY KEY,
  part_id           INTEGER,
  selection_id      INTEGER,
  sort_order        INTEGER
);

Die beiden Tabellen habe ich mit Testdaten gefüllt.

artikel=# select * from selections;
 id | name
----+------
  1 | foo
(1 row)

artikel=# select * from selectionitems;
 id | part_id | selection_id | sort_order
----+---------+--------------+------------
  1 |      23 |            1 |          3
  2 |      42 |            1 |          1
  3 |     123 |            1 |          2
(3 rows)

Die Namen der Tabellen und der Felder sind schon ziemlich Rails-like, so daß in den folgenden Beispielen sehr viele Einstellungen überflüssig sind. Aber ich habe sie hier eingetragen, um zu zeigen, wie man mit beliebigen Tabellen arbeiten könnte.

Mit ActiveRecord verpacke ich nun die beiden Tabellen. Falls es beim require bzw. require_gem zu Fehlern kommen sollte, sind vermutlich die Ruby Gems bzw. das ActiveRecord-Gem nicht installiert. (Genaueres ist auf der Ruby Gems Website beschrieben)

require 'rubygems'
require_gem 'activerecord'

ActiveRecord::Base.establish_connection(
  :adapter    => "postgresql",
  :host       => "localhost",
  :database   => "artikel",
  :username   => "dbuser",
  :password   => "kryptisches_passwort"
)

class Selection < ActiveRecord::Base
  set_table_name "selections"
  set_primary_key "id"
  has_many  :items,
            :class_name => "SelectionItem",
            :foreign_key => "selection_id",
            :order => "sort_order"
end

class SelectionItem < ActiveRecord::Base
  set_table_name "selectionitems"
  set_primary_key "id"
  belongs_to  :selection,
              :class_name => "Selection",
              :foreign_key => "selection_id"
end

Das war der ganze Code, um die beiden Tabellen in Objekte zu verpacken. Was genau steht nun da oben? ActiveRecord::Base.establish_connection() dürfte eigentlich selbsterklärend sein. Interessant wird es bei der Klasse Selections. Ich sage der Klasse mit set_table_name auf welcher Tabelle aus der Datenbank sie basieren soll und mit set_primary_key wie die Spalte mit dem Primärschlüssel heißt. (ActiveRecord hat hier einige Automatismen um vom Namen der Klasse auf den Tabellennamen zu schließen, die ich jedoch bewußt nicht benutzt habe.) Mit has_many habe ich bestimmt, daß jede Instanz der Klasse Selections mehrere Instanzen der Klasse SelectionItem enthalten kann. Die Zuordnung dieser items zu einer Selection geschieht anhand der selection_id aus SelectionItem. Ähnlich habe ich auch in SelectionItem bestimmt, auf welcher Tabelle es basieren soll. Und umgekehrt zu has_many habe ich hier mit belongs_to festgelegt, daß eine Instanz von SelectionItem zu einer bestimmten Selection gehört.

Wie benutze ich das nun? Ich ich suche erstmal die in den Tabellen gespeicherte Auswahl.

irb(main):028:0> foo = Selection.find_by_name("foo")
=> #"foo", "id"=>"1"}>

Wer Ruby on Rails schon gesehen hat, wird das wiedererkennen. Und all die anderen halten es für Magie :) Hier ist die erste Auswahl mit den Namen foo. Diese Auswahl enthält nun einige Artikel. Mal schauen, was ich da habe.

irb(main):029:0> foo.items.count
=> 3
irb(main):030:0> foo.items.each { |bar| puts bar.part_id }
42
123
23

Da ist meine Auswahl. Jetzt will ich ein weiteren Artikel zu dieser Auswahl hinzufügen.

irb(main):031:0> foo.items.create(:part_id => 451, :sort_order => 4)
=> #>, @attributes={"part_id"=>451, "sort_order"=>4, "selection_id"=>1, "id"=>4}>
irb(main):032:0> foo.items.count
=> 4
irb(main):033:0> foo.items.each { |bar| puts bar.part_id }
42
123
23
451

Das war aber noch nicht alles. Ich möchte in meiner Auswahl den zweiten Artikel herausfinden.

irb(main):035:0> foo.items.find_by_sort_order(2).part_id
=> 123

Ich kann diese Auswahl aber auch wie ein Array betrachten. (Achtung, Arrays fangen bei 0 an!)

irb(main):038:0> foo.items[1].part_id
=> 123

Besondere Erwähnung verdient die Suchfunktion. Ich sage nur find_by_feldname, und es wird anhand dieses Feldes in der Tabelle gesucht. ActiveRecord erzeugt also automagisch für alle Tabellenfelder find-Methoden. Das geht sogar so weit, daß man auch mehrere Suchkriterien kombinieren kann.

irb(main):041:0> foo.items.find_by_part_id_and_sort_order(123,2)
=> #"123", "sort_order"=>"2", "selection_id"=>"1", "id"=>"3"}>

Wenn ActiveRecord nichts findet, gibt es einfach nil zurück.

irb(main):040:0> foo.items.find_by_part_id_and_sort_order(123,3)
=> nil

Und für all diejenigen, die ihren Augen noch nicht trauen, hier noch ein letzter Blick in die Datenbank. Ich zeige hier nur die Tabelle selectionitems, da ich nur darin was geändert habe.

artikel=# select * from selectionitems;
 id | part_id | selection_id | sort_order
----+---------+--------------+------------
  1 |      23 |            1 |          3
  2 |      42 |            1 |          1
  3 |     123 |            1 |          2
  4 |     451 |            1 |          4
(4 rows)

Wer sich nun mit den Details von ActiveRecord auseinander setzen möchte, sollte in die Ruby on Rails-Dokumentation schauen.

Categories
Verschiedenes

Vergebliche Suche

Ein altes Sprichwort sagt: Auf einer leeren Diskette kann man lange und vergeblich suchen.. Ähnliches gilt auch für alte Datenbankserver, die vor Wochen durch neue ersetzt wurden und seit dem keine neuen Daten bekommen haben. Dies mußte heute mein Chef erfahren.

Categories
Dokumentation Software

PostgreSQL auf OpenBSD

Für die Installation von Movable Type auf OpenBSD brauchte ich eine Datenbank. Die Wahl fiel auf PostgreSQL. Hier ist was ich tat, um PostgreSQL nach meinen Vorstellungen zu konfigurieren.

Diese Anleitung ist an einigen Stellen OpenBSD-spezifisch. Bei Linux muß logrotate statt newsyslog benutzt werden.

Zuerst muß man den Quelltext herunterladen und an geeigneter Stelle extrahieren. Den Quelltext kompilieren und die fertigen Programme zu installieren funktioniert mit dem üblichen GNU-Dreisatz: (die letzte Zeile sollte man als root aufrufen)

./configure—prefix=/usr/local—with-perl—with-openssl=/usr
make
make install

Damit hat man schon mal alle nötigen Programme installiert. PostgreSQL braucht aber noch einige Vorarbeit, um zu funktionieren. PostgreSQL möchte unter einem eigenen Benutzer laufen. Die folgenden Zeilen legen diesen Benutzer samt passender Gruppe an. (natürlich als root)

groupadd -g 164 pgsql
useradd -c “PostgreSQL Admin User” -d /var/pgsql -g 164 -u 164 -s /bin/sh pgsql

Nun fehlt noch das Datenbankverzeichnis, in dem PostgreSQL seine Daten ablegt. Dieses Verzeichnis sollte dem PostgreSQL-Benutzer gehören.

mkdir /var/pgsql
chown pgsql:pgsql /var/pgsql
chmod 755 /var/pgsql

Jetzt muß die Datenbank initialisiert werden. Da alle Dateien im Datenbankverzeichnis dem PostgreSQL-Benutzer gehören sollten, sollte dies als der PostgreSQL-Benutzer geschehen.

su pgsql
/usr/local/bin/initdb -D /var/pgsql/data

Damit ist die Datenbank im Grunde fertig und kann benutzt werden. Es fehlen aber noch einige Kleinigkeiten, damit das alles rund läuft.

Zuerst soll PostgreSQL beim Booten gestartet werden. Die nächsten Zeilen sollten an passender Stelle in die /etc/rc.local aufgenommen werden: (wieder als root)

if [ -x /usr/local/bin/pg_ctl ]; then
        su -l pgsql -c “/usr/local/bin/pg_ctl start \
                -D /var/pgsql/data -l /var/pgsql/logfile”
        echo -n ‘ postgresql’
fi

Natürlich soll PostgreSQL beim Herunterfahren von OpenBSD sauber beendet werden, um inkonsistenzen in der Datenbank zu verhindern. Dies erledigen diese Zeilen in der /etc/rc.shutdown:

if [ -f /var/pgsql/data/postmaster.pid ]; then
        su -l pgsql -c “/usr/local/bin/pg_ctl stop \
                -D /var/pgsql/data”
        echo -n ‘ postgresql’
fi

PostgreSQL soll über syslogd(8) loggen. Das macht es einfacher, auf einem zentralen Logging-Host zu loggen. Hier müssen in der /var/pgsql/data/postgresql.conf 3 Zeilen angepasst werden. Die Zeilen stehen schon in der Datei drin, sind jedoch auskommentiert.

syslog = 2                      # range 0-2; 0=stdout; 1=both; 2=syslog
syslog_facility = ‘LOCAL0’
syslog_ident = ‘postgres’

Selbverständlich muß der syslogd(8) auch wissen, was er mit den Daten anfangen soll. Darum kümmert sich diese Zeile in der /etc/syslog.conf:

local0.*                                                /var/log/pgsql

Bevor der syslogd(8) nun restarted wird, damit er anfangen kann zu loggen, sollte noch ein leeres Logfile angelegt werden, da der syslogd(8) dies in der Regel nicht tut. Mit touch /var/log/pgsql entsteht ein leeres Logfile an. Schicke ein SIGHUP an syslogd(8) um ihn zu restarten.

Die Logfiles sollten noch in regelmäßigen Abständen rotiert werden, damit das Dateisystem nicht überläuft. Bei OpenBSD kümmert sich newsyslog(8) um das Rotieren von Logfiles. Eine Zeile in der /etc/newsyslog.conf erledigt dies:

/var/log/pgsql                          640  7    *    168   Z

Damit ist PostgreSQL nun bereit zum Einsatz. Um den Server nun endlich zu starten, kann der gleiche Code benutzt werden, wie er auch in der /etc/rc.local steht. Viel Spaß mit PostgreSQL.