void stats_initialize(void) { if (_stats_running) return; /* set up global struct */ _stats.global_tree = avl_tree_new(_compare_stats, NULL); _stats.source_tree = avl_tree_new(_compare_source_stats, NULL); _stats.event_listeners = NULL; thread_mutex_create (&_stats.listeners_lock); _stats_running = 1; stats_event_time (NULL, "server_start", STATS_GENERAL); /* global currently active stats */ stats_event_flags (NULL, "clients", "0", STATS_COUNTERS); stats_event_flags (NULL, "connections", "0", STATS_COUNTERS); stats_event_flags (NULL, "sources", "0", STATS_COUNTERS); stats_event_flags (NULL, "stats", "0", STATS_COUNTERS); stats_event_flags (NULL, "banned_IPs", "0", STATS_COUNTERS); stats_event (NULL, "listeners", "0"); /* global accumulating stats */ stats_event_flags (NULL, "client_connections", "0", STATS_COUNTERS); stats_event_flags (NULL, "source_client_connections", "0", STATS_COUNTERS); stats_event_flags (NULL, "source_relay_connections", "0", STATS_COUNTERS); stats_event_flags (NULL, "source_total_connections", "0", STATS_COUNTERS); stats_event_flags (NULL, "stats_connections", "0", STATS_COUNTERS); stats_event_flags (NULL, "listener_connections", "0", STATS_COUNTERS); stats_event_flags (NULL, "outgoing_kbitrate", "0", STATS_COUNTERS|STATS_REGULAR); stats_event_flags (NULL, "stream_kbytes_sent", "0", STATS_COUNTERS|STATS_REGULAR); stats_event_flags (NULL, "stream_kbytes_read", "0", STATS_COUNTERS|STATS_REGULAR); }
static void *_stats_thread(void *arg) { stats_event_t *event; stats_event_t *copy; event_listener_t *listener; stats_event_time (NULL, "server_start"); stats_event_time_iso8601 (NULL, "server_start_iso8601"); /* global currently active stats */ stats_event (NULL, "clients", "0"); stats_event (NULL, "connections", "0"); stats_event (NULL, "sources", "0"); stats_event (NULL, "stats", "0"); stats_event (NULL, "listeners", "0"); /* global accumulating stats */ stats_event (NULL, "client_connections", "0"); stats_event (NULL, "source_client_connections", "0"); stats_event (NULL, "source_relay_connections", "0"); stats_event (NULL, "source_total_connections", "0"); stats_event (NULL, "stats_connections", "0"); stats_event (NULL, "listener_connections", "0"); ICECAST_LOG_INFO("stats thread started"); while (_stats_running) { thread_mutex_lock(&_global_event_mutex); if (_global_event_queue.head != NULL) { /* grab the next event from the queue */ event = _get_event_from_queue (&_global_event_queue); thread_mutex_unlock(&_global_event_mutex); if (event == NULL) continue; event->next = NULL; thread_mutex_lock(&_stats_mutex); /* check if we are dealing with a global or source event */ if (event->source == NULL) process_global_event (event); else process_source_event (event); /* now we have an event that's been processed into the running stats */ /* this event should get copied to event listeners' queues */ listener = (event_listener_t *)_event_listeners; while (listener) { copy = _copy_event(event); thread_mutex_lock (&listener->mutex); _add_event_to_queue (copy, &listener->queue); thread_mutex_unlock (&listener->mutex); listener = listener->next; } /* now we need to destroy the event */ _free_event(event); thread_mutex_unlock(&_stats_mutex); continue; } else { thread_mutex_unlock(&_global_event_mutex); } thread_sleep(300000); } return NULL; }
/* This is called when there has been a change in the metadata. Usually * artist and title are provided separately so here we update the stats * and write log entry if required. */ static void update_comments (source_t *source) { ogg_state_t *ogg_info = source->format->_state; char *title = ogg_info->title; char *artist = ogg_info->artist; char *metadata = NULL; unsigned int len = 1; /* space for the nul byte at least */ ogg_codec_t *codec; char codec_names [100] = ""; if (ogg_info->artist) { if (title) { len += strlen(artist) + strlen(title) + 3; metadata = calloc (1, len); snprintf (metadata, len, "%s - %s", artist, title); } else { len += strlen(artist); metadata = calloc (1, len); snprintf (metadata, len, "%s", artist); } } else { if (title) { len += strlen (title); metadata = calloc (1, len); snprintf (metadata, len, "%s", title); } } json_stats_update(source->mount, ogg_info->artist, ogg_info->title, source->listeners); if (metadata) { logging_playlist (source->mount, metadata, source->listeners); free (metadata); } stats_event (source->mount, "artist", artist); stats_event (source->mount, "title", title); stats_event_time (source->mount, "metadata_updated", STATS_GENERAL); codec = ogg_info->codecs; while (codec) { if (codec->name) { size_t len = strlen (codec_names); size_t remaining = sizeof (codec_names) - len; char *where = codec_names + len; char *separator = "/"; if (len == 0) separator = ""; snprintf (where, remaining, "%s%s", separator, codec->name); } codec = codec->next; } stats_event (source->mount, "subtype", codec_names); yp_touch (source->mount); }
/* Perform any initialisation just before the stream data is processed, the header * info is processed by now and the format details are setup */ static void source_init (source_t *source) { ice_config_t *config = config_get_config(); char *listenurl; const char *str; int listen_url_size; mount_proxy *mountinfo; /* 6 for max size of port */ listen_url_size = strlen("http://") + strlen(config->hostname) + strlen(":") + 6 + strlen(source->mount) + 1; listenurl = malloc (listen_url_size); memset (listenurl, '\000', listen_url_size); snprintf (listenurl, listen_url_size, "http://%s%s", config->hostname, source->mount); config_release_config(); str = httpp_getvar(source->parser, "ice-audio-info"); source->audio_info = util_dict_new(); if (str) { _parse_audio_info (source, str); stats_event (source->mount, "audio_info", str); } stats_event (source->mount, "listenurl", listenurl); free(listenurl); if (source->dumpfilename != NULL) { source->dumpfile = fopen (source->dumpfilename, "ab"); if (source->dumpfile == NULL) { WARN2("Cannot open dump file \"%s\" for appending: %s, disabling.", source->dumpfilename, strerror(errno)); } } /* grab a read lock, to make sure we get a chance to cleanup */ thread_rwlock_rlock (source->shutdown_rwlock); /* start off the statistics */ source->listeners = 0; stats_event_inc (NULL, "source_total_connections"); stats_event (source->mount, "slow_listeners", "0"); stats_event_args (source->mount, "listeners", "%lu", source->listeners); stats_event_args (source->mount, "listener_peak", "%lu", source->peak_listeners); stats_event_time (source->mount, "stream_start"); DEBUG0("Source creation complete"); source->last_read = time (NULL); source->prev_listeners = -1; source->running = 1; mountinfo = config_find_mount (config_get_config(), source->mount); if (mountinfo) { if (mountinfo->on_connect) source_run_script (mountinfo->on_connect, source->mount); auth_stream_start (mountinfo, source->mount); } config_release_config(); /* ** Now, if we have a fallback source and override is on, we want ** to steal its clients, because it means we've come back online ** after a failure and they should be gotten back from the waiting ** loop or jingle track or whatever the fallback is used for */ if (source->fallback_override && source->fallback_mount) { source_t *fallback_source; avl_tree_rlock(global.source_tree); fallback_source = source_find_mount(source->fallback_mount); if (fallback_source) source_move_clients (fallback_source, source); avl_tree_unlock(global.source_tree); } }
static void *_stats_thread(void *arg) { stats_event_t *event; stats_event_t *copy; event_listener_t *listener; if (!kitsune_is_updating()) { /**DSU control */ stats_event (NULL, "server", ICECAST_VERSION_STRING); stats_event_time (NULL, "server_start"); /* global currently active stats */ stats_event (NULL, "clients", "0"); stats_event (NULL, "connections", "0"); stats_event (NULL, "sources", "0"); stats_event (NULL, "stats", "0"); /* global accumulating stats */ stats_event (NULL, "client_connections", "0"); stats_event (NULL, "source_client_connections", "0"); stats_event (NULL, "source_relay_connections", "0"); stats_event (NULL, "source_total_connections", "0"); stats_event (NULL, "stats_connections", "0"); stats_event (NULL, "listener_connections", "0"); INFO0 ("stats thread started"); } while (_stats_running) { kitsune_update("stats"); /**DSU updatepoint */ if (_global_event_queue != NULL) { /* grab the next event from the queue */ thread_mutex_lock(&_global_event_mutex); event = (stats_event_t *)_global_event_queue; _global_event_queue = event->next; thread_mutex_unlock(&_global_event_mutex); event->next = NULL; thread_mutex_lock(&_stats_mutex); /* check if we are dealing with a global or source event */ if (event->source == NULL) process_global_event (event); else process_source_event (event); /* now we have an event that's been processed into the running stats */ /* this event should get copied to event listeners' queues */ listener = (event_listener_t *)_event_listeners; while (listener) { copy = _copy_event(event); thread_mutex_lock(listener->mutex); _add_event_to_queue(copy, listener->queue); thread_mutex_unlock(listener->mutex); listener = listener->next; } /* now we need to destroy the event */ _free_event(event); thread_mutex_unlock(&_stats_mutex); continue; } thread_sleep(300000); } return NULL; }