Warteschleifen sind der Horror vieler Kunden. Trotzdem sind sie in kaum einer Firma mit einem telefonischen Kunden-Service mehr wegzudenken, daher soll hier beschrieben werden, wie man eine Warteschleife anlegt und welche Einstellungen möglich sind.[116]
Hier sind für uns insbesondere 4 Dateien wichtig:
queues.conf
- Definiert Warteschlangen.
agents.conf
- Definiert „Agenten“, also die Mitarbeiter, die die Anrufe entgegennehmen.
musiconhold.conf
- Definiert die Wartemusik.
extensions.conf
- Im Dialplan werden Anrufe mit der
Queue()
in eine Schlange eingereiht und Agenten mitAgentLogin()
oderAgentCallbackLogin()
am System registriert.
Eine häufige Ursache für Missverständnisse ist die Verwechslung von „Queue Members“ mit Anrufern: Mit den Mitgliedern einer Warteschlange sind immer nur die Agenten, nicht die Anrufer gemeint.[117]
Agenten können mehreren Schlangen angehören, und wir wollen, dass sich jeder Agent von einer beliebigen Extension aus einloggen kann („Hot-desking“). Das grundsätzliche Vorgehen zur Definition von Agenten und Warteschlangen sieht vereinfacht so aus:
agents.conf
[agents] ; AgentenNr,Passwort,Name agent => 1001,1234,Mark Spencer agent => 1002,1234,Will Meadows
queues.conf
[support-schlange] member => Agent/1001 ; Agent 1001 zur support-schlange hinzufügen member => Agent/1002 ; ... 1002 ...
extensions.conf
exten => 20,1,Queue(support-schlange) ; => Warteschlange exten => 25,1,AgentLogin() ; bei Anruf Login
Und so funktioniert's: Die Agenten loggen sich über Extension
25
ein, hören fröhliche Musik und warten auf Anrufer. Anrufe
auf Extension 20
werden in die Schlange aufgenommen und der
Reihe nach (FIFO) abgearbeitet: Der Agent hört einen Piepton, und der erste
Anrufer wird verbunden.
Wir legen uns in der extensions.conf
folgende
Extension an, mit der wir gleich die ordnungsgemäße Funktion der
Wartemusik überprüfen können:
exten => 222,1,Answer() ; abheben exten => 222,n,Set(MUSICCLASS()=default) ; Musikklasse "default" setzen exten => 222,n,WaitMusicOnHold(20) ; 20 Sekunden Musik exten => 222,n,Hangup() ; auflegen
Beginnen wir mit dem Einfachsten, der Festlegung der Wartemusik (Music on Hold).
Die Einstellmöglichkeiten werden in der Datei
musiconhold.conf
beschrieben, ein paar Infos zur
MP3-Unterstützung durch das Programm mpg123 stehen in
doc/README.mp3
(1.2) /
doc/mp3.txt
(1.4). Die optimale Abtastrate für die
MP3s ist 8000 Hz, mono.
Die einfachste (Default-)Konfiguration mit nur einer Musikklasse
(default
):
[default] mode=quietmp3 directory=/var/lib/asterisk/mohmp3
Jetzt stoppen und starten
wir Asterisk, z.B. mit asterisk -rx "stop now" und
asterisk, um die neue Extension und die Streams zu
aktivieren (ein Reload reicht nicht aus). Wenn Sie jetzt die Extension
222
(wie oben definiert) anrufen, sollten Sie Wartemusik
hören (im o.g. Verzeichnis werden bereits 3 Dateien mitgeliefert).
Besser ist aber folgende Konfiguration, für die wir ein Verzeichnis
moh-native
in /var/lib/asterisk/
anlegen:
[default] mode=files ; Dateien direkt in einem Asterisk-kompatiblen Format lesen directory=/var/lib/asterisk/moh-native random=yes ; Dateien in zufälliger Reihenfolge spielen
Es ist dazu notwendig, die MP3-Dateien in ein Asterisk-kompatibles Format zu konvertieren, was z.B. mit den Programmen sox[118] und lame[119] so geht:
$
lame --decode musik.mp3 musik.wav$
sox -V musik.wav -r 8000 -c 1 -w musik.raw$
sox -V musik.wav -r 8000 -c 1 -w musik.gsm
Damit
haben wir eine fiktive Datei musik.mp3
ins WAV- und
dann in die Formate RAW und GSM konvertiert (mit einer Abtastrate von 8
kHz). Wir können in unserem Verzeichnis auch Formate wie aLaw und uLaw
(Dateiendungen für sox: .al
und
.ul
) ablegen - Asterisk wird automatisch das am
wenigsten CPU-intensive wählen. Wichtig ist, dass die Abtastrate immer
8000 Hz beträgt.
Wichtig | |
---|---|
Wenn Sie in der |
In unserem Test haben wir die im Verzeichnis
moh/
mitgelieferten WAV-Dateien in unser Verzeichnis
moh-native/
kopiert, mit sox nach
RAW und GSM umkodiert und dann die WAV-Dateien, die Probleme bereiteten,
aus dem Verzeichnis gelöscht:
$
cd /var/lib/asterisk/moh-native/$
for i in *.wav; do \ sox $i -r 8000 -c 1 $(basename $i .wav).raw; \ sox $i -r 8000 -c 1 $(basename $i .wav).gsm; \ done$
rm *.wav
Für CPU-kritische Anwendungen (große Installationen) sollten Sie
einen Blick auf die Beschreibung in
contrib/utils/README.rawplayer
im ursprünglichen
Asterisk-Verzeichnis werfen.
Weitere Musikklassen lassen sich definieren, indem man außer dem
[default]
-Abschnitt noch weitere Abschnitte, z.B.
[rock]
anlegt, dort ein anderes Verzeichnis, z.B. ein
Unterverzeichnis, angibt und die Musikdateien in dieses Verzeichnis legt.
Reload nicht vergessen!
In der queues.conf
werden Warteschlangen
definiert und entsprechende Einstellungen vorgenommen. Die Datei ist - wie
Sie das schon kennen - in Abschnitte unterteilt.
Unter [general]
stellen wir nur
persistentmembers = yes
ein, damit beim Neustart von Asterisk
die Agenten automatisch wieder in ihre Schlangen aufgenommen
werden.
Jede Warteschleife stellt einen eigenen Abschnitt dar. Wir legen
bespielsweise eine Schlange im Abschnitt [support]
an.
Folgende Parameter stehen zur Verfügung:
Legt die in musiconhold.conf
definierte
Musikklasse der Warteschleife fest. Wir wählen die oben angelegte Klasse
default
:
musiconhold = default
Legt eine Audiodatei fest, die einem Agenten vor dem Beantworten eines Anrufs vorgespielt wird. Dies dient dazu, dass ein Agent, der auf mehreren Schlangen Anrufe entgegennimmt, weiß, um welche Schlange es sich handelt und z.B. den Anrufer entsprechend begrüßen kann.
;announce = schlange-support
Wenn
Sie diese Einstellung verwenden, denken Sie daran, auch eine
entsprechende Audiodatei im sounds/
-Verzeichnis
anzulegen, also z.B. schlange-support.gsm
.
Legt fest, in welcher Weise und Reihenfolge die Agenten bei einem Anruf angeklingelt werden sollen:
ringall
- Alle anklingeln, bis einer antwortet. (Default)
roundrobin
- Der Reihe nach alle anklingeln, bis einer antwortet.
leastrecent
- Das Interface anklingeln, bei dem der letzte Anruf am längsten zurückliegt.
fewestcalls
- Den anklingeln, der am wenigsten Anrufe in dieser Schlange abgearbeitet hat.
random
- Ein zufällig gewähltes Interface anklingeln.
rrmemory
- Round-Robin mit Gedächtnis. Beginnt die Reihe bei dem, der nach dem letzten Anruf an der Reihe ist.
Es ist zu beachten, dass Agenten, für die ein niedrigerer Malus (penalty) festgelegt wurde, immer Agenten mit höherem Malus vorgezogen werden.
strategy = ringall
Die
Einstellung ist abhängig von Ihren Gegebenheiten: ringall
ist vielleicht lästig, die anderen Werte verursachen zusätzliche
Wartezeit für den Anrufer, falls Agenten nicht ans Telefon gehen.
Legt die Zeit (in Sekunden) fest, in der Anrufe beantwortet sein sollen. Nur für statistische Auswertungen interessant („Wie viele Anrufe wurden innerhalb der Service-Zeit von x Sekunden beantwortet?“).
servicelevel = 60
Hier kann ein Context angegeben werden, in dem, wenn der Anrufer eine Extension mit nur einer Ziffer drückt, aus der Schlange rausgenommen und zu dieser Extension in diesem Context weitergeleitet wird.
context = supportschlange-Context ; so könnten wir es einstellen ; aber wir lassen das erst mal weg, also auskommentiert: ;context = supportschlange-Context
Legt fest, wie lange (in Sekunden) ein Telefon klingeln soll, bis wir es als nicht besetzt (also Timeout) betrachten.
timeout = 15
Bestimmt, wie lange (in Sekunden) gewartet werden soll, bevor erneut alle Agenten angeklingelt werden.
retry = 5
Das Gewicht (Wichtigkeit) der Schlange, relativ zu anderen Schlangen. Wenn ein Agent auf mehreren Schlangen ist, werden ihm zuerst Anrufe von Schlangen mit höherem Gewicht durchgestellt. So könnte z.B. einer Notfallschlange ein höheres Gewicht gegeben werden.
weight = 0
Die Wartezeit (in Sekunden), bevor ein Agent, der gerade einen Anruf beendet hat, erneut einen Anruf erhält (Default: 0).
; wir lassen unseren Agenten eine kleine Verschnaufpause, um ; einen Schluck Wasser zu trinken: wrapuptime = 10
Bestimmt, in welchen Abständen (in Sekunden) den Anrufern ihre Position in der Schlange und/oder die geschätzte Wartezeit angesagt werden soll (0 für aus).
announce-frequency = 90
Ob die geschätzte Wartezeit in den Ankündigungen nach der Position
genannt werden soll. Mögliche Werte sind yes
(ja),
no
(nein) oder once
(nur
einmal).
announce-holdtime = yes
Rundungsschritte der Sekunden. Mit der Einstellung 0 werden nur die Minuten, nicht die Sekunden angesagt. Andere mögliche Werte sind: 0, 1, 5, 10, 15, 20 und 30. (Mit 30 würde beispielsweise eine geschätzte Wartezeit von 2:34 auf 2:30 gerundet.)
announce-round-seconds = 0
Die folgenden Parameter stellen ein, welche Sprachbausteine für die Ansagen der Position und Wartezeit verwendet werden. I.d.R sind hier keine Veränderungen notwendig:
queue-youarenext = queue-youarenext ; "You are now first in line." queue-thereare = queue-thereare ; "There are" ... queue-callswaiting = queue-callswaiting ; ... "calls waiting." queue-holdtime = queue-holdtime ; "The current est. holdtime is" ... queue-minutes = queue-minutes ; ... "minutes" queue-seconds = queue-seconds ; ... "seconds" queue-thankyou = queue-thankyou ; "Thank you for your patience." queue-lessthan = queue-less-than ; ... "less than" ... queue-reporthold = queue-reporthold ; "Hold time" ... periodic-announce = queue-periodic-announce ; "All reps busy, wait for next"
Wenn diese Parameter nicht angegeben werden (also auskommentiert sind), gelten diese Default-Werte.
Bestimmt, in welchen Abständen (in Sekunden) den Anrufern die
periodische Ankündigung (periodic-announce
, s.o.,
„Zur Zeit sind alle Mitarbeiter im Gespräch, bitte warten
Sie.“) angesagt werden soll.
periodic-announce-frequency = 60
Die Angabe dieses Parameters schaltet die Aufzeichnung von
Gesprächen ein (wie mit der Monitor()
-Applikation) und
bestimmt das Aufzeichnungsformat. (Bei auskommentiertem
monitor-format
werden keine Mitschnitte gemacht.) Geben Sie
hier also gsm
, wav
(große Dateien!) oder
wav49
an.
; wenn Sie Aufzeichnungen wollen, diese Zeile einkommentieren: ;monitor-format = gsm
Per Default werden die Dateien (eine -in
und eine -out
) nach ${UNIQUEID}
benannt. Sie können das bei Bedarf verändern, indem Sie im Dialplan vor
dem Queue()
-Aufruf
Set(MONITOR_FILENAME=
angeben. Wir nehmen aber im Beispiel keine Veränderung vor.dateiname
)
Weitere Informationen über Mitschnitte siehe „Monitor()
“
Kombiniert die beiden durch einen Gesprächs-Mitschnitt erzeugten
Dateien
und
...
-in
zu einer Datei.
Werte: ...
-outyes
oder no
.
monitor-join = yes
Weitere
Informationen über Mitschnitte siehe „Monitor()
“
Legt fest, ob Anrufer in eine Warteschleife ohne Agenten eingereiht werden.
yes
- Anrufer können in eine Schleife ohne Agenten oder von nur nicht-verfügbaren Agenten eingereiht werden.
no
- Anrufer können nicht in eine Schleife ohne Agenten eingereiht werden.
strict
Anrufer können nicht in eine Schleife ohne Agenten eingereiht werden (aber in eine Schlange mit nur nicht-verfügbaren Agenten).
Nicht-verfügbar ist nicht zu verwechseln mit im Gespräch (busy). Ein Agent ist nicht verfügbar, wenn er zwar der Schlange zugewiesen, aber tatsächlich nicht am System registriert ist (siehe auch „
member
“). Achtung: Statisch definierte Mitglieder (siehe „member
“) gelten immer als verfügbar!
Sollte ein Anrufer nicht in eine Schlange aufgenommen
werden, ist die Queue()
-Applikation beendet, und der
Dialplan wird fortgesetzt.
joinempty = no ; wir wollen unsere Anrufer nicht unnötig warten lassen
Legt fest, ob Anrufer aus einer Schlange entfernt werden, sobald
sich alle Agenten ausgeloggt haben. Mögliche Werte wie bei
joinempty
. Nach dem Verlassen der Schlange wird der
Dialplan fortgesetzt.
leavewhenempty = strict ; Anrufer nicht unnötig warten lassen
Stellt ein (yes
|no
), ob u.a. die
folgenden Events für das Manager-Interface erzeugt werden: AgentCalled,
AgentDump, AgentConnect, AgentComplete.
eventwhencalled = yes
Stellt ein (yes
|no
), ob
QueueMemberStatus-Events im Manager-Interface erzeugt werden (das können
viele sein!).
eventmemberstatus = no
Legt fest (yes
|no
), ob dem Agenten die
Wartezeit des Anrufers angesagt werden soll, bevor dieser zu ihm
durchgestellt wird. (Geschmacksfrage)
reportholdtime = no
Stellt ein, wie lange (in Sekunden) der Anrufer Stille hört, bevor er mit einem Agenten verbunden wird.
memberdelay = 1
Bestimmt, ob der Antwort-Timeout eines Agenten bei einem Besetzt- oder Leitung-überlastet-Signal zurückgesetzt wird. Kann nützlich für Agenten sein, die die Berechtigung haben, einen Anruf abzuweisen.
timeoutrestart = yes
Dieser Parameter legt fest, ob ein Agent, der einen Anruf nicht beantwortet, automatisch pausiert werden soll.
autopause = no
Legt fest, ob auch solche Agenten angeklingelt werden sollen, von denen bekannt ist, dass sie gerade im Gespräch sind. Der bisher einzige Channel driver, der diesen Status übermittelt, ist SIP.
ringinuse = no
Es ist möglich, direkt in der queues.conf
Agenten statisch in der
Form
member =>Technologie
/Resource
[,Malus
]
-
also z.B. member => Zap/2
- anzulegen (darf mehrmals
verwendet werden, siehe queues.conf
). Das kann
jedoch zu Problemen mit joinempty
und
leavewhenempty
führen, da diese Agenten
immer als verfügbar angesehen werden, auch wenn sie
in Wirklichkeit nicht an ihrem Apparat sind. Zudem hat es den Nachteil,
dass ein Agent immer fest einem Apparat zugeordnet ist und sich nicht
von einem anderen Apparat aus anmelden kann.
Wir verwenden daher lieber die dynamische Form und ordnen unserer Schlange
support
in der Form
member => Agent/AgentenNr
zwei
Agenten 1001
und 1002
zu:
member => Agent/1001 member => Agent/1002
Diese Agenten müssen wir noch in der
agents.conf
definieren (s.u.)[120]. Die AgentenNr
ist eine frei wählbare Nummer,
die jeden Agenten eindeutig identifiziert. Sie hat nichts mit den
Extensions zu tun, die die Agenten evtl. verwenden.
In der agents.conf
werden die Agenten, also
Call-Center-Mitarbeiter, die auch „Members“ genannt werden,
definiert und entsprechende Einstellungen vorgenommen. Auch diese Datei
ist wieder in Abschnitte unterteilt.
Unter [general]
stellen wir persistentagents =
yes
ein, damit die Logins der Agenten persistent (dauerhaft) sind
und in der Asterisk-Datenbank gespeichert werden. Die Agenten werden
dadurch beim Neustart von Asterisk automatisch wieder in ihre Schlangen
aufgenommen.
Im Abschnitt [agents]
nehmen wir weitere
Einstellungen vor und definieren dann die Agenten. Folgende Parameter
stehen zur Verfügung:
Hiermit können wir einstellen, wie lange (in Sekunden) ein Telefon klingeln muss, bis der Agent automatisch ausgeloggt wird.
Beachten Sie, dass Agenten nicht ausgeloggt werden, wenn diese
Dauer über dem timeout („timeout
“) der
Schlange liegt! Da haben wir 15 Sekunden eingestellt, also wählen wir
hier 14.
autologoff = 14
Stellt ein (yes
|no
), ob Agenten, die mit
AgentCallbackLogin()
eingeloggt wurden, die Raute
(#
) drücken müssen, um ein Gespräch anzunehmen. Es ist zu
beachten, dass in bisherigen Asterisk-Versionen der Voiceprompt dem
Agenten nicht mitgeteilt hat, dass er #
drücken
muss.
ackcall = no
Stellte ein (yes
|no
), ob Agenten Anrufe
durch Drücken der Stern-Taste (*
) beenden
können.
endcall = yes
Legt (wie wrapuptime
in der queues.conf, die doppelte
Angabe ist nicht klar) die Wartezeit fest, bis ein Agent, der gerade
einen Anruf beendet hat, erneut einen Anruf erhält - hier allerdings in
Millisekunden. Default: 5000.
wrapuptime = 5000 ; 5 Sekunden Pause
Den CDR-Record anpassen (yes
|no
), so
dass die Kanalangabe
enthält, damit wir wissen, welcher Agent das Gespräch geführt
hat.Agent
/AgentenNr
updatecdr = yes
Aufzeichnungsformat für Mitschnitte. gsm
,
wav
(große Dateien!) oder wav49
. Default:
wav
.
recordformat = gsm
Legt fest (yes
|no
), ob im User-field
(dem Freitextfeld) des CDR der Dateiname der Aufzeichnung gespeichert
werden soll, damit man sie später zuordnen kann.
createlink = yes
Wenn Sie createlink
verwenden, kann mit
urlprefix
direkt eine URL vor den Dateinamen gesetzt
werden, unter der Sie die Aufzeichnungen mit einem Webserver im Intranet
verfügbar gemacht haben.
; so könnte ein Beispiel aussehen: ;urlprefix = http://astbox/anrufe/
Hier können Sie angeben, in welchem Verzeichnis die Mitschnitte
gespeichert werden sollen. Default:
/var/spool/asterisk/monitor
; wenn wir z.B. die Mitschnitte in /var/calls/ speichern wollen: ;savecallsin = /var/calls
Im Dialplan (Kapitel 4, Programmieren im Dialplan) können sich
zum einen die Agenten über eine bestimmte Extension in die Warteschleife
einloggen, zum anderen werden Anrufe mit der Applikation
Queue()
(„Queue()
“) in eine
Schlange eingereiht.
Eine minimale Extension, die die Anrufer in die Warteschleife einreiht, sähe so aus:
exten => 20,1,Answer() ; abheben exten => 20,n,Set(MUSICCLASS()=default) ; Musikklasse "default" setzen exten => 20,n,Queue(support,t) ; in Schlange "support" einreihen exten => 20,n,Hangup() ; hinterher auflegen
Wir lieben es etwas vollständiger und verwenden diese Extension:
exten => 20,n,Wait(2) exten => 20,n,Answer() ; abheben exten => 20,n,Set(MUSICCLASS()=default) ; Musikklasse "default" setzen exten => 20,n,Queue(support,t) ; in Schlange "support" einreihen ; zur Erinnerung: die Option t erlaubt es dem Agenten, den Anruf ; an eine andere Extension weiterzuleiten ; setzt QUEUESTATUS = ; TIMEOUT | FULL | JOINEMPTY | JOINUNAVAIL | LEAVEEMPTY | LEAVEUNAVAIL exten => 20,n,Goto(q-${QUEUESTATUS},1) ; je nach QUEUESTATUS springen ; keine Agenten auf der Schlange: ; (hier könnte man alternativ auf VoiceMail() leiten) exten => q-JOINEMPTY,1,Wait(1) exten => q-JOINEMPTY,n,Playback(vm-nobodyavail,noanswer) exten => q-JOINEMPTY,n,Playback(vm-goodbye,noanswer) exten => q-JOINEMPTY,n,Hangup() ; keine Agenten (oder nur nicht-verfügbare) auf der Schlange: exten => q-JOINUNAVAIL,1,Goto(q-JOINEMPTY,1) ; wie JOINEMPTY behandeln ; alle Agenten haben Schlange verlassen: exten => q-LEAVEEMPTY,1,Goto(q-JOINEMPTY,1) ; wie JOINEMPTY behandeln ; alle Agenten (auch nicht-verfügbare) haben Schlange verlassen: exten => q-LEAVEUNAVAIL,1,Goto(q-JOINEMPTY,1) ; wie JOINEMPTY behandeln ; kein Agent antwortet: exten => q-TIMEOUT,1,Goto(q-JOINEMPTY,1) ; wie JOINEMPTY behandeln ; max. Anruferzahl für Schlange erreicht: ; (hier könnte man alternativ auf VoiceMail() leiten) exten => q-FULL,1,Busy(5) exten => q-FULL,n,Hangup()
Wenn wir diese Extension
anrufen, werden wir, da keine Agenten angemeldet sind, die Ansage hören,
dass z.Zt. niemand unseren Anruf entgegennehmen kann. (Wenn Sie das
verschleiern wollen, setzen Sie in der queues.conf
die Parameter joinempty=yes
und
leaveempty=no
.)
Es fehlt also noch eine Extension, unter der sich die Agenten einloggen, d.h. anwesend melden:
exten => 25,1,Answer() ; abheben exten => 25,n,AgentLogin() ; Agent einloggen exten => 25,n,Hangup() ; hinterher auflegen
Mit
AgentLogin()
bleibt die Verbindung zum Agenten dauerhaft
bestehen, und die eingehenden Anrufe werden auf diesen bereits aufgebauten
Sprachkanal aufgeschaltet. Wenn der Agent den Hörer auflegt, wird er
abgemeldet. Das bedeutet auch, dass ein Agent nicht gleichzeitig
eingeloggt sein kann und ausgehende Gespräche machen kann.
AgentLogin()
ist daher in der Praxis wirklich nur dann
geeignet, wenn es sich um ein reines Inbound-Call-Center handelt.
AgentCallbackLogin()
hingegen hat den Vorteil, dass
sich Agenten einmal anmelden können und bei eingehenden Gesprächen
zurückgerufen werden. Sie bleiben also auch beim Auflegen angemeldet und
können ausgehende Gespräche führen. Diese Applikation ist aber seit
Version 1.4 „deprecated“, wird also zukünftig nicht mehr
vorhanden sein.
Digium verwendet im Beispiel
doc/queues-with-callback-members.txt
(in AEL, lässt
sich aber leicht in einen „herkömmlichen“ Dialplan
umwandeln)
Read(agentennr,agent-user); VMAuthenticate(${agentennr},s);
zum Authentifizieren der
Agenten, AddQueueMember()
zum dynamischen Hinzufügen zur
Schlange und Dial()
zum Anrufen der Agenten.
Sollte AgentCallbackLogin() tatsächlich ersatzlos wegfallen, geht damit tatsächlich Funktionalität und das leichte Setup verloren. (An dieser Stelle nochmal vielen Dank an Markus Bönke!)
Aufgabe. Es bleibt dem Leser als Aufgabe überlassen, vor die Einreihung in eine Warteschlange noch ein Menü zu schalten, z.B. „Um eine Bestellung aufzugeben, drücken Sie die 1. Für Reklamationen drücken Sie die 2.“, und dann zwei Warteschlangen einzurichten, denen die Agenten der entsprechenden Abteilung angehören.
Ereignisse, die auf den Warteschlangen auftreten, werden im
Queue-Log, normalerweise /var/log/asterisk/queue_log
detailliert festgehalten (natürlich werden auch Einträge im CDR-Log
gemacht). Im queue_log
steht ein Eintrag pro Zeile im
Format:
Timestamp
|Anruf-ID
|Schlange
|Kanal
|Event
|Param1
[|Param2
[|Param3
]]
Timestamp
- Ist die Unix-Zeit, zu der der Event aufgetreten ist.
Anruf-ID
- Ist die einmalige ID des Anrufs (alphanumerisch).
Schlange
- Ist der Name der Warteschlange, z.B.
support
. Kann auchNULL
sein. Kanal
- Ist der Name des überbrückten Kanals, z.B.
Agent/1001
. Kann auchNULL
sein. Event
- Ist der Name des aufgetretenen Ereignisses (s.u.). Abhängig
vom Event sind
Param1
,Param2
undParam3
angegeben.
Die möglichen Ereignisse sind u.a. (siehe auch
doc/queuelog.txt
):
ABANDON
- Anrufer hat seine Position in der Schlange durch Auflegen aufgegeben. Parameter: Position, Einstiegsposition, Wartezeit.
AGENTDUMP
- Agent hat den Anrufer während der Ankündigung der Schlange abgewiesen.
AGENTLOGIN
- Agent hat sich eingeloggt. Parameter: Kanal (z.B.
SIP/127.0.0.1-0181ac00
). AGENTCALLBACKLOGIN
- Callback-Agent hat sich eingeloggt. Parameter: Login-Extension[@Context].
AGENTLOGOFF
- Agent hat sich ausgeloggt. Parameter: Kanal, Login-Dauer.
AGENTCALLBACKLOGOFF
- Agent hat sich (/wurde) ausgeloggt. Parameter: Login-Extension[@Context], Login-Dauer, Grund (z.B. Autologoff).
COMPLETEAGENT
- Gespräch zwischen Anrufer und Agent wurde vom Agenten beendet. Parameter: Wartezeit, Anruf-Dauer, Einstiegsposition.
COMPLETECALLER
- Gespräch zwischen Anrufer und Agent wurde vom Anrufer beendet. Parameter: Wartezeit, Anruf-Dauer, Einstiegsposition.
CONFIGRELOAD
- Konfiguration wurde neu eingelesen (z.B. durch asterisk -rx "reload").
CONNECT
- Anrufer wurde zu einem Agenten durchgestellt. Parameter: Wartezeit.
ENTERQUEUE
- Anrufer wurde in die Schlange aufgenommen. Parameter URL (falls verfügbar), Caller-ID.
EXITEMPTY
- Anrufer wurd aus der Schlange geworfen, weil keine Agenten verfügbar waren[121]. Parameter: Position zum Zeitpunkt des Verlassens der Schlange, ursprüngliche Position beim Eintritt, Wartezeit.
EXITWITHKEY
- Anrufer hat die Schlange durch Drücken einer Taste verlassen. Parameter: Taste, Position.
EXITWITHTIMEOUT
- Anrufer war zu lange in der Schlange, und der Timeout ist abgelaufen. Parameter: Position.
QUEUESTART
- Das Warteschlangensystem wurde gestartet. Dabei haben die
Felder
Anruf-ID
,Schlange
undKanal
den WertNULL
. RINGNOANSWER
- Ein verfügbarer Agent wurde angeklingelt, hat aber nicht abgenommen (Timeout). Parameter: Klingeldauer (in Millisekunden).
SYSCOMPAT
- Agent hat Anruf angenommen, aber die Kanäle waren nicht kompatibel, und der Anruf wurde beendet.
TRANSFER
- Anrufer wurde auf eine andere Extension umgeleitet. Parameter: Extension, Context.
Kommerzielle Log-Analyse- und Echtzeitüberwachungssysteme
sind QueueMetrics[122] oder Easy PABX[123]. Siehe auch „QueueLog()
“.
Asterisk kann derzeit das Queue-Log noch nicht direkt in eine
SQL-Tabelle schreiben. Wie man das trotzdem erreichen kann, wird auf
http://www.voip-info.org/wiki/view/Asterisk+queue_log+on+MySQL
beschrieben. Eine Möglichkeit ist, die Datei
queue_log
durch eine Named-Pipe zu ersetzen und dann
z.B. mit einem Perl-Skript die Einträge in eine Datenbank zu schreiben.
Hier ein Perl-Skript von William Lloyd[124]:
#!/usr/bin/perl -w # # wlloyd at slap.net # The asterisk version indpendant way to get queue stats into Mysql, Postgres # or whatever is supported by Perl DBI # It's all about named pipes # to setup this software # stop asterisk # rm /var/log/asterisk/queue_log # mkfifo /var/log/asterisk/queue_log # make sure permissions are setup # chmod 777 /var/log/asterisk/queue_log # run this program as root or under another user as you see fit. # should start BEFORE asterisk. Add to /etc/rc.d/rc.local or whatever # restart asterisk # requires a DB table like the following.. # CREATE TABLE csr_queue ( # qname varchar(30) default NULL, # agent varchar(30) default NULL, # action text, # info1 text, # info2 text, # info3 text, # timestamp int(11) NOT NULL default '0', # id tinytext NOT NULL #) TYPE=MyISAM; use DBI; use IO::File; my $opt_debug = 0; # if you want postgres change this to "Pg" my $db_type = "mysql"; my $db_host = "127.0.0.1"; my $db_user_name = 'username'; my $db_password = 'password'; my $db_database = 'asteriskstat'; my $dbh = DBI->connect("DBI:$db_type:dbname=$db_database;host= $db_host;", $db_user_name, $db_password); open(FIFO, "< /var/log/asterisk/queue_log") or die "Can't open queue_log : $!\n"; while (1) { $message = <FIFO>; next unless defined $message; # interrupted or nothing logged chomp $message; # remove chars that will cause DB problems $message =~ s/\"\'//g; @data = split(/\|/,$message); # these messages are almost useless for my purposes next if ($data[4] eq "QUEUESTART" ); next if ($data[4] eq "CONFIGRELOAD" ); if (!defined($data[5])) { $data[5] = ''; } if (!defined($data[6])) { $data[6] = ''; } if (!defined($data[7])) { $data[7] = ''; } my $sql = "INSERT INTO csr_queue (timestamp, id, qname, agent, action, info1, info2, info3) VALUES ('$data[0]', '$data[1]', '$data [2]', '$data[3]', '$data[4]', '$data[5]', '$data[6]', '$data[7]')"; print "$sql \n\n" if ($opt_debug); $dbh->do($sql); # if you want an actual logfile you might want to uncomment this # if ( open(LOG, ">> /var/log/asterisk/queue_log_real") ) { # print LOG "$message\n"; # close(LOG); # } else { # warn "Couldn't log to /var/log/asterisk_queue_log: $!\n"; # } # } $dbh->disconnect(); exit 0;
Bei QueueMetrics (kostenlose Demo-Version) wird
ebenfalls ein Perl-Skript queueLoader.pl
mitgeliefert.
[116] Ein Beispiel-Setup in AEL von Digium wird ab Asterisk 1.4 in
doc/queues-with-callback-members.txt
beschrieben.
[117] Hier wird der Einfachheit halber der Begriff „Agenten“ verwendet, Markus Bönke macht aber folgende Anmerkung:
Sie übersetzen Queue Member mit "Agenten", wenn man aus der Call-Center-Welt kommt, ist das ein bisschen verwirrend, da Queue Members durchaus normale SIP-Extensions sein können.
[118] sox (http://sox.sourceforge.net/) gibt es als Debian-Paket, also:
$
apt-get install sox
Für MacOS X gibt es - mit installiertem Darwinports (http://darwinports.opendarwin.org/ oder http://darwinports.com/, siehe auch http://apfelwiki.de/wiki/Main/MacPorts) - auch ein Paket:
$
port install sox
[118] Auf anderen Plattformen müssen Sie die Sourcen herunterladen und kompilieren, sofern Sie keine Binaries finden.
[119] lame (http://lame.sourceforge.net/) gibt es nicht als Debian-Paket, wir müssen also die Sourcen herunterladen und mit den bekannten Befehlen ./configure, make und make install kompilieren und installieren.
[119] Für MacOS X gibt es ein Paket über Darwinports (siehe Beschreibung sox):
$
port install lame
oder über Fink (http://fink.sourceforge.net/):$
fink install lame
Natürlich
geht das auch über den FinkCommander mit grafischem Interface.[120] sonst wären es wirklich Geheimagenten ;-)
[121] siehe „leavewhenempty
“
[124] wlloyd at slap.net, veröffentlicht auf der
Digium-Mailingliste asterisk-users
, siehe: http://lists.digium.com/pipermail/asterisk-users/2005-July/109892.html
Version 1.2, November 2002
Neue Version verfügbar
Sie betrachten gerade die alte Version des Buches (Version 1.0). Wir empfehlen Ihnen für Asterisk 1.4 und 1.6 die neue Version des Buches.
Asterisk-Tag 2008
Lernen Sie Mark Spencer (den Erfinder von Asterisk) kennen! Viele Vorträge, Case-Studies und Workshops rund um das Thema VoIP. Asterisk-Tag.org