average(X) -> sum(X) / len(X).
sum([H|T]) -> H + sum(T);
sum([]) -> 0.
len([_|T]) -> 1 + len(T);
len([]) -> 0.
Django requests, logging and Lean Startups
Views: 4,980 Comments: 0Posted January 15, 2012 by derrick
So what does logging and django requests have anything to do with being a Lean Startup. I believe a lot. The model of the Lean Startup is to Build-Measure-Learn and you can only measure if you have the data for it. That is where logging comes into play. In this post I will show you how to integrate logging and django request objects.
I wrote a decorator to make the request available to logging by using a LoggerAdpater and RequestInfo make the request object dict-like.
class RequestInfo(object):
def __init__(self, request):
self.request = request
def __getitem__(self, name):
if name == 'request.host':
return socket.gethostname()
if name.startswith('request.meta.'):
val = name.split('.')[2]
try:
return self.request.META[val.upper()]
except KeyError as e:
return None
return eval('self.%s' % (name))
def _get_attrs(self, obj):
attrs = []
for attr in dir(obj):
try:
if not attr.startswith('_') and \
not callable(getattr(obj, attr)):
attrs.append(attr)
except AttributeError:
pass
return attrs
def __iter__(self):
keys = ['request.host']
keys.extend(['request.%s' % (a) for a in
self._get_attrs(self.request)])
keys.extend(['request.session.%s' % (a) for a in
self._get_attrs(self.request.session)])
keys.extend(['request.user.%s' % (a) for a in
self._get_attrs(self.request.user)])
keys.extend(['request.meta.%s' % (a.lower()) for a in
self.request.META.keys()])
return keys.__iter__()
def logger(name):
def wrap(func):
def caller(*args, **kwargs):
request = None
for arg in args:
if isinstance(arg, HttpRequest):
request = arg
if 'logger' not in kwargs:
if request is not None:
kwargs['logger'] = logging.LoggerAdapter(
logging.getLogger(name), RequestInfo(request))
else:
kwargs['logger'] = logging.getLogger(name)
return func(*args, **kwargs)
return caller
return wrap
@log.logger(__name__)
def home(request, logger=None):
logger.info('user performed some action')
request-json:
(): log.CustomJsonFormatter
format: "'created', 'request.host', 'module', 'funcName', 'lineno', 'levelname', 'request.meta.remote_addr', 'request.meta.http_user_agent', 'request.user.username', 'request.path', 'message'"
{"host": "fastcgi22", "request.meta.http_user_agent": "Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.15 (KHTML, like Gecko) Ubuntu/11.04 Chromium/18.0.996.0 Chrome/18.0.996.0 Safari/535.15", "request.path": "/", "created": 1326706577.275584, "module": "log", "funcName": "caller", "request.user.username": "derrick", "lineno": 114, "request.meta.remote_addr": "76.93.216.138", "message": "user performed some action", "levelname": "INFO"}
In this post I will show you how to configure logging so your application servers can send info in nicely parseable json format to a centralized server for analysis.
So first things first. Lets begin by moving the logging out of settings.py and into it own config. Why because its easier to read and edit in yaml than in python/json and it shows up great in vim/emacs. So let's replace this:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse',
}
},
'handlers': {
'mail_admins': {
'level': 'ERROR',
'filters': ['require_debug_false'],
'class': 'django.utils.log.AdminEmailHandler'
}
},
'loggers': {
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True,
},
}
}
import yaml
SITE_ROOT = os.path.dirname(os.path.realpath(__file__))
LOGGING = yaml.load(open(SITE_ROOT + '/logging.yaml', 'r'))
version: 1
disable_existing_loggers: True
filters:
require_debug_false:
(): django.utils.log.RequireDebugFalse
handlers:
mail_admins:
level: ERROR
filters: [require_debug_false]
class: django.utils.log.AdminEmailHandler
loggers:
django.request:
handlers: [mail_admins]
propagate: True
level: ERROR
class CustomJsonFormatter(jsonlogger.JsonFormatter):
def parse(self):
return eval(self._fmt)
formatters:
(): log.CustomJsonFormatter
json:
format: "'created', 'module', 'funcName', 'lineno', 'levelname', 'message'"
handlers:
syslog:
level: DEBUG
class: logging.handlers.SysLogHandler
facility: local0
formatter: json
address: [loghost, 514]
loggers:
app_name:
handlers: [syslog]
propagate: True
level: DEBUG
$ModLoad imudp
$UDPServerRun 514
$template msg,"{'%msg%\n"
local0.* /var/log/local0;msg
sudo touch /var/log/local0
sudo chown syslog.adm /var/log/local0
sudo restart rsyslog
logger -p local0.info test test
Okay now its time to test. Logging messages from your app server should now be going to the central log host but you would be the luckiest person alive if that all worked without a hitch. If it doesn't be sure to check firewall rules, security groups, stuff like that.
I have been doing a lot of http retrieval lately and the most efficient way to do that is with gzip compression enabled. Fortunately Python makes that really easy. All you have to do is derive from urllib2.HTTPHandler and override http_open().
import httplib, urllib, urllib2
class GzipHandler(urllib2.HTTPHandler):
def http_open(self, req):
req.add_header('Accept-encoding', 'gzip')
r = self.do_open(httplib.HTTPConnection, req)
if 'Content-Encoding'in r.headers and \
r.headers['Content-Encoding'] == 'gzip':
fp = gzip.GzipFile(fileobj=StringIO(r.read()))
else:
fp = r
resp = urllib.addinfourl(fp, r.headers, r.url, r.code)
resp.msg = r.msg
return resp
The Accept-encoding header tells the server that this client supports gzip compression and if the Content-Encoding header is set to gzip the server returned an compressed response. Now you just need to build your opener.
def retrieve(url):
request = urllib2.Request(url)
opener = urllib2.build_opener(GzipHandler)
return opener.open(request)
For more information see:
I wanted to search Twitter and after reading their API docs I knew this was going to be a fun task given their native json support.
That means I would just have to handle pagination and creating the search query. Below is the resulting code.
twitter-search.py
#!/usr/bin/python2.7
import argparse
import datetime
import json
import urllib
import urlparse
class Twitter(object):
search_url = 'http://search.twitter.com/search.json'
def __init__(self, verbose=False):
self.verbose = verbose
super(Twitter, self).__init__()
def search(self, query, until=None, rpp=100, max_results=None):
results = []
params = {
'q': query,
'rpp': rpp,
}
if until:
params['until'] = until.strftime('%Y-%m-%d')
if self.verbose:
print(params)
url = '%s?%s' % (self.search_url, urllib.urlencode(params))
response = json.loads(urllib.urlopen(url).read())
results.extend(response['results'])
if len(results) >= max_results:
return results
while 'next_page' in response:
url = self.search_url + response['next_page']
response = json.loads(urllib.urlopen(url).read())
if self.verbose:
print('%s: %s' % (url, len(response['results'])))
results.extend(response['results'])
if len(results) >= max_results:
break
return results
def search_last_day(self, *args, **kwargs):
kwargs['until'] = datetime.datetime.now() - datetime.timedelta(days=1)
return self.search(*args, **kwargs)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Search twitter')
parser.add_argument('search', nargs=1)
parser.add_argument('--rpp', dest='rpp', type=int, default=100, help='Results per page')
parser.add_argument('-m', '--max-results', dest='max_results', type=int, default=100, help='Max results returned')
parser.add_argument('-p', '--print-results', dest='print_results', action='store_true', help='Print the results')
parser.add_argument('-v', '--verbose', dest='verbose', action='store_true', help='Turn verbose on')
args = parser.parse_args()
twitter = Twitter(verbose=args.verbose)
results = twitter.search_last_day(args.search, rpp=args.rpp, max_results=args.max_results)
print('Found %s items' % (len(results)))
if args.verbose:
json.dumps(results, indent=4)
if args.print_results:
for result in results:
print('%s' % (result['text']))
models.py
from django.contrib.auth.models import User
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.db import models
import random
class YourModelManager(models.Manager):
@staticmethod
def _random_id(prefix='', length=5):
alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
for x in range(length):
prefix += random.choice(alphabet)
return prefix
@classmethod
def _generate_external_id(cls):
external_id = cls._random_id()
while (YourModel.objects.filter(external_id=external_id).count() > 0):
external_id = cls._random_id()
return external_id
def create(self, **kwargs):
kwargs['external_id'] = self._generate_external_id()
return self.get_query_set().create(**kwargs)
def get_or_create(self, **kwargs):
try:
return self.get_query_set().get(**kwargs), False
except self.model.DoesNotExist:
kwargs['external_id'] = self._generate_external_id()
return self.get_query_set().get_or_create(**kwargs)
class YourModel(models.Model):
external_id = models.CharField(max_length=5, unique=True)
objects = YourModelManager()
sample.py
def encode(filename, callback=None):
cmd = 'ffmpeg -i "%s" -acodec libfaac -ab 128kb ' + \
'-vcodec mpeg4 -b 1200kb -mbd 2 -flags +4mv ' + \
'-trellis 2 -cmp 2 -subcmp 2 -s 320x180 "%s.mp4"'
pipe = subprocess.Popen(
shlex.split(cmd % (filename, os.path.splitext(filename)[0])),
stderr=subprocess.PIPE,
close_fds=True
)
fcntl.fcntl(
pipe.stderr.fileno(),
fcntl.F_SETFL,
fcntl.fcntl(pipe.stderr.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK,
)
# frame= 29 fps= 0 q=2.6 size= 114kB time=0.79 bitrate=1181.0kbits/s
reo = re.compile("""\S+\s+(?P<frame>d+) # frame
\s\S+\s+(?P<fps>\d+) # fps
\sq=(?P<q>\S+) # q
\s\S+\s+(?P<size>\S+) # size
\stime=(?P<time>\S+) # time
\sbitrate=(?P<bitrate>[\d\.]+) # bitrate
""", re.X)
while True:
readx = select.select([pipe.stderr.fileno()], [], [])[0]
if readx:
chunk = pipe.stderr.read()
if chunk == '':
break
m = reo.match(chunk)
if m and callback:
callback(m.groupdict())
time.sleep(.1)
average(X) -> sum(X) / len(X).
sum([H|T]) -> H + sum(T);
sum([]) -> 0.
len([_|T]) -> 1 + len(T);
len([]) -> 0.
s3upload.py
#!/usr/bin/python
import os
import sys
import optparse
import progressbar
import time
from boto.s3.connection import S3Connection
from boto.exception import S3ResponseError
from boto.s3.key import Key
AWS_ACCESS_KEY_ID = ''
AWS_SECRET_ACCESS_KEY = ''
pbar = None
def sizeof_fmt(num):
for x in ['bytes','KB','MB','GB','TB']:
if num < 1024.0:
return "%3.1f%s" % (num, x)
num /= 1024.0
def progress_callback(current, total):
try:
pbar.update(current)
except AssertionError, e:
print e
def upload_file(filename, bucket, prefix=None, reduced_redundancy=False):
global pbar
key = Key(bucket)
if prefix:
key.key = '%s/%s' % (prefix, filename)
else:
key.key = '%s' % (filename)
size = os.stat(filename).st_size
if size == 0:
print 'Bad filesize for "%s"' % (filename)
return 0
widgets = [
unicode(filename, errors='ignore').encode('utf-8'), ' ',
progressbar.FileTransferSpeed(),
' <<<', progressbar.Bar(), '>>> ',
progressbar.Percentage(), ' ', progressbar.ETA()
]
pbar = progressbar.ProgressBar(widgets=widgets, maxval=size)
pbar.start()
try:
key.set_contents_from_filename(
filename,
cb=progress_callback,
num_cb=100,
reduced_redundancy=reduced_redundancy,
)
key.set_acl('public-read')
except IOError, e:
print e
return 0
pbar.finish()
return size
if __name__ == '__main__':
parser = optparse.OptionParser(usage='usage: %prog [options] ')
parser.add_option('-p', '--prefix', dest='prefix')
parser.add_option('-r', '--reduced_rendundancy', dest='reduced_redundancy', action='store_true', default=False)
(options, args) = parser.parse_args()
if len(args) < 2:
parser.print_help()
sys.exit(1)
conn = S3Connection(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
try:
bucket = conn.get_bucket(args[0])
except S3ResponseError, e:
if e.error_code == 'NoSuchBucket':
bucket = conn.create_bucket(args[0])
else:
raise e
stime = time.time()
total_bytes = 0
count = 0
for arg in args[1:]:
size = upload_file(arg, bucket, options.prefix, options.reduced_redundancy)
total_bytes += size
count += 1
if len(args) > 2:
print
print '%s files %s at %.2f kb/s' % (count, sizeof_fmt(total_bytes), (total_bytes / 1024)/time.time() - stime))
sudo pip install boto progressbar git clone git://gist.github.com/510222.git s3upload-gist cd s3upload-gist vim s3upload # Add your AWS settings chmod 755 s3upload-gist/s3upload sudo mv s3upload-gist/s3upload /usr/local/bin rm -rf s3upload-gist
Here is a Django authentication backend I wrote using Facebook's amazingly simple Graph API. It logs the user in using their Facebook credentials so you site doesn't have to worry about creating user profiles, validating, etc. See
- http://developers.facebook.com/docs/authentication/
- http://developers.facebook.com/docs/authentication/permissions
- http://developers.facebook.com/docs/api
- http://github.com/facebook/python-sdk/blob/master/examples/oauth/facebookoauth.py
Define the facebook tokens in settings.py and replace
backends.py
from django.conf import settings
from django.contrib.auth import models as auth_models
import cgi
import urllib
import simplejson
from <app_name> import models
class FacebookBackend:
def authenticate(self, token=None):
facebook_session = models.FacebookSession.objects.get(
access_token=token,
)
profile = facebook_session.query('me')
try:
user = auth_models.User.objects.get(username=profile['id'])
except auth_models.User.DoesNotExist, e:
user = auth_models.User(username=profile['id'])
user.set_unusable_password()
user.email = profile['email']
user.first_name = profile['first_name']
user.last_name = profile['last_name']
user.save()
try:
models.FacebookSession.objects.get(uid=profile['id']).delete()
except models.FacebookSession.DoesNotExist, e:
pass
facebook_session.uid = profile['id']
facebook_session.user = user
facebook_session.save()
return user
def get_user(self, user_id):
try:
return auth_models.User.objects.get(pk=user_id)
except auth_models.User.DoesNotExist:
return None
models.py
from django.db import models
from django.contrib.auth.models import User
class FacebookSessionError(Exception):
def __init__(self, error_type, message):
self.message = message
self.type = error_type
def get_message(self):
return self.message
def get_type(self):
return self.type
def __unicode__(self):
return u'%s: "%s"' % (self.type, self.message)
class FacebookSession(models.Model):
access_token = models.CharField(max_length=103, unique=True)
expires = models.IntegerField(null=True)
user = models.ForeignKey(User, null=True)
uid = models.BigIntegerField(unique=True, null=True)
class Meta:
unique_together = (('user', 'uid'), ('access_token', 'expires'))
def query(self, object_id, connection_type=None, metadata=False):
import urllib
import simplejson
url = 'https://graph.facebook.com/%s' % (object_id)
if connection_type:
url += '/%s' % (connection_type)
params = {'access_token': self.access_token}
if metadata:
params['metadata'] = 1
url += '?' + urllib.urlencode(params)
response = simplejson.load(urllib.urlopen(url))
if 'error' in response:
error = response['error']
raise FacebookSessionError(error['type'], error['message'])
return response
views.py
from django.contrib import auth
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template import RequestContext
import cgi
import simplejson
import urllib
from <app_name> import settings
def login(request):
error = None
if request.user.is_authenticated():
return HttpResponseRedirect('/yay/')
if request.GET:
if 'code' in request.GET:
args = {
'client_id': settings.FACEBOOK_APP_ID,
'redirect_uri': settings.FACEBOOK_REDIRECT_URI,
'client_secret': settings.FACEBOOK_API_SECRET,
'code': request.GET['code'],
}
url = 'https://graph.facebook.com/oauth/access_token?' + \
urllib.urlencode(args)
response = cgi.parse_qs(urllib.urlopen(url).read())
access_token = response['access_token'][0]
expires = response['expires'][0]
facebook_session = models.FacebookSession.objects.get_or_create(
access_token=access_token,
)[0]
facebook_session.expires = expires
facebook_session.save()
user = auth.authenticate(token=access_token)
if user:
if user.is_active:
auth.login(request, user)
return HttpResponseRedirect('/yay/')
else:
error = 'AUTH_DISABLED'
else:
error = 'AUTH_FAILED'
elif 'error_reason' in request.GET:
error = 'AUTH_DENIED'
template_context = {'settings': settings, 'error': error}
return render_to_response('login.html', template_context, context_instance=RequestContext(request))
settings.py
FACEBOOK_APP_ID = ''
FACEBOOK_API_KEY = ''
FACEBOOK_API_SECRET = ''
FACEBOOK_REDIRECT_URI = 'http://example.com/login/'
AUTHENTICATION_BACKENDS = (
'<app_name>.backends.FacebookBackend',
)
login.html
{% if error %}
{% if error == 'AUTH_FAILED' %}
<p>Authentication failed</p>
{% else %}{% if error == 'AUTH_DISABLED' %}
<p>Your account is disabled</p>
{% else %}{% if error == 'AUTH_DENIED' %}
<p>You did not allow access</p>
{% endif %}{% endif %}{% endif %}
{% else %}
<a href="https://graph.facebook.com/oauth/authorize?client_id={{ settings.FACEBOOK_APP_ID }}&redirect_uri={{ settings.FACEBOOK_REDIRECT_URI }}&scope=publish_stream,email&display=popup">
<img src="http://developers.facebook.com/images/devsite/login-button.png"/>
</a>
{% endif %}
syslogging.py
#!/usr/bin/python
import syslog
class SysLogging:
def __init__(self, facility, prefix=None):
self.facility = facility
if prefix:
syslog.openlog(prefix)
def _logit(self, priority, message):
syslog.syslog(self.facility | priority, '%s' % (message))
def debug(self, message):
self._logit(syslog.LOG_DEBUG, message)
def info(self, message):
self._logit(syslog.LOG_INFO, message)
def notice(self, message):
self._logit(syslog.LOG_NOTICE, message)
def warning(self, message):
self._logit(syslog.LOG_WARNING, message)
def error(self, message):
self._logit(syslog.LOG_ERR, message)
def crit(self, message):
self._logit(syslog.LOG_CRIT, message)
def alert(self, message):
self._logit(syslog.LOG_ALERT, message)
def emerg(self, message):
self._logit(syslog.LOG_EMERG, message)
def syslogging(func):
def caller(*args, **kwargs):
if 'logger' not in kwargs:
kwargs['logger'] = SysLogging(syslog.LOG_LOCAL2, func.__name__)
return func(*args, **kwargs)
return caller
@syslogging
def test_func(arg1, arg2=None, logger=None):
logger.info('%s %s' % (arg1, arg2))
if __name__ == '__main__':
test_func(1, 'two')
logtime.py
#!/usr/bin/python
import time
import syslog
def logtime(func):
def caller(*args, **kwargs):
stime = time.time()
ret = func(*args, **kwargs)
syslog.syslog(
syslog.LOG_LOCAL2 | syslog.LOG_INFO,
'%s=%s\n' % (func.__name__, time.time() - stime))
return ret
return caller
@logtime
def test_func(arg1, arg2=None):
print arg1, arg2
time.sleep(1)
if __name__ == '__main__':
test_func(1, 2)
Jul 14 15:05:01 olomai python: test_func=1.00114893913
Comparison of IN, GROUP BY and COUNT using Hibernate, Django and SQLAlchemy
Views: 1,244 Comments: 0Posted July 7, 2010 by derrick
SELECT COUNT(*),state FROM download_request WHERE id IN (<id list>) GROUP BY state;Below is the code, output and SQL generated for the three ORMs.
Hibernate
class HibernateDAO implements ApplicationDAO {
public Map getStateCounts(final Collection ids) {
HibernateSession hibernateSession = new HibernateSession();
Session session = hibernateSession.getSession();
Criteria criteria = session.createCriteria(DownloadRequestEntity.class)
.add(Restrictions.in("id", ids));
ProjectionList projectionList = Projections.projectionList();
projectionList.add(Projections.groupProperty("state"));
projectionList.add(Projections.rowCount());
criteria.setProjection(projectionList);
List results = criteria.list();
Map stateMap = new HashMap();
for(Object[] obj: results) {
DownloadState downloadState = (DownloadState)obj[0];
stateMap.put(downloadState.getDescription().toLowerCase(), (Integer)obj[1]);
}
hibernateSession.closeSession();
return stateMap;
}
public static void main(String args[]) {
HibernateDAO downloadRequestDAO = new HibernateDAO();
Collection ids = new ArrayList();
for (int i = 1000; i < 1010; i++ )
ids.add(i);
Map stateCounts = downloadRequestDAO.getStateCounts(ids);
for (String state: stateCounts.keySet()) {
System.out.println(state + ": " + stateCounts.get(state));
}
}
}
Output
failed: 5 downloaded: 1 completed: 4
SQL
select this_.state as y0_, count(*) as y1_ from download_request this_ where this_.id in (1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009) group by this_.state
Django
counts = models.DownloadRequest.objects.filter(
id__in=range(1000, 1010),
).values('state').annotate(Count('state'))
for count in counts:
print count
Output
{'state': u'FAILED', 'state__count': 5}
{'state': u'COMPLETED', 'state__count': 4}
{'state': u'DOWNLOADED', 'state__count': 1}
SQL
SELECT `download_request`.`state`, COUNT(`download_request`.`state`) AS `state__count` FROM `download_request` WHERE `download_request`.`id` IN (1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009) GROUP BY `download_request`.`state` ORDER BY NULL
SQLAlchmey
query = session.query(
func.count(DownloadRequest.state), DownloadRequest.state,
).filter(
DownloadRequest.id.in_(range(1000,1010)),
).group_by(DownloadRequest.state)
for count in query.all():
print count
Output
(4L, 'COMPLETED') (1L, 'DOWNLOADED') (5L, 'FAILED')
SQL
SELECT count(download_request.state) AS count_1, download_request.state AS download_request_state FROM download_request WHERE download_request.id IN (1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009) GROUP BY download_request.stateAs you can see SQLAlchemy is the most similar to SQL, django's is the briefest and Hibernate (obviously) is the most Java-like. Of the three I'd say I like SQLAlchemy the best as it is the most similar to SQL and me being from an SQL background it is the most natural. However all three get the job done and it is always great to have options.
SELECT COUNT(*), state FROM download_request WHERE id IN (<id list>) GROUP BY state;
Criteria criteria = session.createCriteria(DownloadRequestEntity.class)
.add(Restrictions.in("id", ids))
ProjectionList projectionList = Projections.projectionList();
projectionList.add(Projections.groupProperty("state"));
projectionList.add(Projections.rowCount());
criteria.setProjection(projectionList);
public Map getStateCounts(final Collection ids) {
HibernateSession hibernateSession = new HibernateSession();
Session session = hibernateSession.getSession();
Criteria criteria = session.createCriteria(DownloadRequestEntity.class)
.add(Restrictions.in("id", ids));
ProjectionList projectionList = Projections.projectionList();
projectionList.add(Projections.groupProperty("state"));
projectionList.add(Projections.rowCount());
criteria.setProjection(projectionList);
List results = criteria.list();
Map stateMap = new HashMap();
for(Object[] obj: results) {
DownloadState downloadState = (DownloadState)obj[0];
stateMap.put(downloadState.getDescription().toLowerCase(), (Integer)obj[1]);
}
hibernateSession.closeSession();
return stateMap;
}
fastcgi-php
#!/bin/sh
## BEGIN INIT INFO
# Provides: FastCGI servers for PHP
# Required-Start: networking
# Required-Stop: networking
# Default-Start: 2 3 4 5
# Default-Stop: S 0 1 6
# Short-Description: Start FastCGI servers with PHP.
# Description: Start PHP with spawn-fcgi. For use with nginx and lighttpd.
#
#
### END INIT INFO
#
# Author: Derrick Petzold
#
# http://derrickpetzold.com/index.php/2010/07/02/init-script-fastcgi-php-ubuntu/
#
RUN_USER=nobody
RUN_GROUP=nogroup
LISTEN_ADDRESS=127.0.0.1
LISTEN_PORT=53217
SPAWN_FCGI=/opt/lighttpd/bin/spawn-fcgi
PHP_CGI=/opt/php5/bin/php-cgi
PID_FILE=/var/run/fastcgi-php.pid
d_start() {
if [ -f $PID_FILE ]; then
echo -n " already running"
else
start-stop-daemon --start -p $PID_FILE \
--exec /usr/bin/env -- $SPAWN_FCGI -f $PHP_CGI \
-u $RUN_USER -g $RUN_GROUP -a $LISTEN_ADDRESS -p $LISTEN_PORT \
-P $PID_FILE
fi
}
d_stop() {
start-stop-daemon --stop --quiet --pidfile $PID_FILE \
|| echo -n " not running"
if [ -f $PID_FILE ]; then
rm $PID_FILE
fi
}
case "$1" in
start)
echo -n "Starting FastCGI: $0 "
d_start
echo "."
;;
stop)
echo -n "Stopping FastCGI: $0 "
d_stop
echo "."
;;
restart)
echo -n "Restarting FastCGI: $0 "
d_stop
sleep 1
d_start
;;
*)
echo "usage: $0 {start|stop|restart}"
;;
esac
git clone git://gist.github.com/510245.git fastcgi-php.gist vim fastcgi-php.gist/fastcgi-php # Update with your pathnames chmod 755 fastcgi-php.gist/fastcgi-php mv fastcgi-php.gist/fastcgi-php /etc/init.d/ update-rc.d fastcgi-php defaults /etc/init.d/fastcgi-php start rm -rf fastcgi-php.gist
crowdtube.tv
dmusic.bz
ilovephotos.com
kindfish.com
Below is a snippet of my resume. Click here to view the full version in pdf, its proper format.







Be the first to comment.